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.
160 lines
7.2 KiB
C
160 lines
7.2 KiB
C
#ifndef SPACETIME_H
|
|
#define SPACETIME_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
typedef struct {
|
|
double alpha;
|
|
double beta[3];
|
|
double gamma[3][3];
|
|
double K[3][3];
|
|
double d_alpha[3];
|
|
double d_beta[3][3]; /* d_beta[spatial derivative][component] */
|
|
double d_gamma[3][3][3]; /* d_gamma[spatial derivative][j][k] */
|
|
} MetricData;
|
|
|
|
/* Result of evaluating the metric at one event. `OK` is zero so that legacy
|
|
* `if (eval(...))` call sites keep working. These codes describe data
|
|
* availability only; they never express a physical capture. */
|
|
typedef enum {
|
|
SPACETIME_POINT_OK = 0,
|
|
SPACETIME_POINT_TIME_UNAVAILABLE,
|
|
SPACETIME_POINT_OUT_OF_DOMAIN,
|
|
SPACETIME_POINT_INVALID_METRIC,
|
|
SPACETIME_POINT_INTERNAL_ERROR
|
|
} SpacetimePointStatus;
|
|
|
|
/* Optional legacy region query for backends that declare no asymptotic end.
|
|
* It can only report ACTIVE or ESCAPED; it can never report a physical
|
|
* capture, and it is not required by spacetime_source_finalize(). */
|
|
typedef enum {
|
|
SPACETIME_RAY_ACTIVE,
|
|
SPACETIME_RAY_ESCAPED
|
|
} SpacetimeRayStatus;
|
|
|
|
/* Stable identifier for one asymptotic end (infinity) of a backend. Backends
|
|
* may describe more than one; the current analytic backends expose one. */
|
|
typedef uint32_t SpacetimeEndId;
|
|
#define SPACETIME_END_NONE ((SpacetimeEndId)0xffffffffu)
|
|
|
|
typedef enum {
|
|
ASYMPTOTIC_EXTERIOR_MINKOWSKI,
|
|
ASYMPTOTIC_EXTERIOR_SCHWARZSCHILD_MONOPOLE
|
|
} AsymptoticExteriorKind;
|
|
|
|
/* Declared asymptotic end. `frame_origin` and the columns of `frame_axes`
|
|
* express the asymptotic reference frame in backend coordinates; spatial
|
|
* `n_infinity` values use the same coordinate axes as the observer tetrad. */
|
|
typedef struct {
|
|
SpacetimeEndId end_id;
|
|
AsymptoticExteriorKind exterior_kind;
|
|
double mass;
|
|
double frame_origin[3];
|
|
double frame_axes[3][3];
|
|
} SpacetimeAsymptoticEnd;
|
|
|
|
/* Escape worldtube sample at one coordinate time. A zero `radius_rate` and a
|
|
* time-independent `velocity` describe the fixed/constant-velocity cases used
|
|
* in this phase. `valid == 0` means the backend cannot describe the worldtube
|
|
* at this time (history exhausted); callers must not treat that as a miss. */
|
|
typedef struct {
|
|
double center[3];
|
|
double velocity[3];
|
|
double radius;
|
|
double radius_rate;
|
|
/* Nonzero when `velocity` and `radius_rate` are exact throughout the
|
|
* current motion segment, so the first entry has a closed quadratic form. */
|
|
int velocity_constant;
|
|
int valid;
|
|
} SpacetimeEscapeWorldtubeSample;
|
|
|
|
typedef struct SpacetimeSource SpacetimeSource;
|
|
typedef struct MetricSlab MetricSlab;
|
|
|
|
struct MetricSlab {
|
|
const SpacetimeSource *source;
|
|
double t_hi, t_lo;
|
|
void *context;
|
|
};
|
|
|
|
typedef struct {
|
|
SpacetimePointStatus (*eval)(const SpacetimeSource *source, double t,
|
|
const double x[3], MetricData *metric);
|
|
SpacetimeRayStatus (*classify)(const SpacetimeSource *source, double t,
|
|
const double x[3]);
|
|
int (*load_slab)(const SpacetimeSource *source, double t_hi, double t_lo,
|
|
MetricSlab **out);
|
|
void (*free_slab)(MetricSlab *slab);
|
|
SpacetimePointStatus (*eval_slab)(const MetricSlab *slab, double t,
|
|
const double x[3], MetricData *metric);
|
|
SpacetimeRayStatus (*classify_slab)(const MetricSlab *slab, double t,
|
|
const double x[3]);
|
|
/* Declared asymptotic ends and their moving escape worldtubes. Backends
|
|
* without an escape sphere may leave these NULL. */
|
|
size_t (*asymptotic_end_count)(const SpacetimeSource *source);
|
|
int (*asymptotic_end)(const SpacetimeSource *source, size_t index,
|
|
SpacetimeAsymptoticEnd *out);
|
|
int (*escape_worldtube_sample)(const SpacetimeSource *source,
|
|
SpacetimeEndId end_id, double t,
|
|
SpacetimeEscapeWorldtubeSample *out);
|
|
/* Coordinate time of the next motion-segment boundary reached while
|
|
* integrating backward in time, i.e. the largest boundary strictly less
|
|
* than `t`. Return NAN when the worldtube description has a single open
|
|
* segment. */
|
|
double (*escape_worldtube_next_segment)(const SpacetimeSource *source,
|
|
SpacetimeEndId end_id, double t);
|
|
/* Analytic backends have negligible per-ray metric state. A numerical
|
|
* backend must opt in once its metric slabs and evaluator workspaces need
|
|
* to reserve memory alongside the private HDR render buffers. */
|
|
int limit_render_workers_by_memory;
|
|
void (*destroy)(SpacetimeSource *source);
|
|
} SpacetimeOps;
|
|
|
|
struct SpacetimeSource {
|
|
const SpacetimeOps *ops;
|
|
void *context;
|
|
};
|
|
|
|
/* The selected build provides spacetime_create_default(). Named constructors
|
|
* remain available to backend-specific tests and tools. */
|
|
int spacetime_create_default(SpacetimeSource *source);
|
|
int spacetime_create_minkowski(SpacetimeSource *source, double escape_radius);
|
|
int spacetime_create_schwarzschild_ks(SpacetimeSource *source, double mass,
|
|
double escape_radius);
|
|
/* Moving Alcubierre bubble with x_s(t) = vs*t and x_s(0) = 0. Requires
|
|
* |vs| < 1, R > 0, and sigma > 0. */
|
|
int spacetime_create_alcubierre(SpacetimeSource *source, double vs,
|
|
double radius, double sigma);
|
|
/* Bubble-centered escape radius used by the Alcubierre backend; also lets
|
|
* callers size their integration step budget. */
|
|
double spacetime_alcubierre_escape_radius(double radius, double sigma);
|
|
void spacetime_destroy(SpacetimeSource *source);
|
|
SpacetimePointStatus spacetime_eval(const SpacetimeSource *source, double t,
|
|
const double x[3], MetricData *metric);
|
|
SpacetimeRayStatus spacetime_classify(const SpacetimeSource *source, double t,
|
|
const double x[3]);
|
|
int spacetime_load_slab(const SpacetimeSource *source, double t_hi, double t_lo,
|
|
MetricSlab **out);
|
|
void spacetime_free_slab(MetricSlab *slab);
|
|
SpacetimePointStatus spacetime_slab_eval(const MetricSlab *slab, double t,
|
|
const double x[3], MetricData *metric);
|
|
SpacetimeRayStatus spacetime_slab_classify(const MetricSlab *slab, double t,
|
|
const double x[3]);
|
|
size_t spacetime_asymptotic_end_count(const SpacetimeSource *source);
|
|
int spacetime_asymptotic_end(const SpacetimeSource *source, size_t index,
|
|
SpacetimeAsymptoticEnd *out);
|
|
int spacetime_escape_worldtube_sample(const SpacetimeSource *source,
|
|
SpacetimeEndId end_id, double t,
|
|
SpacetimeEscapeWorldtubeSample *out);
|
|
double spacetime_escape_worldtube_next_segment(const SpacetimeSource *source,
|
|
SpacetimeEndId end_id, double t);
|
|
/* Common structural validation that every successful constructor must pass
|
|
* before returning. A source that passes is a promise that it can safely
|
|
* enter ray tracing; backend-specific history/segment validation stays in the
|
|
* backend constructor. On failure the constructor must destroy its context. */
|
|
int spacetime_source_finalize(SpacetimeSource *source);
|
|
int spacetime_limits_render_workers_by_memory(const SpacetimeSource *source);
|
|
|
|
#endif
|