Feat: generate freely falling Schwarzschild camera tracks

Integrate timelike geodesics and Fermi-Walker tetrads in ingoing Kerr-Schild coordinates, sampled at a configurable proper-time cadence.

Add movie-track-samples to preserve CSV events as frames. Document usage and singularity guards, and cover analytic orbits, transport convergence, sampling, and CSV rendering.
This commit is contained in:
wyj committed 2026-09-06 05:56:51 -04:00
1 parent 8d011b7ec5
commit b69c9cfd45
9 files changed
+446 -3

No files matched your search

+46
View File
@@ -185,3 +185,49 @@ mkdir -p output/imgs
[![Synthetic stellar grid lensed by a Schwarzschild black hole, with adaptive mesh overlay](assets/images/schwarzschild_test_grid.png)](assets/images/schwarzschild_test_grid.png)
*4K test-grid reference image. Click to view at full resolution.*
### Freely falling Schwarzschild movie camera
`scripts/schwarzschild_camera_track.py` generates the canonical 21-column observer
CSV in ingoing Cartesian Kerr–Schild coordinates (`G=c=M=1`, matching the renderer).
It requires Python 3, NumPy and SciPy. Position is `(x,y,z)`; velocity is coordinate
`(dx/dt,dy/dt,dz/dt)`. Look RA/Dec and roll construct the initial rest-frame
forward/up/right legs with the same convention as the single-image camera. Without
look angles, the camera initially points toward the origin. The orientation then
follows Fermi–Walker transport; for free fall this is parallel transport, so it does
not keep pointing at the black hole. `--tetrad` alternatively accepts 16 row-major
components `(e0t,e0x,...,e3z)` of an orthonormal tetrad, with `e0` matching velocity.
```sh
python3 scripts/schwarzschild_camera_track.py \
--position 8 0 0 --velocity 0 0 0 \
--look-ra-deg 0 --look-dec-deg 0 --roll-deg 0 \
--fps 30 --duration 10 --output /tmp/freefall_camera.csv
make SPACETIME=schwarzschild all
mkdir -p output/freefall_frames
./build/Release/schwarzschild_sky \
--observer-track /tmp/freefall_camera.csv --movie-track-samples \
--frames-dir output/freefall_frames --catalog assets/sky_grid_5deg.csv \
--width 640 --height 360 --fov-deg 60 --exposure 0.2
ffmpeg -framerate 30 -i output/freefall_frames/frame_%06d.png \
-c:v libx264 -pix_fmt yuv420p output/freefall.mp4
```
Here `--duration` is elapsed **proper time**, and `--fps` is samples per unit proper
time. CSV rows occur at `tau=k/fps <= duration`, including the initial event and an
endpoint only if it lies on that cadence (10 at 30 fps gives 301 rows). `tau` starts
at zero; `--t0` sets the initial coordinate time. `--movie-track-samples` uses each
row exactly once and ignores renderer `--start-time`, `--duration`, and `--fps`;
encode the PNG sequence at the generator's fps. Without this flag the existing
movie mode resamples at uniform coordinate time, which changes the proper-time cadence.
DOP853 jointly integrates the geodesic and all tetrad legs using analytic metric
derivatives. Defaults: `--rtol 1e-10 --atol 1e-12 --stop-radius 0.001`.
Integration crosses the horizon and stops at this numerical guard before the
singularity, reporting its proper time and retaining only regular cadence samples.
The guard is not the exact singularity; reduce it and tolerances to check convergence.
The renderer's independent ray capture cutoff remains `r=1.5M`: rows inside it are
valid trajectory data but the current renderer captures those rays immediately.
The script reports maximum tetrad drift and rejects errors above `1e-6` rather
than silently repairing the transported frame. Run the orbit, transport and CSV
render regressions after building with `python3 tests/test_schwarzschild_camera_track.py`.