Files
GR-raytracing/tests/test_schwarzschild.c
T

85 lines
3.7 KiB
C

#include "geodesic.h"
#include "frame.h"
#include <math.h>
#include <stdio.h>
static int camera_at(const SpacetimeSource *source, double radius,
double ra, double dec, ObserverState *out) {
ObserverCamera camera = {.look_ra_deg = ra, .look_dec_deg = dec};
const ObserverState pointing = observer_fixed_at_origin_look_at(ra, dec);
for (int i = 0; i < 3; ++i)
camera.position[i] = -radius * pointing.tetrad[1][i + 1];
MetricData metric;
return spacetime_eval(source, 0.0, camera.position, &metric) ||
observer_from_coordinate_camera(&metric, &camera, out, NULL);
}
int main(void) {
SpacetimeSource spacetime = {0};
MetricData metric;
ObserverState observer;
ObserverState oriented_observer;
const GeodesicTraceConfig trace = {.coordinate_time_step = 0.1,
.max_steps = 4096,
.capture_log_alpha_p0 = 8.0};
int result = 1;
if (spacetime_create_schwarzschild_ks(&spacetime, 1.0, 256.0, 1.5) ||
spacetime_eval(&spacetime, 0.0, (double[]){2.0, 0.0, 0.0}, &metric) ||
!isfinite(metric.alpha) || !isfinite(metric.gamma[0][0]) ||
!isfinite(metric.K[0][0]) ||
camera_at(&spacetime, 30.0, 180.0, 0.0, &observer) ||
camera_at(&spacetime, 40.0, 270.0, 30.0,
&oriented_observer) ||
fabs(oriented_observer.coordinate_position[0]) > 1e-12 ||
fabs(oriented_observer.coordinate_position[1] - 20.0 * sqrt(3.0)) >
1e-12 ||
fabs(oriented_observer.coordinate_position[2] + 20.0) >
1e-12 ||
fabs(oriented_observer.tetrad[1][1]) > 1e-12 ||
fabs(oriented_observer.tetrad[1][2] + sqrt(0.95) * sqrt(3.0) / 2.0) >
1e-12 ||
fabs(oriented_observer.tetrad[1][3] - 0.5 * sqrt(0.95)) >
1e-12)
goto done;
const RayEndpoint central = geodesic_trace_past(
&spacetime, &observer, (double[]){1.0, 0.0, 0.0}, &trace);
const RayEndpoint inside_shadow = geodesic_trace_past(
&spacetime, &observer, (double[]){cos(0.10), sin(0.10), 0.0}, &trace);
const RayEndpoint outside_shadow = geodesic_trace_past(
&spacetime, &observer, (double[]){cos(0.30), sin(0.30), 0.0}, &trace);
if (central.status != RAY_ENDPOINT_CAPTURED ||
inside_shadow.status != RAY_ENDPOINT_CAPTURED ||
outside_shadow.status != RAY_ENDPOINT_ESCAPED) {
fprintf(stderr,
"Schwarzschild KS shadow regression failed (center=%d, inside=%d, "
"outside=%d)\n",
central.status, inside_shadow.status, outside_shadow.status);
goto done;
}
/* A coarse field covering the shadow must genuinely refine: its initial
* capture/escape-discontinuous triangles are a separate trigger from the
* smooth direction-error criterion. */
FrameLensMesh mesh = {0};
const RefinementConfig refinement = {.max_level = 1,
.angle_absolute_rad = 1e-5,
.angle_relative = 1e-5,
.jacobian_minimum = 1e-3,
.min_edge_pixels = 1.0,
.min_area_pixels2 = 1.0};
if (frame_lens_mesh_build_coarse(&mesh, 48, 48, 24, 40.0) ||
frame_lens_mesh_trace(&mesh, &spacetime, &observer, &trace) ||
frame_lens_mesh_refine(&mesh, &spacetime, &observer, &trace,
&refinement) ||
mesh.vertex_count <= 9 || mesh.triangle_count <= 8) {
fputs("Schwarzschild adaptive-refinement regression failed\n", stderr);
frame_lens_mesh_destroy(&mesh);
goto done;
}
frame_lens_mesh_destroy(&mesh);
result = 0;
done:
spacetime_destroy(&spacetime);
return result;
}