Observer: parameterize Schwarzschild camera view
This commit is contained in:
1 parent
457c0728b4
commit
83dc05fd52
5 files changed
+98
-21
No files matched your search
@@ -88,8 +88,12 @@ mkdir -p output/imgs
|
|||||||
|
|
||||||
`SPACETIME=minkowski` (the default) and `SPACETIME=schwarzschild` select source
|
`SPACETIME=minkowski` (the default) and `SPACETIME=schwarzschild` select source
|
||||||
files at compile time, so each executable contains exactly one metric provider.
|
files at compile time, so each executable contains exactly one metric provider.
|
||||||
The Schwarzschild demonstration uses mass `M=1`, a static camera at Cartesian
|
The Schwarzschild demonstration uses mass `M=1` and places a static camera at
|
||||||
Kerr--Schild position `(30, 0, 0)`, directed at the hole, escapes at `r=256`,
|
coordinate radius `30` by default. `--look-ra-deg` and `--look-dec-deg`
|
||||||
|
define the direction from the camera to the hole; the camera is placed at the
|
||||||
|
opposite direction from the origin and its local forward axis points radially
|
||||||
|
inward. Use `--observer-radius R` to select any `R > 2`; it is a coordinate
|
||||||
|
radius in Cartesian Kerr--Schild coordinates. The backend escapes at `r=256`
|
||||||
and declares capture at `r=1.5`, safely inside the horizon at `r=2`. Those
|
and declares capture at `r=1.5`, safely inside the horizon at `r=2`. Those
|
||||||
rendering thresholds are Phase-1 demonstration values, not settled production
|
rendering thresholds are Phase-1 demonstration values, not settled production
|
||||||
refinement or integration settings.
|
refinement or integration settings.
|
||||||
|
|||||||
+8
-3
@@ -19,6 +19,7 @@ typedef struct {
|
|||||||
int coarse_cell_pixels;
|
int coarse_cell_pixels;
|
||||||
int draw_mesh;
|
int draw_mesh;
|
||||||
double horizontal_fov_deg, look_ra_deg, look_dec_deg, exposure;
|
double horizontal_fov_deg, look_ra_deg, look_dec_deg, exposure;
|
||||||
|
double observer_radius;
|
||||||
double observer_inward_speed;
|
double observer_inward_speed;
|
||||||
PointSpreadFunction psf;
|
PointSpreadFunction psf;
|
||||||
const char *catalog_path;
|
const char *catalog_path;
|
||||||
@@ -102,6 +103,7 @@ static int parse_args(int argc, char **argv, Settings *s,
|
|||||||
.look_ra_deg = 270.0,
|
.look_ra_deg = 270.0,
|
||||||
.look_dec_deg = 0.0,
|
.look_dec_deg = 0.0,
|
||||||
.exposure = 1e-3,
|
.exposure = 1e-3,
|
||||||
|
.observer_radius = 30.0,
|
||||||
.psf = {2.7, 4.5},
|
.psf = {2.7, 4.5},
|
||||||
.catalog_path = "assets/sky_grid_5deg.csv",
|
.catalog_path = "assets/sky_grid_5deg.csv",
|
||||||
.output_path = "output/imgs/minkowski_sky.ppm",
|
.output_path = "output/imgs/minkowski_sky.ppm",
|
||||||
@@ -137,6 +139,8 @@ static int parse_args(int argc, char **argv, Settings *s,
|
|||||||
!parse_positive(argv[++i], &s->exposure)) {
|
!parse_positive(argv[++i], &s->exposure)) {
|
||||||
} else if (!strcmp(argv[i], "--observer-inward-speed") && i + 1 < argc &&
|
} else if (!strcmp(argv[i], "--observer-inward-speed") && i + 1 < argc &&
|
||||||
!parse_speed(argv[++i], &s->observer_inward_speed)) {
|
!parse_speed(argv[++i], &s->observer_inward_speed)) {
|
||||||
|
} else if (!strcmp(argv[i], "--observer-radius") && i + 1 < argc &&
|
||||||
|
!parse_positive(argv[++i], &s->observer_radius)) {
|
||||||
} else if (!strcmp(argv[i], "--psf-fwhm-pixels") && i + 1 < argc &&
|
} else if (!strcmp(argv[i], "--psf-fwhm-pixels") && i + 1 < argc &&
|
||||||
!parse_positive(argv[++i], &s->psf.fwhm_pixels)) {
|
!parse_positive(argv[++i], &s->psf.fwhm_pixels)) {
|
||||||
} else if (!strcmp(argv[i], "--psf-moffat-beta") && i + 1 < argc &&
|
} else if (!strcmp(argv[i], "--psf-moffat-beta") && i + 1 < argc &&
|
||||||
@@ -184,8 +188,9 @@ static GeodesicTraceConfig trace_config(void) {
|
|||||||
|
|
||||||
static int default_observer(const Settings *s, ObserverState *observer) {
|
static int default_observer(const Settings *s, ObserverState *observer) {
|
||||||
#ifdef SPACETIME_SCHWARZSCHILD
|
#ifdef SPACETIME_SCHWARZSCHILD
|
||||||
return observer_inward_schwarzschild_ks(1.0, 30.0,
|
return observer_inward_schwarzschild_ks_look_at(
|
||||||
s->observer_inward_speed, observer);
|
1.0, s->observer_radius, s->look_ra_deg, s->look_dec_deg,
|
||||||
|
s->observer_inward_speed, observer);
|
||||||
#else
|
#else
|
||||||
*observer = observer_fixed_at_origin_look_at(s->look_ra_deg, s->look_dec_deg);
|
*observer = observer_fixed_at_origin_look_at(s->look_ra_deg, s->look_dec_deg);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -352,7 +357,7 @@ int main(int argc, char **argv) {
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Usage: %s [--catalog PATH | --all-sky-catalog DIR] [--output PATH] [--width N] [--height "
|
"Usage: %s [--catalog PATH | --all-sky-catalog DIR] [--output PATH] [--width N] [--height "
|
||||||
"N] [--fov-deg D] [--look-ra-deg D] [--look-dec-deg D] "
|
"N] [--fov-deg D] [--look-ra-deg D] [--look-dec-deg D] "
|
||||||
"[--exposure E] [--observer-inward-speed V] "
|
"[--exposure E] [--observer-radius R] [--observer-inward-speed V] "
|
||||||
"[--psf-fwhm-pixels N] [--psf-moffat-beta N] "
|
"[--psf-fwhm-pixels N] [--psf-moffat-beta N] "
|
||||||
"[--coarse-cell-pixels N] [--draw-mesh] [--write-catalog PATH] "
|
"[--coarse-cell-pixels N] [--draw-mesh] [--write-catalog PATH] "
|
||||||
"[--catalog-load-workers N] "
|
"[--catalog-load-workers N] "
|
||||||
|
|||||||
+58
-12
@@ -30,29 +30,69 @@ ObserverState observer_fixed_at_origin_look_at(double ra_deg, double dec_deg) {
|
|||||||
{0.0, right[0], right[1], right[2]}}};
|
{0.0, right[0], right[1], right[2]}}};
|
||||||
}
|
}
|
||||||
|
|
||||||
int observer_static_schwarzschild_ks(double mass, double radius,
|
static int schwarzschild_look_direction(double ra_deg, double dec_deg,
|
||||||
ObserverState *out) {
|
double direction[3], double up[3],
|
||||||
if (out == NULL || mass <= 0.0 || radius <= 2.0 * mass)
|
double right[3]) {
|
||||||
|
if (!isfinite(ra_deg) || !isfinite(dec_deg) || ra_deg < 0.0 ||
|
||||||
|
ra_deg >= 360.0 || dec_deg < -90.0 || dec_deg > 90.0)
|
||||||
|
return -1;
|
||||||
|
const double ra = ra_deg * pi / 180.0;
|
||||||
|
const double dec = dec_deg * pi / 180.0;
|
||||||
|
const double cos_ra = cos(ra), sin_ra = sin(ra);
|
||||||
|
const double cos_dec = cos(dec), sin_dec = sin(dec);
|
||||||
|
direction[0] = cos_dec * cos_ra;
|
||||||
|
direction[1] = sin_dec;
|
||||||
|
direction[2] = cos_dec * sin_ra;
|
||||||
|
up[0] = -sin_dec * cos_ra;
|
||||||
|
up[1] = cos_dec;
|
||||||
|
up[2] = -sin_dec * sin_ra;
|
||||||
|
right[0] = -sin_ra;
|
||||||
|
right[1] = 0.0;
|
||||||
|
right[2] = cos_ra;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int observer_static_schwarzschild_ks_look_at(double mass, double radius,
|
||||||
|
double look_ra_deg,
|
||||||
|
double look_dec_deg,
|
||||||
|
ObserverState *out) {
|
||||||
|
double direction[3], up[3], right[3];
|
||||||
|
if (out == NULL || mass <= 0.0 || radius <= 2.0 * mass ||
|
||||||
|
schwarzschild_look_direction(look_ra_deg, look_dec_deg, direction, up,
|
||||||
|
right))
|
||||||
return -1;
|
return -1;
|
||||||
const double f = 2.0 * mass / radius;
|
const double f = 2.0 * mass / radius;
|
||||||
const double normalization = sqrt(1.0 - f);
|
const double normalization = sqrt(1.0 - f);
|
||||||
*out = (ObserverState){
|
*out = (ObserverState){
|
||||||
.coordinate_time = 0.0,
|
.coordinate_time = 0.0,
|
||||||
.coordinate_position = {radius, 0.0, 0.0},
|
.coordinate_position = {-radius * direction[0], -radius * direction[1],
|
||||||
/* e_(0) is the static four-velocity. e_(1) points inward; its time
|
-radius * direction[2]},
|
||||||
* component makes the tetrad orthonormal in the KS metric. */
|
/* e_(0) is the static four-velocity. e_(1) points inward, toward the
|
||||||
|
* origin; its time component makes the tetrad orthonormal in the KS
|
||||||
|
* metric. */
|
||||||
.tetrad = {{1.0 / normalization, 0.0, 0.0, 0.0},
|
.tetrad = {{1.0 / normalization, 0.0, 0.0, 0.0},
|
||||||
{-f / normalization, -normalization, 0.0, 0.0},
|
{-f / normalization, normalization * direction[0],
|
||||||
{0.0, 0.0, 1.0, 0.0},
|
normalization * direction[1], normalization * direction[2]},
|
||||||
{0.0, 0.0, 0.0, 1.0}}};
|
{0.0, up[0], up[1], up[2]},
|
||||||
|
{0.0, right[0], right[1], right[2]}}};
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int observer_inward_schwarzschild_ks(double mass, double radius,
|
int observer_static_schwarzschild_ks(double mass, double radius,
|
||||||
double inward_speed, ObserverState *out) {
|
ObserverState *out) {
|
||||||
|
return observer_static_schwarzschild_ks_look_at(mass, radius, 180.0, 0.0,
|
||||||
|
out);
|
||||||
|
}
|
||||||
|
|
||||||
|
int observer_inward_schwarzschild_ks_look_at(double mass, double radius,
|
||||||
|
double look_ra_deg,
|
||||||
|
double look_dec_deg,
|
||||||
|
double inward_speed,
|
||||||
|
ObserverState *out) {
|
||||||
ObserverState static_observer;
|
ObserverState static_observer;
|
||||||
if (inward_speed < 0.0 || inward_speed >= 1.0 ||
|
if (inward_speed < 0.0 || inward_speed >= 1.0 ||
|
||||||
observer_static_schwarzschild_ks(mass, radius, &static_observer))
|
observer_static_schwarzschild_ks_look_at(
|
||||||
|
mass, radius, look_ra_deg, look_dec_deg, &static_observer))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
const double gamma = 1.0 / sqrt(1.0 - inward_speed * inward_speed);
|
const double gamma = 1.0 / sqrt(1.0 - inward_speed * inward_speed);
|
||||||
@@ -65,3 +105,9 @@ int observer_inward_schwarzschild_ks(double mass, double radius,
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int observer_inward_schwarzschild_ks(double mass, double radius,
|
||||||
|
double inward_speed, ObserverState *out) {
|
||||||
|
return observer_inward_schwarzschild_ks_look_at(mass, radius, 180.0, 0.0,
|
||||||
|
inward_speed, out);
|
||||||
|
}
|
||||||
+15
-4
@@ -12,12 +12,23 @@ ObserverState observer_fixed_at_origin(void);
|
|||||||
/* Point the fixed inertial observer at an ICRS-style RA/Dec direction.
|
/* Point the fixed inertial observer at an ICRS-style RA/Dec direction.
|
||||||
* The local spatial axes remain (forward, celestial north, increasing RA). */
|
* The local spatial axes remain (forward, celestial north, increasing RA). */
|
||||||
ObserverState observer_fixed_at_origin_look_at(double ra_deg, double dec_deg);
|
ObserverState observer_fixed_at_origin_look_at(double ra_deg, double dec_deg);
|
||||||
/* Static camera at (radius, 0, 0) in Cartesian Kerr--Schild coordinates,
|
/* Static camera at Cartesian Kerr--Schild position -radius * look_direction,
|
||||||
* directed toward the Schwarzschild black hole at the origin. */
|
* directed toward the Schwarzschild black hole at the origin. look_direction
|
||||||
|
* uses the same ICRS-style RA/Dec convention as the flat-space camera. */
|
||||||
|
int observer_static_schwarzschild_ks_look_at(double mass, double radius,
|
||||||
|
double look_ra_deg,
|
||||||
|
double look_dec_deg,
|
||||||
|
ObserverState *out);
|
||||||
|
/* Compatibility shortcut for the +X camera directed toward the origin. */
|
||||||
int observer_static_schwarzschild_ks(double mass, double radius,
|
int observer_static_schwarzschild_ks(double mass, double radius,
|
||||||
ObserverState *out);
|
ObserverState *out);
|
||||||
/* Camera at (radius, 0, 0), moving inward at local speed inward_speed with
|
/* As above, with a local radial inward boost relative to the static observer. */
|
||||||
* respect to the static Schwarzschild observer. */
|
int observer_inward_schwarzschild_ks_look_at(double mass, double radius,
|
||||||
|
double look_ra_deg,
|
||||||
|
double look_dec_deg,
|
||||||
|
double inward_speed,
|
||||||
|
ObserverState *out);
|
||||||
|
/* Compatibility shortcut for the +X camera directed toward the origin. */
|
||||||
int observer_inward_schwarzschild_ks(double mass, double radius,
|
int observer_inward_schwarzschild_ks(double mass, double radius,
|
||||||
double inward_speed, ObserverState *out);
|
double inward_speed, ObserverState *out);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ int main(void) {
|
|||||||
SpacetimeSource spacetime = {0};
|
SpacetimeSource spacetime = {0};
|
||||||
MetricData metric;
|
MetricData metric;
|
||||||
ObserverState observer;
|
ObserverState observer;
|
||||||
|
ObserverState oriented_observer;
|
||||||
ObserverState inward_observer;
|
ObserverState inward_observer;
|
||||||
const GeodesicTraceConfig trace = {.coordinate_time_step = 0.1,
|
const GeodesicTraceConfig trace = {.coordinate_time_step = 0.1,
|
||||||
.max_steps = 4096,
|
.max_steps = 4096,
|
||||||
@@ -17,6 +18,16 @@ int main(void) {
|
|||||||
!isfinite(metric.alpha) || !isfinite(metric.gamma[0][0]) ||
|
!isfinite(metric.alpha) || !isfinite(metric.gamma[0][0]) ||
|
||||||
!isfinite(metric.K[0][0]) ||
|
!isfinite(metric.K[0][0]) ||
|
||||||
observer_static_schwarzschild_ks(1.0, 30.0, &observer) ||
|
observer_static_schwarzschild_ks(1.0, 30.0, &observer) ||
|
||||||
|
observer_static_schwarzschild_ks_look_at(1.0, 40.0, 270.0, 30.0,
|
||||||
|
&oriented_observer) ||
|
||||||
|
fabs(oriented_observer.coordinate_position[0]) > 1e-12 ||
|
||||||
|
fabs(oriented_observer.coordinate_position[1] + 20.0) > 1e-12 ||
|
||||||
|
fabs(oriented_observer.coordinate_position[2] - 20.0 * sqrt(3.0)) >
|
||||||
|
1e-12 ||
|
||||||
|
fabs(oriented_observer.tetrad[1][1]) > 1e-12 ||
|
||||||
|
fabs(oriented_observer.tetrad[1][2] - 0.5 * sqrt(0.95)) > 1e-12 ||
|
||||||
|
fabs(oriented_observer.tetrad[1][3] + sqrt(0.95) * sqrt(3.0) / 2.0) >
|
||||||
|
1e-12 ||
|
||||||
observer_inward_schwarzschild_ks(1.0, 30.0, 0.5,
|
observer_inward_schwarzschild_ks(1.0, 30.0, 0.5,
|
||||||
&inward_observer) ||
|
&inward_observer) ||
|
||||||
fabs(inward_observer.tetrad[0][0] -
|
fabs(inward_observer.tetrad[0][0] -
|
||||||
|
|||||||
Reference in new issue
Block a user