Files
GR-raytracing/src/spacetime.h
T
wyj f7380cbf75 Feat: Rework ray termination into escaped/dark/unresolved/incomplete
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.
2026-10-05 06:22:47 -04:00

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