Feat: Complete adaptive geodesic tracing with DP54
Add error-controlled DP5(4) integration and trusted first-crossing localization, including non-monotonic energy thresholds and representable-time stepping. Preserve adaptive state and independent step/time retry grants across RayPool, refinement and movie scheduling. Expose numerical controls, record actual persistent-sample costs, and add v3 lens-map provenance with legacy v2 RK4 import. Use DP54 by default and select an 8M Schwarzschild maximum step from bounded scans and a two-run 4K comparison. Retain the conservative minimum-step guard and document critical-ray and backend capability limits. Archive self-contained benchmark inputs and raw output; keep fixed RK4 HDR references explicit. Validation: make -B -j4 BUILD_TYPE=Debug test passed; explicit RK4 HDR references have zero differences. Bounded convergence checks, benchmark reproduction, Release build and focused reviews passed. No numerical-relativity backend is added.
This commit is contained in:
1 parent
c894fdb11a
commit
0a46a7095b
48 files changed
+11491
-380
No files matched your search
@@ -106,6 +106,7 @@ endif
|
|||||||
# built for a different backend.
|
# built for a different backend.
|
||||||
TEST_OUT_DIR := $(OBJECT_DIR)/$(HDR_BUILD_TAG)
|
TEST_OUT_DIR := $(OBJECT_DIR)/$(HDR_BUILD_TAG)
|
||||||
TEST_TARGET := $(TEST_OUT_DIR)/test_geodesic
|
TEST_TARGET := $(TEST_OUT_DIR)/test_geodesic
|
||||||
|
ADAPTIVE_GEODESIC_TEST_TARGET := $(TEST_OUT_DIR)/test_geodesic_adaptive
|
||||||
ASYMPTOTIC_TEST_TARGET := $(TEST_OUT_DIR)/test_asymptotic
|
ASYMPTOTIC_TEST_TARGET := $(TEST_OUT_DIR)/test_asymptotic
|
||||||
ASYMPTOTIC_SCHWARZSCHILD_TEST_TARGET := $(TEST_OUT_DIR)/test_asymptotic_schwarzschild
|
ASYMPTOTIC_SCHWARZSCHILD_TEST_TARGET := $(TEST_OUT_DIR)/test_asymptotic_schwarzschild
|
||||||
TERMINATION_ORACLE_TEST_TARGET := $(TEST_OUT_DIR)/test_termination_oracle
|
TERMINATION_ORACLE_TEST_TARGET := $(TEST_OUT_DIR)/test_termination_oracle
|
||||||
@@ -207,6 +208,12 @@ $(TEST_OUT_DIR): | $(BUILD_DIR)
|
|||||||
$(TEST_TARGET): tests/test_geodesic.c $(CORE_MINKOWSKI_SOURCES) $(CPU_FFTW_SOURCES) | $(TEST_OUT_DIR)
|
$(TEST_TARGET): tests/test_geodesic.c $(CORE_MINKOWSKI_SOURCES) $(CPU_FFTW_SOURCES) | $(TEST_OUT_DIR)
|
||||||
$(CC) $(CPPFLAGS) $(BUILD_CPPFLAGS) $(CFLAGS) $(BUILD_CFLAGS) $(OPENMP_FLAGS) -Isrc $^ $(LDLIBS) -o $@
|
$(CC) $(CPPFLAGS) $(BUILD_CPPFLAGS) $(CFLAGS) $(BUILD_CFLAGS) $(OPENMP_FLAGS) -Isrc $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
|
# Explicit adaptive DP5(4) core and RayPool regression. The test textually
|
||||||
|
# includes both analytic providers (renaming spacetime_create_default), so the
|
||||||
|
# link line deliberately omits src/spacetime_{minkowski,schwarzschild}.c.
|
||||||
|
$(ADAPTIVE_GEODESIC_TEST_TARGET): tests/test_geodesic_adaptive.c $(COMMON_SOURCES) $(CPU_FFTW_SOURCES) | $(TEST_OUT_DIR)
|
||||||
|
$(CC) $(CPPFLAGS) $(BUILD_CPPFLAGS) $(CFLAGS) $(BUILD_CFLAGS) $(OPENMP_FLAGS) -DGEODESIC_EVENT_TESTING -Isrc $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
$(ASYMPTOTIC_TEST_TARGET): tests/test_asymptotic.c $(CORE_MINKOWSKI_SOURCES) $(CPU_FFTW_SOURCES) | $(TEST_OUT_DIR)
|
$(ASYMPTOTIC_TEST_TARGET): tests/test_asymptotic.c $(CORE_MINKOWSKI_SOURCES) $(CPU_FFTW_SOURCES) | $(TEST_OUT_DIR)
|
||||||
$(CC) $(CPPFLAGS) $(BUILD_CPPFLAGS) $(CFLAGS) $(BUILD_CFLAGS) $(OPENMP_FLAGS) -Isrc $^ $(LDLIBS) -o $@
|
$(CC) $(CPPFLAGS) $(BUILD_CPPFLAGS) $(CFLAGS) $(BUILD_CFLAGS) $(OPENMP_FLAGS) -Isrc $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
@@ -273,10 +280,11 @@ FAST_PSF_FFTW_TEST_DEP :=
|
|||||||
FAST_PSF_FFTW_TEST_RUN :=
|
FAST_PSF_FFTW_TEST_RUN :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
test: $(CAMERA_TEST_TARGETS) $(TEST_TARGET) $(ASYMPTOTIC_TEST_TARGET) $(ASYMPTOTIC_SCHWARZSCHILD_TEST_TARGET) $(TERMINATION_ORACLE_TEST_TARGET) $(FRAME_TEST_TARGET) $(SCHWARZSCHILD_TEST_TARGET) $(ALCUBIERRE_TEST_TARGET) $(OBSERVER_TRACK_TEST_TARGET) $(CATALOG_PREFETCH_TEST_TARGET) $(FAST_PSF_FFTW_TEST_DEP) $(TONE_MAP_TEST_TARGET) $(MOVIE_OUTPUT_TEST_TARGET) $(SENSOR_BLOOM_TEST_TARGET)
|
test: $(CAMERA_TEST_TARGETS) $(TEST_TARGET) $(ADAPTIVE_GEODESIC_TEST_TARGET) $(ASYMPTOTIC_TEST_TARGET) $(ASYMPTOTIC_SCHWARZSCHILD_TEST_TARGET) $(TERMINATION_ORACLE_TEST_TARGET) $(FRAME_TEST_TARGET) $(SCHWARZSCHILD_TEST_TARGET) $(ALCUBIERRE_TEST_TARGET) $(OBSERVER_TRACK_TEST_TARGET) $(CATALOG_PREFETCH_TEST_TARGET) $(FAST_PSF_FFTW_TEST_DEP) $(TONE_MAP_TEST_TARGET) $(MOVIE_OUTPUT_TEST_TARGET) $(SENSOR_BLOOM_TEST_TARGET)
|
||||||
$(TEST_OUT_DIR)/test_observer_minkowski
|
$(TEST_OUT_DIR)/test_observer_minkowski
|
||||||
$(TEST_OUT_DIR)/test_observer_schwarzschild
|
$(TEST_OUT_DIR)/test_observer_schwarzschild
|
||||||
$(TEST_TARGET)
|
$(TEST_TARGET)
|
||||||
|
$(ADAPTIVE_GEODESIC_TEST_TARGET)
|
||||||
$(ASYMPTOTIC_TEST_TARGET)
|
$(ASYMPTOTIC_TEST_TARGET)
|
||||||
$(ASYMPTOTIC_SCHWARZSCHILD_TEST_TARGET)
|
$(ASYMPTOTIC_SCHWARZSCHILD_TEST_TARGET)
|
||||||
$(TERMINATION_ORACLE_TEST_TARGET)
|
$(TERMINATION_ORACLE_TEST_TARGET)
|
||||||
@@ -290,6 +298,7 @@ test: $(CAMERA_TEST_TARGETS) $(TEST_TARGET) $(ASYMPTOTIC_TEST_TARGET) $(ASYMPTOT
|
|||||||
$(MOVIE_OUTPUT_TEST_TARGET)
|
$(MOVIE_OUTPUT_TEST_TARGET)
|
||||||
$(SENSOR_BLOOM_TEST_TARGET)
|
$(SENSOR_BLOOM_TEST_TARGET)
|
||||||
python3 tests/test_camera_cli.py $(BUILD_DIR) $(TEST_OUT_DIR)
|
python3 tests/test_camera_cli.py $(BUILD_DIR) $(TEST_OUT_DIR)
|
||||||
|
python3 tests/test_adaptive_cli.py $(BUILD_DIR) $(TEST_OUT_DIR)
|
||||||
|
|
||||||
tone-map-test: $(TONE_MAP_TEST_TARGET)
|
tone-map-test: $(TONE_MAP_TEST_TARGET)
|
||||||
$(TONE_MAP_TEST_TARGET)
|
$(TONE_MAP_TEST_TARGET)
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
# adaptive_step_bounds_2026-10-05
|
||||||
|
|
||||||
|
Long-term benchmark for calibrating the DP54 adaptive-integrator step bounds
|
||||||
|
(`min_step` / `max_step`) of the past-directed null-geodesic tracer, and the
|
||||||
|
public record of the one authorised 4K Schwarzschild `max_step` 2-vs-8 pair.
|
||||||
|
|
||||||
|
The benchmark runs the public endpoint `geodesic_trace_past()`, the production
|
||||||
|
DP core, and bounded adaptive-mesh renders against the analytic
|
||||||
|
Minkowski / Schwarzschild / Alcubierre backends. It does not modify production
|
||||||
|
sources.
|
||||||
|
|
||||||
|
## Build (required before renderer scripts)
|
||||||
|
|
||||||
|
The Python mesh/4K drivers start from an existing renderer binary. The shell
|
||||||
|
endpoint/core drivers compile their own small harnesses against production code.
|
||||||
|
|
||||||
|
```
|
||||||
|
make -j4 BUILD_TYPE=Release SPACETIME=schwarzschild backend
|
||||||
|
# binary: build/Release/schwarzschild_sky
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| file | role |
|
||||||
|
|---|---|
|
||||||
|
| `a_public_endpoints.c` | Experiment A: step-bound scans through the public endpoint, tol=1e-12 reference, RK4 h-halving on near-critical rays. |
|
||||||
|
| `b_actual_h.c` | Experiment B: textually includes `src/geodesic.c`, drives the production `dp_advance_one` on finite trusted intervals to measure observed accepted `h`. |
|
||||||
|
| `critical_ref_check.c` | Critical-classification probe (r30/r100 inward, r2.1 outward; `theta_crit` and `theta_crit±1e-7`; tol/max_step ladder). |
|
||||||
|
| `mesh_maps.py` | Pure GRLENS v3 `load`/`compare`; no renderer, no untracked import. |
|
||||||
|
| `run_mesh.py` | 8 bounded 320x180 candidates (R100 and R2.1, `max_step` .5/2/8/32). |
|
||||||
|
| `run_mesh_reference.py` | 2 tight-tolerance references and comparisons against the 8 maps. |
|
||||||
|
| `summarize_4k.py` | Postprocess existing maps only; never invokes a renderer. |
|
||||||
|
| `run_4k_pair.py` | One-task, at-most-two-attempt 4K pair; refuses to run without `--authorize-two-4k`. |
|
||||||
|
| `record_environment.py` | Provenance (git/hashes/compiler/cpu/build/run commands); no render. |
|
||||||
|
| `failure_floor.c` | Failure-path floor diagnostic; includes `../../tests/test_geodesic_adaptive.c`. |
|
||||||
|
| `run_failure_floor.sh` | Builds/runs `failure_floor.c` with `-DGEODESIC_EVENT_TESTING`. |
|
||||||
|
| `run_limited.sh` | Builds/runs Experiment A + B; all output under `OUT_DIR`. |
|
||||||
|
| `run_critical_ref.sh` | Builds/runs `critical_ref_check.c`; all output under `OUT_DIR`. |
|
||||||
|
| `summarize.py` | `OUT_DIR` CLI arg (default `local/adaptive_step_bounds_2026-10-05`); writes `OUT_DIR/logs/summary.txt`. |
|
||||||
|
| `results/` | Tracked long-term evidence (see below). |
|
||||||
|
|
||||||
|
## Reproduction
|
||||||
|
|
||||||
|
```
|
||||||
|
AB_OUT="$PWD/local/adaptive_step_bounds_2026-10-05"
|
||||||
|
OUT="$PWD/local/adaptive_bounds_mesh"
|
||||||
|
|
||||||
|
bash benchmarks/adaptive_step_bounds_2026-10-05/run_limited.sh "$AB_OUT"
|
||||||
|
bash benchmarks/adaptive_step_bounds_2026-10-05/run_critical_ref.sh "$AB_OUT"
|
||||||
|
python3 benchmarks/adaptive_step_bounds_2026-10-05/summarize.py "$AB_OUT"
|
||||||
|
|
||||||
|
python3 benchmarks/adaptive_step_bounds_2026-10-05/run_mesh.py "$OUT"
|
||||||
|
python3 benchmarks/adaptive_step_bounds_2026-10-05/run_mesh_reference.py "$OUT"
|
||||||
|
bash benchmarks/adaptive_step_bounds_2026-10-05/run_failure_floor.sh "$OUT"
|
||||||
|
|
||||||
|
# 4K only after explicit fresh user authorization for that task:
|
||||||
|
python3 benchmarks/adaptive_step_bounds_2026-10-05/run_4k_pair.py \
|
||||||
|
--authorize-two-4k --out local/adaptive_bounds_4k
|
||||||
|
```
|
||||||
|
|
||||||
|
Defaults: A/B `OUT_DIR` is `local/adaptive_step_bounds_2026-10-05`; mesh
|
||||||
|
`OUT_DIR` is `local/adaptive_bounds_mesh`; 4K `--out` default is
|
||||||
|
`local/adaptive_bounds_4k`. All logs/CSV go to `OUT_DIR`; the tracked
|
||||||
|
benchmark directory holds only sources and `results/`. Scratch binaries go to
|
||||||
|
`/tmp/opencode/step_bounds/`.
|
||||||
|
|
||||||
|
The `run_4k_pair.py` driver refuses to run without `--authorize-two-4k`, keeps
|
||||||
|
an attempt ledger, and has no automatic retry. Authorisation does not extend to
|
||||||
|
later tasks or routine tests.
|
||||||
|
|
||||||
|
All catalog inputs are generated inline by the scripts (column header
|
||||||
|
`longitude_deg,latitude_deg,temperature_K,amplitude`, one 1e-30 star); no
|
||||||
|
external survey CSV is read.
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
### 1. Public-endpoint step-bound scan (Experiment A/B)
|
||||||
|
|
||||||
|
Environment and full table inputs: `results/source_environment.txt`,
|
||||||
|
`results/summary_tables.txt`; full stdout: `results/expA.log`,
|
||||||
|
`results/expB.log`. Per-ray raw CSV (not tracked) is reproduced by
|
||||||
|
`run_limited.sh`.
|
||||||
|
|
||||||
|
| backend | worst near-critical sky error vs tol=1e-12 ref | notes |
|
||||||
|
|---|---|---|
|
||||||
|
| Schwarzschild r30 | 2.82e-4 rad (`max_step`≥1); 8.67e-5 rad at 0.25 | r100 8.0e-5 / 2.6e-5; r2.1 2.87e-4 |
|
||||||
|
| Minkowski | Δn = 0, Δg/g = 0 (analytic) | crossing x/t ≤ 7.7e-11 at `max_step`≤256 |
|
||||||
|
| Alcubierre | ≤1.8e-10 rad, no class change | 8x vs 1x `initial` RHS cost 4.3x–5.7x |
|
||||||
|
|
||||||
|
- Dark terminal `L−L0` margin agrees with the reference to ≤2.1e-13 in every
|
||||||
|
config; near-critical dark stop times differ up to ~41 time units between
|
||||||
|
tol=1e-9 and tol=1e-12 (orbit-count sensitivity, reported not hidden).
|
||||||
|
- Schwarzschild floor plateau: `min_step` `1e-14 … 1e-2` give bit-identical
|
||||||
|
results and RHS; only `0.1` breaks one r1.5 ray
|
||||||
|
(`INCOMPLETE/INTEGRATION_ERROR`). No evidence to raise the default floor,
|
||||||
|
and no evidence that `1e-12` is uniquely optimal (it is never active).
|
||||||
|
- Observed accepted `h` (Experiment B, finite window `T=min(20, ref span)`):
|
||||||
|
**Schwarzschild only** — r1.5 radial 0.0921, all other sampled Schwarzschild
|
||||||
|
rays ≥0.1; Alcubierre minimum = its initial step (0.05 / 0.005 / 0.0005);
|
||||||
|
Minkowski 1.0. This is a finite-window diagnostic, **not** a full-trajectory
|
||||||
|
minimum.
|
||||||
|
- RK4 h-halving worst (r2.1, `theta_crit−1e-7`): 1.04e-5 rad.
|
||||||
|
|
||||||
|
### 2. Bounded 320x180 adaptive mesh
|
||||||
|
|
||||||
|
Numeric inputs: `results/mesh_summary.json`,
|
||||||
|
`results/mesh_reference_summary.json`. Scene: R100/FOV45/jacobian0.2 and
|
||||||
|
R2.1/outward/FOV90; DP54, hmin 1e-12, initial 0.1, tol 1e-9 (tight reference
|
||||||
|
1e-12), 8 threads, one-point dim catalog.
|
||||||
|
|
||||||
|
| scene | `max_step` | persistent vertices | RHS | wall (s) |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| R100 | 0.5 | 3158 | 16813349 | 2.071 |
|
||||||
|
| R100 | 2 | 3158 | 6030185 | 0.979 |
|
||||||
|
| R100 | 8 | 3158 | 4230835 | 0.823 |
|
||||||
|
| R100 | 32 | 3158 | 4081609 | 0.830 |
|
||||||
|
| R2.1 | 0.5 | 5496 | 20136508 | 1.974 |
|
||||||
|
| R2.1 | 2 | 5496 | 9548434 | 1.178 |
|
||||||
|
| R2.1 | 8 | 5496 | 7389760 | 0.970 |
|
||||||
|
| R2.1 | 32 | 5496 | 7197806 | 0.972 |
|
||||||
|
|
||||||
|
- 2→8 RHS reduction 29.84% (R100) / 22.61% (R2.1); 8→32 only 3.53% / 2.60%.
|
||||||
|
- Identical terminal classifications and mesh/sample counts for all four caps.
|
||||||
|
- Error vs tight reference: R100 max sky 9.216e-8 (hmax2) / 8.744e-8 (hmax8),
|
||||||
|
mutual 2-vs-8 difference 7.063e-9 rad; R2.1 max sky 1.4772e-5 rad at both,
|
||||||
|
mutual difference 8.370e-11 rad. The larger R2.1 reference error is
|
||||||
|
tolerance/conditioning sensitive and is not cured by a smaller `max_step`.
|
||||||
|
- Max log-frequency differences ≤8.51e-10 (R100) / ≤2.10e-9 (R2.1).
|
||||||
|
- Short single-run wall times include setup/cache/output; not a timing study.
|
||||||
|
|
||||||
|
### 3. One authorised 4K pair (R100, 3840x2160, FOV45)
|
||||||
|
|
||||||
|
Raw terminal output (byte-for-byte): `results/4k_hmax2.log`,
|
||||||
|
`results/4k_hmax8.log`; provenance: `results/4k_metadata.json`,
|
||||||
|
`results/4k_attempts.json`; postprocessed: `results/4k_final_summary.json`,
|
||||||
|
`results/4k_raw_summary.log`.
|
||||||
|
|
||||||
|
| metric | `max_step`=2 | `max_step`=8 |
|
||||||
|
|---|---:|---:|
|
||||||
|
| persistent vertices / triangles | 66045 / 131338 | 66045 / 131338 |
|
||||||
|
| outcomes | 62419 ESC, 3626 DARK | 62419 ESC, 3626 DARK |
|
||||||
|
| unresolved / error | 0 | 0 |
|
||||||
|
| persistent accepted | 15,768,677 | 10,183,020 |
|
||||||
|
| persistent rejected | 97,176 | 194,781 |
|
||||||
|
| persistent RHS | 130,409,139 | 91,991,144 |
|
||||||
|
| trace+refine time (s) | 10.774 | 7.805 |
|
||||||
|
| process wall (s) | 11.3893 | 8.38925 |
|
||||||
|
|
||||||
|
- Triangle payload is bit-identical; shared film identities 66045, terminal
|
||||||
|
mismatches 0; max mutual endpoint sky difference 7.9544e-7 rad, max logg
|
||||||
|
difference 3.4711e-11.
|
||||||
|
- Persistent-vertex RHS reduction −29.46%; accepted −35.42%; wall −26.34%.
|
||||||
|
- **Cost scope:** the v3 map stores final persistent vertices only. The
|
||||||
|
requested-sample count including discarded refinement probes is 116308
|
||||||
|
(> 66045), so discarded probes contribute no stored cost and these sums must
|
||||||
|
not be read as full-render executed RHS totals.
|
||||||
|
- **Timing:** one sequential pair only; no statistical timing confidence.
|
||||||
|
- PSF splat cached/direct = 0 and `--psf-min-y` discarded 1965 (hmax2) / 1954
|
||||||
|
(hmax8) events; this does not measure image error. The PNGs are dark
|
||||||
|
diagnostic backgrounds; no 2MASS catalog was used.
|
||||||
|
|
||||||
|
### 4. Critical-classification reference check
|
||||||
|
|
||||||
|
Full output: `results/critical_ref.log`, `results/critical_ref.csv` (36
|
||||||
|
endpoint traces). The exact `theta_crit` direction is a classification
|
||||||
|
separatrix; it is reported, never asserted.
|
||||||
|
|
||||||
|
- r2.1 `theta_crit`: ref tol1e-12/h0.25 vs tol1e-13/h0.125 sky difference
|
||||||
|
**2.33638 rad** — the exactly-critical escape direction is not
|
||||||
|
independently converged. `EXACT_CRITICAL_REFERENCE_NOT_CONVERGED`.
|
||||||
|
- r30 `theta_crit` (DARK) stop-time difference 13.056; r100 `theta_crit` (DARK)
|
||||||
|
12.700. At tol1e-11, h2-vs-h8 at r2.1 `theta_crit` is 5.09e-5 rad.
|
||||||
|
- Neighbours `±1e-7`: both reference tiers agree (same outcome/reason/end,
|
||||||
|
clean, positive steps) at every neighbour. Escaped-neighbour sky differences
|
||||||
|
between the layers are ~1e-7 rad (9.47e-8 r30, 2.74e-8 r100, 1.42e-7 r2.1),
|
||||||
|
consistent with the loose 1e-4 magnitude trend; DARK neighbours report
|
||||||
|
stop-time differences 1.5e-7 … 7.5e-7.
|
||||||
|
- `CRITICAL_REFERENCE_CHECK status=0` (no neighbour reference disagreement or
|
||||||
|
error endpoint).
|
||||||
|
|
||||||
|
## Decision summary
|
||||||
|
|
||||||
|
- **Schwarzschild `max_step = 8`**: supported by the far-field cost plateau
|
||||||
|
(2→8 saves ~23–30% persistent RHS; 8→32 only ~3%) together with the tight
|
||||||
|
reference and 4K 2-vs-8 comparisons. This is not claimed as globally optimal
|
||||||
|
and gives no guarantee for arbitrary near-critical/shadow directions.
|
||||||
|
- **`min_step = 1e-12`**: retained as a non-binding numerical guard; not a
|
||||||
|
measured optimum.
|
||||||
|
- **Minkowski `max_step = 16`** and **Alcubierre `max_step = 8 × initial`**:
|
||||||
|
retained as conservative caps. Their bounded accuracy checks support keeping
|
||||||
|
these values, not claiming cost optimality; larger Alcubierre caps still
|
||||||
|
reduce RHS, but have larger frequency errors in some cases.
|
||||||
|
- The R2.1 exactly-critical difference is tolerance-sensitive;
|
||||||
|
`critical_ref_check.c` confirms the exact direction is not
|
||||||
|
independently converged and the report does not treat it as certified.
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- Analytic backends only; no time-dependent numerical-relativity metric was
|
||||||
|
exercised. Bounds and the `unit = 1` calibration are not transferable to NR.
|
||||||
|
- Experiment B samples `T = min(20, reference span)`; no full-trajectory
|
||||||
|
minimum-step claim is made.
|
||||||
|
- The 4K numbers are one sequential pair; no timing-stability confidence and
|
||||||
|
no image-error bound (inverse-lens-map Jacobian amplification is separate).
|
||||||
|
- Sky-angle differences divided by pixel angle are not inverse-lens-map image
|
||||||
|
error bounds.
|
||||||
|
- `failure_floor.c` reuses the regression invalid-metric temporal-domain
|
||||||
|
fixture; it is not a physical shadow or floor calibration.
|
||||||
|
|
||||||
|
## Verification of the selected defaults and reproduction tools
|
||||||
|
|
||||||
|
`make -B -j4 BUILD_TYPE=Debug test` passed after selecting the Schwarzschild
|
||||||
|
cap of 8 and adding CLI provenance assertions for the default bounds. Full
|
||||||
|
terminal output is retained locally at
|
||||||
|
`local/step_bounds_mesh/final_debug_tests.log` (`STEP_BOUNDS_FULL_DEBUG_EXIT=0`).
|
||||||
|
The explicit-RK4 HDR reference tests remain bit-identical. The Release
|
||||||
|
Schwarzschild binary was rebuilt with the selected default.
|
||||||
|
|
||||||
|
The self-contained limited driver was also executed with the relative output
|
||||||
|
path `local/step_bounds_reproduction`: 1500 endpoint traces and 2427 observed
|
||||||
|
finite-window steps completed, including summary generation. Small angular
|
||||||
|
differences use `atan2(|cross|,dot)` rather than rounded `acos(dot)`. Running the
|
||||||
|
4K driver without fresh explicit authorization refuses with exit code 2;
|
||||||
|
this check launches no renderer. No further 4K attempt was made.
|
||||||
@@ -0,0 +1,867 @@
|
|||||||
|
/*
|
||||||
|
* Experiment A: DP54 step-bound scan through the *public* production
|
||||||
|
* endpoint geodesic_trace_past().
|
||||||
|
*
|
||||||
|
* Sub-commands:
|
||||||
|
* schwarzschild : r30/r100 static inward, r2.1 static outward, r1.5 free-fall
|
||||||
|
* minkowski : moving observer, escape sphere 64, analytic flat check
|
||||||
|
* alcubierre : comoving bubble-center camera, vs .3/.9, sigma 1/10/100
|
||||||
|
*
|
||||||
|
* Each sub-command computes one DP54 tol=1e-12 reference per ray, then scans
|
||||||
|
* - upper scan : max_step over a list, min_step fixed
|
||||||
|
* - min scan : min_step over a list, max_step fixed
|
||||||
|
* and compares every result against the reference (class, sky angle, g,
|
||||||
|
* dark threshold margin / stop time, cost). Raw per-ray CSV and stdout
|
||||||
|
* summaries are produced. No production source is modified.
|
||||||
|
*
|
||||||
|
* Link line (do NOT link geodesic.c twice; the backends are textually included
|
||||||
|
* below, so only the common sources are linked):
|
||||||
|
* cc -std=c11 -O2 -Isrc a_public_endpoints.c geodesic.c asymptotic.c \
|
||||||
|
* asymptotic_schwarzschild.c spacetime_common.c observer.c -lm
|
||||||
|
*/
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* Textually include all three analytic backends with renamed default
|
||||||
|
* constructors so one binary can exercise every provider (the files each
|
||||||
|
* define spacetime_create_default, which would collide at link time). */
|
||||||
|
#define spacetime_create_default spacetime_create_default_minkowski_local
|
||||||
|
#include "../../src/spacetime_minkowski.c"
|
||||||
|
#undef spacetime_create_default
|
||||||
|
#define spacetime_create_default spacetime_create_default_schwarzschild_local
|
||||||
|
#include "../../src/spacetime_schwarzschild.c"
|
||||||
|
#undef spacetime_create_default
|
||||||
|
#define spacetime_create_default spacetime_create_default_alcubierre_local
|
||||||
|
#include "../../src/spacetime_alcubierre.c"
|
||||||
|
#undef spacetime_create_default
|
||||||
|
|
||||||
|
#include "geodesic.h"
|
||||||
|
#include "observer.h"
|
||||||
|
#include "spacetime.h"
|
||||||
|
|
||||||
|
#define PI 3.14159265358979323846
|
||||||
|
#define MAX_CASES 16
|
||||||
|
#define MAX_DIRS 16
|
||||||
|
#define RAY_CAP 2500
|
||||||
|
|
||||||
|
static long g_rays = 0;
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Small helpers */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static double dot3(const double a[3], const double b[3]) {
|
||||||
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static double ang_delta(const double a[3], const double b[3]) {
|
||||||
|
const double na = sqrt(dot3(a, a)), nb = sqrt(dot3(b, b));
|
||||||
|
if (!(na > 0.0) || !(nb > 0.0))
|
||||||
|
return NAN;
|
||||||
|
const double ca = dot3(a, b) / (na * nb);
|
||||||
|
const double cross[3] = {a[1] * b[2] - a[2] * b[1],
|
||||||
|
a[2] * b[0] - a[0] * b[2],
|
||||||
|
a[0] * b[1] - a[1] * b[0]};
|
||||||
|
const double sn = sqrt(dot3(cross, cross)) / (na * nb);
|
||||||
|
return atan2(sn, ca);
|
||||||
|
}
|
||||||
|
|
||||||
|
static double now_s(void) {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (double)ts.tv_sec + 1e-9 * (double)ts.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_dark(int outcome) { return outcome == RAY_OUTCOME_DARK; }
|
||||||
|
static int is_escaped(int outcome) { return outcome == RAY_OUTCOME_ESCAPED; }
|
||||||
|
|
||||||
|
/* Critical local angle (static observer, M=1) for the Schwarzschild monopole.
|
||||||
|
* theta_c = asin(3 sqrt(3) sqrt(1-2/r) / r). */
|
||||||
|
static double critical_angle(double r) {
|
||||||
|
const double b = 3.0 * sqrt(3.0) * sqrt(1.0 - 2.0 / r) / r;
|
||||||
|
if (!(b < 1.0))
|
||||||
|
return PI / 2.0;
|
||||||
|
return asin(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Case / result / comparison structures */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[32];
|
||||||
|
int prov; /* 0 schwarzschild, 1 minkowski, 2 alcubierre */
|
||||||
|
double mass, escape_radius;
|
||||||
|
double alc_vs, alc_radius, alc_sigma;
|
||||||
|
double look_ra_deg, look_dec_deg;
|
||||||
|
double position[3], velocity[3];
|
||||||
|
double initial_step, lookback;
|
||||||
|
unsigned int max_steps;
|
||||||
|
unsigned int ref_max_steps; /* budget for the tol=1e-12 reference only */
|
||||||
|
double max_step_for_min_scan; /* fixed upper during the min scan */
|
||||||
|
int n_dirs;
|
||||||
|
double dirs[MAX_DIRS][3];
|
||||||
|
double theta[MAX_DIRS]; /* NAN for non-angle direction sets */
|
||||||
|
} Case;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int outcome, reason, end_id;
|
||||||
|
double stop_t, g, thr;
|
||||||
|
double n[3];
|
||||||
|
unsigned int steps, rejected;
|
||||||
|
unsigned long rhs;
|
||||||
|
double wall;
|
||||||
|
} Res;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int has_ref;
|
||||||
|
int class_match;
|
||||||
|
double dn_ang, dlogg, dgrel, dstopT, dmargin;
|
||||||
|
} Cmp;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long n, class_mismatch;
|
||||||
|
double max_dn_ang, max_dlogg, max_dgrel, max_dstopT, max_dmargin;
|
||||||
|
unsigned long sum_rhs, max_rhs;
|
||||||
|
unsigned int max_rejected;
|
||||||
|
double sum_wall;
|
||||||
|
long escaped, dark, unresolved, incomplete;
|
||||||
|
} Agg;
|
||||||
|
|
||||||
|
static void agg_init(Agg *a) {
|
||||||
|
memset(a, 0, sizeof *a);
|
||||||
|
a->max_dn_ang = a->max_dlogg = a->max_dgrel = a->max_dstopT =
|
||||||
|
a->max_dmargin = -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bump(double *m, double v) {
|
||||||
|
if (!isfinite(v))
|
||||||
|
return;
|
||||||
|
if (v > *m)
|
||||||
|
*m = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void agg_add(Agg *a, const Res *r, const Cmp *c) {
|
||||||
|
++a->n;
|
||||||
|
if (c->has_ref && !c->class_match)
|
||||||
|
++a->class_mismatch;
|
||||||
|
if (c->has_ref) {
|
||||||
|
bump(&a->max_dn_ang, c->dn_ang);
|
||||||
|
bump(&a->max_dlogg, c->dlogg);
|
||||||
|
bump(&a->max_dgrel, c->dgrel);
|
||||||
|
bump(&a->max_dstopT, c->dstopT);
|
||||||
|
bump(&a->max_dmargin, c->dmargin);
|
||||||
|
}
|
||||||
|
a->sum_rhs += r->rhs;
|
||||||
|
if (r->rhs > a->max_rhs)
|
||||||
|
a->max_rhs = r->rhs;
|
||||||
|
if (r->rejected > a->max_rejected)
|
||||||
|
a->max_rejected = r->rejected;
|
||||||
|
a->sum_wall += r->wall;
|
||||||
|
if (is_dark(r->outcome))
|
||||||
|
++a->dark;
|
||||||
|
else if (is_escaped(r->outcome))
|
||||||
|
++a->escaped;
|
||||||
|
else if (r->outcome == RAY_OUTCOME_UNRESOLVED)
|
||||||
|
++a->unresolved;
|
||||||
|
else
|
||||||
|
++a->incomplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Config builders */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static GeodesicTraceConfig make_dp(double initial, double min_step,
|
||||||
|
double max_step, double tol,
|
||||||
|
unsigned int max_steps, double lookback) {
|
||||||
|
GeodesicTraceConfig c;
|
||||||
|
memset(&c, 0, sizeof c);
|
||||||
|
c.coordinate_time_step = initial;
|
||||||
|
c.max_steps = max_steps;
|
||||||
|
c.threshold.kind = THRESHOLD_LOG_ENERGY_GROWTH;
|
||||||
|
c.threshold.value = 8.0;
|
||||||
|
c.threshold.policy_version = 3;
|
||||||
|
c.stepper = GEODESIC_STEPPER_DP54;
|
||||||
|
c.atol_x = tol;
|
||||||
|
c.atol_Pi = tol;
|
||||||
|
c.atol_L = tol;
|
||||||
|
c.rtol = tol;
|
||||||
|
c.min_step = min_step;
|
||||||
|
c.max_step = max_step;
|
||||||
|
c.consecutive_rejection_limit = 32;
|
||||||
|
c.max_lookback_time = lookback;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GeodesicTraceConfig make_rk4(double step, unsigned int max_steps) {
|
||||||
|
GeodesicTraceConfig c;
|
||||||
|
memset(&c, 0, sizeof c);
|
||||||
|
c.coordinate_time_step = step;
|
||||||
|
c.max_steps = max_steps;
|
||||||
|
c.threshold.kind = THRESHOLD_LOG_ENERGY_GROWTH;
|
||||||
|
c.threshold.value = 8.0;
|
||||||
|
c.threshold.policy_version = 3;
|
||||||
|
c.stepper = GEODESIC_STEPPER_RK4;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Trace + compare */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static Res run_ray(const SpacetimeSource *source, const ObserverState *observer,
|
||||||
|
const double dir[3], const GeodesicTraceConfig *config) {
|
||||||
|
Res r;
|
||||||
|
memset(&r, 0, sizeof r);
|
||||||
|
++g_rays;
|
||||||
|
if (g_rays > RAY_CAP) {
|
||||||
|
fprintf(stderr, "FATAL: ray cap %d exceeded\n", RAY_CAP);
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
const double t0 = now_s();
|
||||||
|
const RayEndpoint e = geodesic_trace_past(source, observer, dir, config);
|
||||||
|
r.wall = now_s() - t0;
|
||||||
|
r.outcome = e.outcome;
|
||||||
|
r.reason = e.reason;
|
||||||
|
r.end_id = e.end_id;
|
||||||
|
r.stop_t = e.stop_coordinate_time;
|
||||||
|
r.g = e.frequency_ratio;
|
||||||
|
r.thr = e.threshold_value;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
r.n[i] = e.n_infinity[i];
|
||||||
|
r.steps = e.accepted_steps;
|
||||||
|
r.rejected = e.rejected_steps;
|
||||||
|
r.rhs = e.rhs_evaluations;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void compare(const Res *a, const Res *ref, Cmp *c) {
|
||||||
|
memset(c, 0, sizeof *c);
|
||||||
|
c->has_ref = 1;
|
||||||
|
c->class_match = (a->outcome == ref->outcome && a->reason == ref->reason);
|
||||||
|
if (is_escaped(a->outcome) && is_escaped(ref->outcome)) {
|
||||||
|
c->dn_ang = ang_delta(a->n, ref->n);
|
||||||
|
if (a->g > 0.0 && ref->g > 0.0 && isfinite(a->g) && isfinite(ref->g)) {
|
||||||
|
c->dlogg = fabs(log(a->g) - log(ref->g));
|
||||||
|
c->dgrel = fabs(a->g / ref->g - 1.0);
|
||||||
|
} else {
|
||||||
|
c->dlogg = c->dgrel = NAN;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c->dn_ang = c->dlogg = c->dgrel = NAN;
|
||||||
|
}
|
||||||
|
c->dstopT = (isfinite(a->stop_t) && isfinite(ref->stop_t))
|
||||||
|
? fabs(a->stop_t - ref->stop_t)
|
||||||
|
: NAN;
|
||||||
|
c->dmargin = (is_dark(a->outcome) && is_dark(ref->outcome) &&
|
||||||
|
isfinite(a->thr) && isfinite(ref->thr))
|
||||||
|
? fabs(a->thr - ref->thr)
|
||||||
|
: NAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_row(FILE *f, const char *phase, const Case *c, int di,
|
||||||
|
double upper, double min_step, double tol, const Res *r,
|
||||||
|
const Cmp *cmp) {
|
||||||
|
fprintf(f,
|
||||||
|
"%s,%s,%d,%.17g,%.6g,%.6g,%.6g,%d,%d,%u,%.17g,%u,%u,%lu,%.6g,"
|
||||||
|
"%.17g,%.17g,%.17g,%.17g,%.17g",
|
||||||
|
phase, c->name, di, c->theta[di], upper, min_step, tol, r->outcome,
|
||||||
|
r->reason, r->end_id, r->stop_t, r->steps, r->rejected, r->rhs,
|
||||||
|
r->wall, r->n[0], r->n[1], r->n[2], r->g, r->thr);
|
||||||
|
if (cmp->has_ref)
|
||||||
|
fprintf(f, ",%d,%.17g,%.17g,%.17g,%.17g,%.17g", cmp->class_match,
|
||||||
|
cmp->dn_ang, cmp->dlogg, cmp->dgrel, cmp->dstopT, cmp->dmargin);
|
||||||
|
else
|
||||||
|
fprintf(f, ",,nan,nan,nan,nan,nan");
|
||||||
|
fprintf(f, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *ROW_HEADER =
|
||||||
|
"phase,case,dir,theta,upper,min_step,tol,outcome,reason,end_id,stop_t,"
|
||||||
|
"steps,rejected,rhs,wall_s,nx,ny,nz,g,thr,class_match,dn_ang,dlogg,dgrel,"
|
||||||
|
"dstopT,dmargin\n";
|
||||||
|
|
||||||
|
static void write_agg(FILE *f, const char *phase, const Case *c, double upper,
|
||||||
|
double min_step, double tol, const Agg *a) {
|
||||||
|
fprintf(f,
|
||||||
|
"%s,%s,%.6g,%.6g,%.6g,%ld,%ld,%.6g,%.6g,%.6g,%.6g,%.6g,%lu,%lu,%u,"
|
||||||
|
"%.4f,%ld,%ld,%ld,%ld\n",
|
||||||
|
phase, c->name, upper, min_step, tol, a->n, a->class_mismatch,
|
||||||
|
a->max_dn_ang, a->max_dlogg, a->max_dgrel, a->max_dstopT,
|
||||||
|
a->max_dmargin, a->sum_rhs, a->max_rhs, a->max_rejected, a->sum_wall,
|
||||||
|
a->escaped, a->dark, a->unresolved, a->incomplete);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *AGG_HEADER =
|
||||||
|
"phase,case,upper,min_step,tol,n,class_mismatch,max_dn_ang,max_dlogg,"
|
||||||
|
"max_dgrel,max_dstopT,max_dmargin,sum_rhs,max_rhs,max_rejected,sum_wall,"
|
||||||
|
"escaped,dark,unresolved,incomplete\n";
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Case builders */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void dir_from_theta(double th, double n[3]) {
|
||||||
|
if (th == 0.0) {
|
||||||
|
n[0] = 1.0;
|
||||||
|
n[1] = n[2] = 0.0;
|
||||||
|
} else if (th == PI) {
|
||||||
|
n[0] = -1.0;
|
||||||
|
n[1] = n[2] = 0.0;
|
||||||
|
} else {
|
||||||
|
n[0] = cos(th);
|
||||||
|
n[1] = sin(th);
|
||||||
|
n[2] = 0.0;
|
||||||
|
}
|
||||||
|
const double nn = sqrt(dot3(n, n));
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
n[i] /= nn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fill_static_dirs(Case *c, double r) {
|
||||||
|
const double tc = critical_angle(r);
|
||||||
|
const double th[MAX_DIRS] = {0.0, PI, PI / 2.0, tc,
|
||||||
|
tc - 1e-3, tc + 1e-3, tc - 1e-5, tc + 1e-5,
|
||||||
|
tc - 1e-7, tc + 1e-7, tc + 0.05, tc - 0.05};
|
||||||
|
c->n_dirs = 12;
|
||||||
|
for (int i = 0; i < c->n_dirs; ++i) {
|
||||||
|
c->theta[i] = th[i];
|
||||||
|
dir_from_theta(th[i], c->dirs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void case_static(Case *c, const char *name, double r, double look_ra) {
|
||||||
|
memset(c, 0, sizeof *c);
|
||||||
|
snprintf(c->name, sizeof c->name, "%s", name);
|
||||||
|
c->prov = 0;
|
||||||
|
c->mass = 1.0;
|
||||||
|
c->escape_radius = 256.0;
|
||||||
|
c->look_ra_deg = look_ra;
|
||||||
|
c->look_dec_deg = 0.0;
|
||||||
|
c->position[0] = r;
|
||||||
|
c->position[1] = c->position[2] = 0.0;
|
||||||
|
c->velocity[0] = c->velocity[1] = c->velocity[2] = 0.0;
|
||||||
|
c->initial_step = 0.1;
|
||||||
|
c->lookback = 6553.6;
|
||||||
|
c->max_steps = 65536;
|
||||||
|
c->ref_max_steps = 65536;
|
||||||
|
c->max_step_for_min_scan = 2.0;
|
||||||
|
fill_static_dirs(c, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void case_freefall(Case *c, const char *name, double r) {
|
||||||
|
memset(c, 0, sizeof *c);
|
||||||
|
snprintf(c->name, sizeof c->name, "%s", name);
|
||||||
|
c->prov = 0;
|
||||||
|
c->mass = 1.0;
|
||||||
|
c->escape_radius = 256.0;
|
||||||
|
c->look_ra_deg = 180.0;
|
||||||
|
c->look_dec_deg = 0.0;
|
||||||
|
c->position[0] = r;
|
||||||
|
c->position[1] = c->position[2] = 0.0;
|
||||||
|
/* Free-fall from rest at infinity, coordinate velocity dx/dt (the formula
|
||||||
|
* used by local/p2d_validation/observer_endpoints.c). */
|
||||||
|
const double y = sqrt(2.0 / r);
|
||||||
|
c->velocity[0] = -y * (1.0 + y) / (1.0 + y + y * y);
|
||||||
|
c->velocity[1] = c->velocity[2] = 0.0;
|
||||||
|
c->initial_step = 0.1;
|
||||||
|
c->lookback = 6553.6;
|
||||||
|
c->max_steps = 65536;
|
||||||
|
c->ref_max_steps = 65536;
|
||||||
|
c->max_step_for_min_scan = 2.0;
|
||||||
|
{
|
||||||
|
const double th[4] = {0.0, PI / 2.0, PI, 3.0 * PI / 4.0};
|
||||||
|
c->n_dirs = 4;
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
c->theta[i] = th[i];
|
||||||
|
dir_from_theta(th[i], c->dirs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void case_minkowski(Case *c) {
|
||||||
|
memset(c, 0, sizeof *c);
|
||||||
|
snprintf(c->name, sizeof c->name, "mink_moving");
|
||||||
|
c->prov = 1;
|
||||||
|
c->escape_radius = 64.0;
|
||||||
|
c->look_ra_deg = 0.0;
|
||||||
|
c->look_dec_deg = 0.0;
|
||||||
|
c->position[0] = 10.0;
|
||||||
|
c->position[1] = 20.0;
|
||||||
|
c->position[2] = -15.0;
|
||||||
|
c->velocity[0] = 0.3;
|
||||||
|
c->velocity[1] = 0.2;
|
||||||
|
c->velocity[2] = 0.1;
|
||||||
|
c->initial_step = 1.0;
|
||||||
|
c->lookback = 2048.0;
|
||||||
|
c->max_steps = 2048;
|
||||||
|
c->ref_max_steps = 4096;
|
||||||
|
c->max_step_for_min_scan = 16.0;
|
||||||
|
{
|
||||||
|
const double d[6][3] = {{1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0},
|
||||||
|
{0.0, 1.0, 0.0}, {0.0, 0.0, 1.0},
|
||||||
|
{0.6, 0.8, 0.0}, {-0.6, 0.8, 0.0}};
|
||||||
|
c->n_dirs = 6;
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
c->theta[i] = NAN;
|
||||||
|
for (int k = 0; k < 3; ++k)
|
||||||
|
c->dirs[i][k] = d[i][k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void case_alcubierre(Case *c, const char *name, double vs, double sigma) {
|
||||||
|
memset(c, 0, sizeof *c);
|
||||||
|
snprintf(c->name, sizeof c->name, "%s", name);
|
||||||
|
c->prov = 2;
|
||||||
|
c->alc_vs = vs;
|
||||||
|
c->alc_radius = 1.0;
|
||||||
|
c->alc_sigma = sigma;
|
||||||
|
c->look_ra_deg = 0.0;
|
||||||
|
c->look_dec_deg = 0.0;
|
||||||
|
c->position[0] = c->position[1] = c->position[2] = 0.0;
|
||||||
|
c->velocity[0] = vs; /* comoving with the bubble center */
|
||||||
|
c->velocity[1] = c->velocity[2] = 0.0;
|
||||||
|
c->initial_step = fmin(0.1, 0.05 / sigma);
|
||||||
|
c->max_steps = 100000;
|
||||||
|
c->ref_max_steps = 200000;
|
||||||
|
{
|
||||||
|
const double esc = spacetime_alcubierre_escape_radius(1.0, sigma);
|
||||||
|
c->lookback = 1.25 * 4.0 * esc / (1.0 - fabs(vs));
|
||||||
|
}
|
||||||
|
c->max_step_for_min_scan = c->initial_step * 8.0;
|
||||||
|
{
|
||||||
|
const double d[6][3] = {{1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0},
|
||||||
|
{0.0, 1.0, 0.0}, {0.0, 0.0, 1.0},
|
||||||
|
{0.6, 0.8, 0.0}, {-0.6, 0.8, 0.0}};
|
||||||
|
c->n_dirs = 6;
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
c->theta[i] = NAN;
|
||||||
|
for (int k = 0; k < 3; ++k)
|
||||||
|
c->dirs[i][k] = d[i][k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Source/observer construction */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static int build_source(const Case *c, SpacetimeSource *s) {
|
||||||
|
if (c->prov == 0)
|
||||||
|
return spacetime_create_schwarzschild_ks(s, c->mass, c->escape_radius);
|
||||||
|
if (c->prov == 1)
|
||||||
|
return spacetime_create_minkowski(s, c->escape_radius);
|
||||||
|
return spacetime_create_alcubierre(s, c->alc_vs, c->alc_radius,
|
||||||
|
c->alc_sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int build_observer(const Case *c, const SpacetimeSource *s,
|
||||||
|
ObserverState *o) {
|
||||||
|
MetricData m;
|
||||||
|
if (spacetime_eval(s, 0.0, c->position, &m) != SPACETIME_POINT_OK)
|
||||||
|
return -1;
|
||||||
|
ObserverCamera cam;
|
||||||
|
memset(&cam, 0, sizeof cam);
|
||||||
|
cam.coordinate_time = 0.0;
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
cam.position[i] = c->position[i];
|
||||||
|
cam.velocity[i] = c->velocity[i];
|
||||||
|
}
|
||||||
|
cam.look_ra_deg = c->look_ra_deg;
|
||||||
|
cam.look_dec_deg = c->look_dec_deg;
|
||||||
|
cam.roll_deg = 0.0;
|
||||||
|
return observer_from_coordinate_camera(&m, &cam, o, NULL) ==
|
||||||
|
OBSERVER_BUILD_OK
|
||||||
|
? 0
|
||||||
|
: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Generic scan driver */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void run_grid(const Case *cases, int ncases, const double *uppers,
|
||||||
|
int n_up, const double *floors, int n_fl, double tol,
|
||||||
|
const char *phase, const char *rows_path,
|
||||||
|
const char *agg_path, Res refs[][MAX_DIRS]) {
|
||||||
|
FILE *rf = fopen(rows_path, "w");
|
||||||
|
FILE *af = fopen(agg_path, "w");
|
||||||
|
if (!rf || !af) {
|
||||||
|
fprintf(stderr, "FATAL: cannot open %s / %s\n", rows_path, agg_path);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
fprintf(rf, "%s", ROW_HEADER);
|
||||||
|
fprintf(af, "%s", AGG_HEADER);
|
||||||
|
for (int ci = 0; ci < ncases; ++ci) {
|
||||||
|
const Case *c = &cases[ci];
|
||||||
|
SpacetimeSource source;
|
||||||
|
ObserverState observer;
|
||||||
|
if (build_source(c, &source) || build_observer(c, &source, &observer)) {
|
||||||
|
fprintf(stderr, "FATAL: cannot build case %s\n", c->name);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
for (int ui = 0; ui < n_up; ++ui) {
|
||||||
|
for (int fi = 0; fi < n_fl; ++fi) {
|
||||||
|
Agg agg;
|
||||||
|
agg_init(&agg);
|
||||||
|
for (int di = 0; di < c->n_dirs; ++di) {
|
||||||
|
const GeodesicTraceConfig cfg =
|
||||||
|
make_dp(c->initial_step, floors[fi], uppers[ui], tol, c->max_steps,
|
||||||
|
c->lookback);
|
||||||
|
const Res r = run_ray(&source, &observer, c->dirs[di], &cfg);
|
||||||
|
Cmp cmp;
|
||||||
|
compare(&r, &refs[ci][di], &cmp);
|
||||||
|
write_row(rf, phase, c, di, uppers[ui], floors[fi], tol, &r, &cmp);
|
||||||
|
agg_add(&agg, &r, &cmp);
|
||||||
|
}
|
||||||
|
write_agg(af, phase, c, uppers[ui], floors[fi], tol, &agg);
|
||||||
|
printf("SUMMARY %s %s upper=%.6g min=%.6g n=%ld mismatch=%ld "
|
||||||
|
"max_dn_ang=%.6g max_dgrel=%.6g max_dstopT=%.6g sum_rhs=%lu "
|
||||||
|
"esc=%ld dark=%ld unres=%ld inc=%ld wall=%.3fs\n",
|
||||||
|
phase, c->name, uppers[ui], floors[fi], agg.n,
|
||||||
|
agg.class_mismatch, agg.max_dn_ang, agg.max_dgrel,
|
||||||
|
agg.max_dstopT, agg.sum_rhs, agg.escaped, agg.dark,
|
||||||
|
agg.unresolved, agg.incomplete, agg.sum_wall);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spacetime_destroy(&source);
|
||||||
|
}
|
||||||
|
fclose(rf);
|
||||||
|
fclose(af);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute DP tol=1e-12 reference for every direction of every case.
|
||||||
|
* upper_ref <= 0 means "use the case's own initial step" as the max_step. */
|
||||||
|
static void compute_refs(const Case *cases, int ncases, double upper_ref,
|
||||||
|
const char *path, Res refs[][MAX_DIRS]) {
|
||||||
|
FILE *f = fopen(path, "w");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "FATAL: cannot open %s\n", path);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
fprintf(f, "%s", ROW_HEADER);
|
||||||
|
for (int ci = 0; ci < ncases; ++ci) {
|
||||||
|
const Case *c = &cases[ci];
|
||||||
|
SpacetimeSource source;
|
||||||
|
ObserverState observer;
|
||||||
|
if (build_source(c, &source) || build_observer(c, &source, &observer)) {
|
||||||
|
fprintf(stderr, "FATAL: cannot build case %s\n", c->name);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
const double upper = (upper_ref > 0.0) ? upper_ref : c->initial_step;
|
||||||
|
for (int di = 0; di < c->n_dirs; ++di) {
|
||||||
|
const GeodesicTraceConfig cfg = make_dp(c->initial_step, 1e-12, upper,
|
||||||
|
1e-12, c->ref_max_steps,
|
||||||
|
c->lookback);
|
||||||
|
refs[ci][di] = run_ray(&source, &observer, c->dirs[di], &cfg);
|
||||||
|
Cmp none;
|
||||||
|
memset(&none, 0, sizeof none);
|
||||||
|
write_row(f, "ref", c, di, upper, 1e-12, 1e-12, &refs[ci][di], &none);
|
||||||
|
printf("REF %s dir=%d theta=%.6g outcome=%d reason=%d stop_t=%.9g "
|
||||||
|
"steps=%u rejected=%u rhs=%lu g=%.12g thr=%.12g\n",
|
||||||
|
c->name, di, c->theta[di], refs[ci][di].outcome,
|
||||||
|
refs[ci][di].reason, refs[ci][di].stop_t, refs[ci][di].steps,
|
||||||
|
refs[ci][di].rejected, refs[ci][di].rhs, refs[ci][di].g,
|
||||||
|
refs[ci][di].thr);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
spacetime_destroy(&source);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Sub-command: Schwarzschild */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void cmd_schwarzschild(void) {
|
||||||
|
static Case cases[MAX_CASES];
|
||||||
|
static Res refs[MAX_CASES][MAX_DIRS];
|
||||||
|
memset(refs, 0, sizeof refs);
|
||||||
|
int nc = 0;
|
||||||
|
case_static(&cases[nc++], "r30_inward", 30.0, 180.0);
|
||||||
|
case_static(&cases[nc++], "r100_inward", 100.0, 180.0);
|
||||||
|
case_static(&cases[nc++], "r2p1_outward", 2.1, 0.0);
|
||||||
|
case_freefall(&cases[nc++], "r1p5_freefall", 1.5);
|
||||||
|
|
||||||
|
compute_refs(cases, nc, 0.25, "raw/a_sch_reference.csv", refs);
|
||||||
|
|
||||||
|
static const double uppers[9] = {0.25, 0.5, 1.0, 2.0, 4.0,
|
||||||
|
8.0, 16.0, 32.0, 64.0};
|
||||||
|
static const double floors[10] = {1e-1, 1e-2, 1e-3, 1e-4, 1e-5,
|
||||||
|
1e-6, 1e-8, 1e-10, 1e-12, 1e-14};
|
||||||
|
run_grid(cases, nc, uppers, 9, (double[]){1e-12}, 1, 1e-9, "upper",
|
||||||
|
"raw/a_sch_upper.csv", "raw/a_sch_upper_summary.csv", refs);
|
||||||
|
run_grid(cases, nc, (double[]){2.0}, 1, floors, 10, 1e-9, "min",
|
||||||
|
"raw/a_sch_min.csv", "raw/a_sch_min_summary.csv", refs);
|
||||||
|
|
||||||
|
/* Sensitive-ray RK4 h-halving reference (extra independent check).
|
||||||
|
* (case index, dir index): r30 and r2.1, theta_c +- 1e-5 / +- 1e-7. */
|
||||||
|
const int sens[8][2] = {{0, 8}, {0, 9}, {0, 6}, {0, 7},
|
||||||
|
{2, 8}, {2, 9}, {2, 6}, {2, 7}};
|
||||||
|
FILE *f = fopen("raw/a_sch_rk4_sensitive.csv", "w");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "FATAL: cannot open rk4 csv\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
fprintf(f, "%s", ROW_HEADER);
|
||||||
|
for (int k = 0; k < 8; ++k) {
|
||||||
|
const Case *c = &cases[sens[k][0]];
|
||||||
|
const int di = sens[k][1];
|
||||||
|
SpacetimeSource source;
|
||||||
|
ObserverState observer;
|
||||||
|
if (build_source(c, &source) || build_observer(c, &source, &observer)) {
|
||||||
|
fprintf(stderr, "FATAL: cannot build case %s\n", c->name);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
GeodesicTraceConfig rk01 = make_rk4(0.01, 262144);
|
||||||
|
GeodesicTraceConfig rk005 = make_rk4(0.005, 262144);
|
||||||
|
Res r01 = run_ray(&source, &observer, c->dirs[di], &rk01);
|
||||||
|
Res r005 = run_ray(&source, &observer, c->dirs[di], &rk005);
|
||||||
|
Cmp hh, vsdp;
|
||||||
|
compare(&r005, &r01, &hh);
|
||||||
|
compare(&r005, &refs[sens[k][0]][di], &vsdp);
|
||||||
|
Cmp none;
|
||||||
|
memset(&none, 0, sizeof none);
|
||||||
|
write_row(f, "rk4_0.01", c, di, 0.01, 0.0, 0.0, &r01, &none);
|
||||||
|
write_row(f, "rk4_0.005", c, di, 0.005, 0.0, 0.0, &r005, &none);
|
||||||
|
printf("RK4 %s dir=%d theta=%.6g o01=%d/%d o005=%d/%d "
|
||||||
|
"hhalve_dn=%.6g hhalve_dgrel=%.6g vsdp_dn=%.6g vsdp_dgrel=%.6g "
|
||||||
|
"vsdp_class=%d\n",
|
||||||
|
c->name, di, c->theta[di], r01.outcome, r01.reason, r005.outcome,
|
||||||
|
r005.reason, hh.dn_ang, hh.dgrel, vsdp.dn_ang, vsdp.dgrel,
|
||||||
|
vsdp.class_match);
|
||||||
|
spacetime_destroy(&source);
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Sub-command: Minkowski (analytic flat verification) */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
/* Analytic flat past escape from an observer at (t0,x0) with tetrad-frame
|
||||||
|
* direction n: coordinate photon velocity u = k_vec/k^0, crossing radius R at
|
||||||
|
* s = t-t0 < 0, sky direction n_inf = -u, frequency ratio g = 1/k^0. */
|
||||||
|
static int mink_analytic(const Case *c, const ObserverState *o,
|
||||||
|
const double n[3], double R, double *t_cross,
|
||||||
|
double *xc, double *ninf, double *g) {
|
||||||
|
double k[4];
|
||||||
|
for (int mu = 0; mu < 4; ++mu)
|
||||||
|
k[mu] = o->tetrad[0][mu];
|
||||||
|
for (int a = 0; a < 3; ++a)
|
||||||
|
for (int mu = 0; mu < 4; ++mu)
|
||||||
|
k[mu] -= n[a] * o->tetrad[a + 1][mu];
|
||||||
|
if (!(k[0] > 0.0))
|
||||||
|
return -1;
|
||||||
|
double u[3];
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
u[i] = k[i + 1] / k[0];
|
||||||
|
const double uu = dot3(u, u);
|
||||||
|
const double B = 2.0 * dot3(c->position, u);
|
||||||
|
const double C = dot3(c->position, c->position) - R * R;
|
||||||
|
const double disc = B * B - 4.0 * uu * C;
|
||||||
|
if (disc < 0.0)
|
||||||
|
return -1;
|
||||||
|
const double sq = sqrt(disc);
|
||||||
|
const double s1 = (-B + sq) / (2.0 * uu);
|
||||||
|
const double s2 = (-B - sq) / (2.0 * uu);
|
||||||
|
const double s = (s1 < 0.0) ? fmin(s1, s2) : s2;
|
||||||
|
if (!(s < 0.0))
|
||||||
|
return -1;
|
||||||
|
*t_cross = o->coordinate_time + s;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
xc[i] = c->position[i] + u[i] * s;
|
||||||
|
const double nu = sqrt(uu);
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
ninf[i] = -u[i] / nu;
|
||||||
|
*g = 1.0 / k[0];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_minkowski(void) {
|
||||||
|
Case c;
|
||||||
|
case_minkowski(&c);
|
||||||
|
static Res refs[MAX_CASES][MAX_DIRS];
|
||||||
|
memset(refs, 0, sizeof refs);
|
||||||
|
SpacetimeSource source;
|
||||||
|
ObserverState observer;
|
||||||
|
if (build_source(&c, &source) || build_observer(&c, &source, &observer)) {
|
||||||
|
fprintf(stderr, "FATAL: cannot build minkowski case\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *mf = fopen("raw/a_mink_analytic.csv", "w");
|
||||||
|
if (!mf) {
|
||||||
|
fprintf(stderr, "FATAL: cannot open analytic csv\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
fprintf(mf,
|
||||||
|
"case,dir,upper,min_step,tol,outcome,stop_t,x_err,t_err,dn_ang,"
|
||||||
|
"dgrel,g_analytic,stop_t_analytic\n");
|
||||||
|
|
||||||
|
/* Reference: tol=1e-12, max_step = initial (1.0). */
|
||||||
|
const GeodesicTraceConfig refcfg =
|
||||||
|
make_dp(c.initial_step, 1e-12, c.initial_step, 1e-12, c.max_steps,
|
||||||
|
c.lookback);
|
||||||
|
for (int di = 0; di < c.n_dirs; ++di)
|
||||||
|
refs[0][di] = run_ray(&source, &observer, c.dirs[di], &refcfg);
|
||||||
|
|
||||||
|
static const double uppers[5] = {1.0, 4.0, 16.0, 64.0, 256.0};
|
||||||
|
static const double floors[3] = {1e-1, 1e-6, 1e-12};
|
||||||
|
for (int ui = 0; ui < 5; ++ui) {
|
||||||
|
for (int fi = 0; fi < 3; ++fi) {
|
||||||
|
Agg agg;
|
||||||
|
agg_init(&agg);
|
||||||
|
for (int di = 0; di < c.n_dirs; ++di) {
|
||||||
|
const GeodesicTraceConfig cfg =
|
||||||
|
make_dp(c.initial_step, floors[fi], uppers[ui], 1e-9, c.max_steps,
|
||||||
|
c.lookback);
|
||||||
|
const Res r = run_ray(&source, &observer, c.dirs[di], &cfg);
|
||||||
|
Cmp cmp;
|
||||||
|
compare(&r, &refs[0][di], &cmp);
|
||||||
|
agg_add(&agg, &r, &cmp);
|
||||||
|
double t_an, x_an[3], n_an[3], g_an;
|
||||||
|
const int ok = mink_analytic(&c, &observer, c.dirs[di], c.escape_radius,
|
||||||
|
&t_an, x_an, n_an, &g_an);
|
||||||
|
double x_err = NAN, t_err = NAN, dn_an = NAN, dg_an = NAN;
|
||||||
|
if (ok == 0 && is_escaped(r.outcome)) {
|
||||||
|
/* Crossing position is checked through the direct trace in
|
||||||
|
* a_mink_analytic_x.csv; here compare sky direction, g and time. */
|
||||||
|
t_err = fabs(r.stop_t - t_an);
|
||||||
|
dn_an = ang_delta(r.n, n_an);
|
||||||
|
if (r.g > 0.0 && g_an > 0.0)
|
||||||
|
dg_an = fabs(r.g / g_an - 1.0);
|
||||||
|
}
|
||||||
|
fprintf(mf,
|
||||||
|
"%s,%d,%.6g,%.6g,%.6g,%d,%.17g,%.17g,%.17g,%.17g,%.17g,%.17g,"
|
||||||
|
"%.17g\n",
|
||||||
|
c.name, di, uppers[ui], floors[fi], 1e-9, r.outcome, r.stop_t,
|
||||||
|
x_err, t_err, dn_an, dg_an, g_an, t_an);
|
||||||
|
}
|
||||||
|
printf("SUMMARY mink upper=%.6g min=%.6g n=%ld mismatch=%ld "
|
||||||
|
"max_dn_ang=%.6g max_dgrel=%.6g sum_rhs=%lu esc=%ld dark=%ld "
|
||||||
|
"unres=%ld inc=%ld\n",
|
||||||
|
uppers[ui], floors[fi], agg.n, agg.class_mismatch,
|
||||||
|
agg.max_dn_ang, agg.max_dgrel, agg.sum_rhs, agg.escaped, agg.dark,
|
||||||
|
agg.unresolved, agg.incomplete);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Direct endpoint check for the crossing position (x) on a few configs. */
|
||||||
|
FILE *xf = fopen("raw/a_mink_analytic_x.csv", "w");
|
||||||
|
if (!xf) {
|
||||||
|
fprintf(stderr, "FATAL: cannot open analytic x csv\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
fprintf(xf, "case,dir,upper,min_step,tol,outcome,x_err_x,x_err_y,x_err_z,"
|
||||||
|
"t_err\n");
|
||||||
|
for (int ui = 0; ui < 5; ++ui) {
|
||||||
|
for (int fi = 0; fi < 3; ++fi) {
|
||||||
|
for (int di = 0; di < c.n_dirs; ++di) {
|
||||||
|
const GeodesicTraceConfig cfg =
|
||||||
|
make_dp(c.initial_step, floors[fi], uppers[ui], 1e-9, c.max_steps,
|
||||||
|
c.lookback);
|
||||||
|
const RayEndpoint e =
|
||||||
|
geodesic_trace_past(&source, &observer, c.dirs[di], &cfg);
|
||||||
|
++g_rays;
|
||||||
|
double t_an, x_an[3], n_an[3], g_an;
|
||||||
|
const int ok = mink_analytic(&c, &observer, c.dirs[di], c.escape_radius,
|
||||||
|
&t_an, x_an, n_an, &g_an);
|
||||||
|
double ex = NAN, ey = NAN, ez = NAN, te = NAN;
|
||||||
|
if (ok == 0 && e.outcome == RAY_OUTCOME_ESCAPED) {
|
||||||
|
ex = fabs(e.final_x[0] - x_an[0]);
|
||||||
|
ey = fabs(e.final_x[1] - x_an[1]);
|
||||||
|
ez = fabs(e.final_x[2] - x_an[2]);
|
||||||
|
te = fabs(e.stop_coordinate_time - t_an);
|
||||||
|
}
|
||||||
|
fprintf(xf, "%s,%d,%.6g,%.6g,%.6g,%d,%.17g,%.17g,%.17g,%.17g\n",
|
||||||
|
c.name, di, uppers[ui], floors[fi], 1e-9, e.outcome, ex, ey, ez,
|
||||||
|
te);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(xf);
|
||||||
|
fclose(mf);
|
||||||
|
spacetime_destroy(&source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
/* Sub-command: Alcubierre */
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void cmd_alcubierre(void) {
|
||||||
|
static Case cases[MAX_CASES];
|
||||||
|
static Res refs[MAX_CASES][MAX_DIRS];
|
||||||
|
memset(refs, 0, sizeof refs);
|
||||||
|
int nc = 0;
|
||||||
|
case_alcubierre(&cases[nc++], "alc_v3_s1", 0.3, 1.0);
|
||||||
|
case_alcubierre(&cases[nc++], "alc_v3_s10", 0.3, 10.0);
|
||||||
|
case_alcubierre(&cases[nc++], "alc_v9_s1", 0.9, 1.0);
|
||||||
|
case_alcubierre(&cases[nc++], "alc_v9_s10", 0.9, 10.0);
|
||||||
|
case_alcubierre(&cases[nc++], "alc_v9_s100", 0.9, 100.0);
|
||||||
|
|
||||||
|
compute_refs(cases, nc, -1.0, "raw/a_alc_reference.csv", refs);
|
||||||
|
|
||||||
|
/* Standard grid: upper = initial*{1,4,8,16,32,64}, floor {1e-4,1e-8,1e-12}. */
|
||||||
|
{
|
||||||
|
static const double floors[3] = {1e-4, 1e-8, 1e-12};
|
||||||
|
Case sub[4];
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
sub[i] = cases[i];
|
||||||
|
/* run_grid uses one upper array for all cases, so use per-case initial by
|
||||||
|
* calling run_grid four times. */
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
char rp[128], ap[128];
|
||||||
|
snprintf(rp, sizeof rp, "raw/a_alc_%.31s_upper.csv", sub[i].name);
|
||||||
|
snprintf(ap, sizeof ap, "raw/a_alc_%.31s_upper_summary.csv", sub[i].name);
|
||||||
|
const double base = sub[i].initial_step;
|
||||||
|
const double up[6] = {base, 4 * base, 8 * base,
|
||||||
|
16 * base, 32 * base, 64 * base};
|
||||||
|
run_grid(&sub[i], 1, up, 6, floors, 3, 1e-9, "upper", rp, ap, &refs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Focused lower-bound stress: vs=.9, sigma=100, upper = initial*8 = 0.004,
|
||||||
|
* floors {1e-4,1e-5,1e-6,1e-8,1e-12,1e-14}. */
|
||||||
|
{
|
||||||
|
const Case *c = &cases[4];
|
||||||
|
const double up[1] = {c->initial_step * 8.0};
|
||||||
|
const double floors[6] = {1e-4, 1e-5, 1e-6, 1e-8, 1e-12, 1e-14};
|
||||||
|
run_grid(c, 1, up, 1, floors, 6, 1e-9, "min_stress",
|
||||||
|
"raw/a_alc_v9_s100_min.csv", "raw/a_alc_v9_s100_min_summary.csv",
|
||||||
|
&refs[4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage: %s schwarzschild|minkowski|alcubierre\n",
|
||||||
|
argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!strcmp(argv[1], "schwarzschild"))
|
||||||
|
cmd_schwarzschild();
|
||||||
|
else if (!strcmp(argv[1], "minkowski"))
|
||||||
|
cmd_minkowski();
|
||||||
|
else if (!strcmp(argv[1], "alcubierre"))
|
||||||
|
cmd_alcubierre();
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "unknown sub-command %s\n", argv[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
printf("TOTAL_RAYS %ld\n", g_rays);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,404 @@
|
|||||||
|
/*
|
||||||
|
* Experiment B: observed accepted-step sizes of the production DP54 core.
|
||||||
|
*
|
||||||
|
* This translation unit textually includes src/geodesic.c so the real,
|
||||||
|
* production `dp_advance_one` driver and the real `State` (GeodesicRayState)
|
||||||
|
* are exercised directly on a finite trajectory interval. The production
|
||||||
|
* initialization is reproduced exactly as `geodesic_trace_past` does for an
|
||||||
|
* INSIDE route: `geodesic_initialize_past_ray_metric` at the camera event,
|
||||||
|
* then `next_step = config->coordinate_time_step` (the init already sets
|
||||||
|
* `integration_start_time`, `log_alpha_p0` and `log_alpha_p0_0`). This is the
|
||||||
|
* same initialization the public endpoint uses, not a re-implementation.
|
||||||
|
*
|
||||||
|
* For each selected ray we:
|
||||||
|
* 1. run the public endpoint with tol=1e-12 to get a trusted reference
|
||||||
|
* stop time and terminal class (physical terminal class is owned by A);
|
||||||
|
* 2. integrate the same ray with the production DP core up to
|
||||||
|
* T = min(20, ref_span) observed steps <= 2000, recording each accepted
|
||||||
|
* step magnitude, boundary-limit flag, rejection/RHS deltas and the null
|
||||||
|
* residual gamma^{ij} Pi_i Pi_j - 1.
|
||||||
|
*
|
||||||
|
* Link line (geodesic.c is textually included, so it is NOT linked; the
|
||||||
|
* analytic backends are also textually included here):
|
||||||
|
* cc -std=c11 -O2 -Isrc b_actual_h.c asymptotic.c asymptotic_schwarzschild.c \
|
||||||
|
* spacetime_common.c observer.c -lm
|
||||||
|
*/
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define spacetime_create_default spacetime_create_default_minkowski_b
|
||||||
|
#include "../../src/spacetime_minkowski.c"
|
||||||
|
#undef spacetime_create_default
|
||||||
|
#define spacetime_create_default spacetime_create_default_schwarzschild_b
|
||||||
|
#include "../../src/spacetime_schwarzschild.c"
|
||||||
|
#undef spacetime_create_default
|
||||||
|
#define spacetime_create_default spacetime_create_default_alcubierre_b
|
||||||
|
#include "../../src/spacetime_alcubierre.c"
|
||||||
|
#undef spacetime_create_default
|
||||||
|
|
||||||
|
/* The production geodesic core, textually included. Its static State,
|
||||||
|
* dp_advance_one and invert become visible to the code below. */
|
||||||
|
#include "../../src/geodesic.c"
|
||||||
|
|
||||||
|
#define PI 3.14159265358979323846
|
||||||
|
#define MAX_BCASES 12
|
||||||
|
#define MAX_BDIRS 8
|
||||||
|
#define MAX_OBS_STEPS 2000
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char name[32];
|
||||||
|
int prov; /* 0 sch, 1 mink, 2 alc */
|
||||||
|
double mass, esc;
|
||||||
|
double vs, radius, sigma;
|
||||||
|
double look_ra_deg, look_dec_deg;
|
||||||
|
double pos[3], vel[3];
|
||||||
|
double initial, max_step;
|
||||||
|
double ref_max_step, lookback;
|
||||||
|
unsigned int ref_max_steps;
|
||||||
|
int ndirs;
|
||||||
|
double dirs[MAX_BDIRS][3];
|
||||||
|
} BCase;
|
||||||
|
|
||||||
|
static double b_now(void) {
|
||||||
|
struct timespec ts;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (double)ts.tv_sec + 1e-9 * (double)ts.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void b_dir(double th, double n[3]) {
|
||||||
|
if (th == 0.0) {
|
||||||
|
n[0] = 1.0;
|
||||||
|
n[1] = n[2] = 0.0;
|
||||||
|
} else if (th == PI) {
|
||||||
|
n[0] = -1.0;
|
||||||
|
n[1] = n[2] = 0.0;
|
||||||
|
} else {
|
||||||
|
n[0] = cos(th);
|
||||||
|
n[1] = sin(th);
|
||||||
|
n[2] = 0.0;
|
||||||
|
}
|
||||||
|
const double nn = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
n[i] /= nn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double b_critical_angle(double r) {
|
||||||
|
const double b = 3.0 * sqrt(3.0) * sqrt(1.0 - 2.0 / r) / r;
|
||||||
|
return (b < 1.0) ? asin(b) : PI / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GeodesicTraceConfig b_make_dp(double initial, double min_step,
|
||||||
|
double max_step, double tol,
|
||||||
|
unsigned int max_steps, double lookback) {
|
||||||
|
GeodesicTraceConfig c;
|
||||||
|
memset(&c, 0, sizeof c);
|
||||||
|
c.coordinate_time_step = initial;
|
||||||
|
c.max_steps = max_steps;
|
||||||
|
c.threshold.kind = THRESHOLD_LOG_ENERGY_GROWTH;
|
||||||
|
c.threshold.value = 8.0;
|
||||||
|
c.threshold.policy_version = 3;
|
||||||
|
c.stepper = GEODESIC_STEPPER_DP54;
|
||||||
|
c.atol_x = c.atol_Pi = c.atol_L = c.rtol = tol;
|
||||||
|
c.min_step = min_step;
|
||||||
|
c.max_step = max_step;
|
||||||
|
c.consecutive_rejection_limit = 32;
|
||||||
|
c.max_lookback_time = lookback;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b_build_source(const BCase *c, SpacetimeSource *s) {
|
||||||
|
if (c->prov == 0)
|
||||||
|
return spacetime_create_schwarzschild_ks(s, c->mass, c->esc);
|
||||||
|
if (c->prov == 1)
|
||||||
|
return spacetime_create_minkowski(s, c->esc);
|
||||||
|
return spacetime_create_alcubierre(s, c->vs, c->radius, c->sigma);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b_build_observer(const BCase *c, const SpacetimeSource *s,
|
||||||
|
ObserverState *o) {
|
||||||
|
MetricData m;
|
||||||
|
if (spacetime_eval(s, 0.0, c->pos, &m) != SPACETIME_POINT_OK)
|
||||||
|
return -1;
|
||||||
|
ObserverCamera cam;
|
||||||
|
memset(&cam, 0, sizeof cam);
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
cam.position[i] = c->pos[i];
|
||||||
|
cam.velocity[i] = c->vel[i];
|
||||||
|
}
|
||||||
|
cam.look_ra_deg = c->look_ra_deg;
|
||||||
|
cam.look_dec_deg = c->look_dec_deg;
|
||||||
|
return observer_from_coordinate_camera(&m, &cam, o, NULL) ==
|
||||||
|
OBSERVER_BUILD_OK
|
||||||
|
? 0
|
||||||
|
: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void b_add_sch(BCase *c, const char *name, double r, double look,
|
||||||
|
const double *thetas, int nt) {
|
||||||
|
memset(c, 0, sizeof *c);
|
||||||
|
snprintf(c->name, sizeof c->name, "%s", name);
|
||||||
|
c->prov = 0;
|
||||||
|
c->mass = 1.0;
|
||||||
|
c->esc = 256.0;
|
||||||
|
c->look_ra_deg = look;
|
||||||
|
c->pos[0] = r;
|
||||||
|
c->initial = 0.1;
|
||||||
|
c->max_step = 2.0;
|
||||||
|
c->ref_max_step = 0.25;
|
||||||
|
c->lookback = 6553.6;
|
||||||
|
c->ref_max_steps = 65536;
|
||||||
|
c->ndirs = nt;
|
||||||
|
for (int i = 0; i < nt; ++i)
|
||||||
|
b_dir(thetas[i], c->dirs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void b_add_mink(BCase *c) {
|
||||||
|
memset(c, 0, sizeof *c);
|
||||||
|
snprintf(c->name, sizeof c->name, "mink_moving");
|
||||||
|
c->prov = 1;
|
||||||
|
c->esc = 64.0;
|
||||||
|
c->look_ra_deg = 0.0;
|
||||||
|
c->pos[0] = 10.0;
|
||||||
|
c->pos[1] = 20.0;
|
||||||
|
c->pos[2] = -15.0;
|
||||||
|
c->vel[0] = 0.3;
|
||||||
|
c->vel[1] = 0.2;
|
||||||
|
c->vel[2] = 0.1;
|
||||||
|
c->initial = 1.0;
|
||||||
|
c->max_step = 16.0;
|
||||||
|
c->ref_max_step = 1.0;
|
||||||
|
c->lookback = 2048.0;
|
||||||
|
c->ref_max_steps = 4096;
|
||||||
|
c->ndirs = 2;
|
||||||
|
b_dir(0.0, c->dirs[0]);
|
||||||
|
b_dir(PI, c->dirs[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void b_add_alc(BCase *c, const char *name, double vs, double sigma,
|
||||||
|
const double *thetas, int nt) {
|
||||||
|
memset(c, 0, sizeof *c);
|
||||||
|
snprintf(c->name, sizeof c->name, "%s", name);
|
||||||
|
c->prov = 2;
|
||||||
|
c->vs = vs;
|
||||||
|
c->radius = 1.0;
|
||||||
|
c->sigma = sigma;
|
||||||
|
c->look_ra_deg = 0.0;
|
||||||
|
c->vel[0] = vs;
|
||||||
|
c->initial = fmin(0.1, 0.05 / sigma);
|
||||||
|
c->max_step = c->initial * 8.0;
|
||||||
|
c->ref_max_step = c->initial;
|
||||||
|
const double esc = spacetime_alcubierre_escape_radius(1.0, sigma);
|
||||||
|
c->lookback = 1.25 * 4.0 * esc / (1.0 - fabs(vs));
|
||||||
|
c->ref_max_steps = 200000;
|
||||||
|
c->ndirs = nt;
|
||||||
|
for (int i = 0; i < nt; ++i)
|
||||||
|
b_dir(thetas[i], c->dirs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gamma^{ij} Pi_i Pi_j - 1; `invert` is the production static from
|
||||||
|
* geodesic.c, so this is the exact production metric contraction. */
|
||||||
|
static double b_null_residual(const MetricData *m, const double Pi[3]) {
|
||||||
|
double g[3][3], inv[3][3];
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
for (int j = 0; j < 3; ++j)
|
||||||
|
g[i][j] = m->gamma[i][j];
|
||||||
|
if (invert(g, inv))
|
||||||
|
return NAN;
|
||||||
|
double v = 0.0;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
for (int j = 0; j < 3; ++j)
|
||||||
|
v += inv[i][j] * Pi[i] * Pi[j];
|
||||||
|
return v - 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
static BCase cases[MAX_BCASES];
|
||||||
|
int nc = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
const double tc = b_critical_angle(30.0);
|
||||||
|
const double th[6] = {0.0, PI, tc - 1e-7, tc + 1e-7, tc - 1e-5, tc + 1e-5};
|
||||||
|
b_add_sch(&cases[nc++], "r30_inward", 30.0, 180.0, th, 6);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const double tc = b_critical_angle(100.0);
|
||||||
|
const double th[4] = {0.0, PI, tc, tc - 1e-7};
|
||||||
|
b_add_sch(&cases[nc++], "r100_inward", 100.0, 180.0, th, 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const double tc = b_critical_angle(2.1);
|
||||||
|
const double th[5] = {0.0, tc, tc - 1e-7, tc + 1e-7, PI};
|
||||||
|
b_add_sch(&cases[nc++], "r2p1_outward", 2.1, 0.0, th, 5);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const double th[2] = {0.0, PI};
|
||||||
|
b_add_sch(&cases[nc++], "r1p5_freefall", 1.5, 180.0, th, 2);
|
||||||
|
/* free-fall velocity is set below (b_add_sch leaves it zero). */
|
||||||
|
}
|
||||||
|
b_add_mink(&cases[nc++]);
|
||||||
|
{
|
||||||
|
const double th[2] = {0.0, PI};
|
||||||
|
b_add_alc(&cases[nc++], "alc_v3_s1", 0.3, 1.0, th, 2);
|
||||||
|
b_add_alc(&cases[nc++], "alc_v9_s10", 0.9, 10.0, th, 2);
|
||||||
|
b_add_alc(&cases[nc++], "alc_v9_s100", 0.9, 100.0, th, 2);
|
||||||
|
}
|
||||||
|
/* Free-fall coordinate velocity for r1.5 (same formula as A). */
|
||||||
|
{
|
||||||
|
BCase *c = &cases[3];
|
||||||
|
const double y = sqrt(2.0 / c->pos[0]);
|
||||||
|
c->vel[0] = -y * (1.0 + y) / (1.0 + y + y * y);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *hf = fopen("raw/b_actual_h.csv", "w");
|
||||||
|
FILE *sf = fopen("raw/b_summary.csv", "w");
|
||||||
|
if (!hf || !sf) {
|
||||||
|
fprintf(stderr, "FATAL: cannot open b csv\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
fprintf(hf, "case,dir,step,t,h,boundary_limited,rhs_delta,reject_delta,"
|
||||||
|
"null_residual\n");
|
||||||
|
fprintf(sf, "case,dir,ref_outcome,ref_stop_t,span,target,observed_steps,"
|
||||||
|
"reached_target,terminated_reason,h_min,h_max,h_first,h_last,"
|
||||||
|
"boundary_steps,sum_rhs,sum_reject,max_reject_delta,"
|
||||||
|
"null_residual_max,final_t,wall_s\n");
|
||||||
|
|
||||||
|
long total_steps = 0;
|
||||||
|
for (int ci = 0; ci < nc; ++ci) {
|
||||||
|
BCase *c = &cases[ci];
|
||||||
|
SpacetimeSource source;
|
||||||
|
ObserverState observer;
|
||||||
|
if (b_build_source(c, &source) || b_build_observer(c, &source, &observer)) {
|
||||||
|
fprintf(stderr, "FATAL: cannot build B case %s\n", c->name);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
for (int di = 0; di < c->ndirs; ++di) {
|
||||||
|
/* 1. trusted reference via the public endpoint (physical terminal). */
|
||||||
|
GeodesicTraceConfig refcfg =
|
||||||
|
b_make_dp(c->initial, 1e-12, c->ref_max_step, 1e-12, c->ref_max_steps,
|
||||||
|
c->lookback);
|
||||||
|
RayEndpoint ref =
|
||||||
|
geodesic_trace_past(&source, &observer, c->dirs[di], &refcfg);
|
||||||
|
const double span =
|
||||||
|
isfinite(ref.stop_coordinate_time)
|
||||||
|
? (observer.coordinate_time - ref.stop_coordinate_time)
|
||||||
|
: 20.0;
|
||||||
|
const double finite_T = fmin(20.0, span > 0.0 ? span : 20.0);
|
||||||
|
const double target = observer.coordinate_time - finite_T;
|
||||||
|
|
||||||
|
/* 2. production-exact INSIDE-route initialization. */
|
||||||
|
MetricData metric;
|
||||||
|
if (spacetime_eval(&source, observer.coordinate_time,
|
||||||
|
observer.coordinate_position, &metric) !=
|
||||||
|
SPACETIME_POINT_OK) {
|
||||||
|
fprintf(stderr, "FATAL: camera metric %s\n", c->name);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
State st;
|
||||||
|
if (geodesic_initialize_past_ray_metric(&metric, &observer, c->dirs[di],
|
||||||
|
&st)) {
|
||||||
|
fprintf(stderr, "FATAL: init %s dir %d\n", c->name, di);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
GeodesicTraceConfig cfg =
|
||||||
|
b_make_dp(c->initial, 1e-12, c->max_step, 1e-9, 0u, 0.0);
|
||||||
|
st.next_step = cfg.coordinate_time_step;
|
||||||
|
|
||||||
|
MetricSlab *slab = NULL;
|
||||||
|
if (spacetime_load_slab(&source, st.coordinate_time, target - 1.0,
|
||||||
|
&slab)) {
|
||||||
|
fprintf(stderr, "FATAL: slab %s dir %d\n", c->name, di);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
double h_min = INFINITY, h_max = 0.0, h_first = NAN, h_last = NAN;
|
||||||
|
double null_max = 0.0, sum_wall = 0.0;
|
||||||
|
unsigned long sum_rhs = 0;
|
||||||
|
unsigned int sum_rej = 0, max_rej_delta = 0, boundary_steps = 0;
|
||||||
|
int reached = 0, terminated_reason = -1;
|
||||||
|
int step_index = 0;
|
||||||
|
const double start_wall = b_now();
|
||||||
|
while (st.coordinate_time > target && step_index < MAX_OBS_STEPS) {
|
||||||
|
const double before_t = st.coordinate_time;
|
||||||
|
unsigned long rhs = st.rhs_evaluations;
|
||||||
|
unsigned int rej = st.rejected_steps;
|
||||||
|
RayReason reason = RAY_REASON_INTEGRATION_ERROR;
|
||||||
|
const int rc =
|
||||||
|
dp_advance_one(slab, &cfg, &st, target, &reason, &rhs, &rej, NULL);
|
||||||
|
const unsigned long rhs_delta = rhs - st.rhs_evaluations;
|
||||||
|
const unsigned int rej_delta = rej - st.rejected_steps;
|
||||||
|
st.rhs_evaluations = rhs;
|
||||||
|
st.rejected_steps = rej;
|
||||||
|
sum_rhs += rhs_delta;
|
||||||
|
sum_rej += rej_delta;
|
||||||
|
if (rej_delta > max_rej_delta)
|
||||||
|
max_rej_delta = rej_delta;
|
||||||
|
if (rc) {
|
||||||
|
terminated_reason = (int)reason;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const double h = before_t - st.coordinate_time;
|
||||||
|
const int boundary = (st.coordinate_time == target);
|
||||||
|
if (boundary)
|
||||||
|
++boundary_steps;
|
||||||
|
if (h < h_min)
|
||||||
|
h_min = h;
|
||||||
|
if (h > h_max)
|
||||||
|
h_max = h;
|
||||||
|
if (step_index == 0)
|
||||||
|
h_first = h;
|
||||||
|
h_last = h;
|
||||||
|
++step_index;
|
||||||
|
MetricData m;
|
||||||
|
double nr = NAN;
|
||||||
|
if (spacetime_slab_eval(slab, st.coordinate_time, st.x, &m) ==
|
||||||
|
SPACETIME_POINT_OK)
|
||||||
|
nr = b_null_residual(&m, st.Pi);
|
||||||
|
if (isfinite(nr) && fabs(nr) > null_max)
|
||||||
|
null_max = fabs(nr);
|
||||||
|
fprintf(hf, "%s,%d,%d,%.17g,%.17g,%d,%lu,%u,%.6g\n", c->name, di,
|
||||||
|
step_index, st.coordinate_time, h, boundary, rhs_delta,
|
||||||
|
rej_delta, nr);
|
||||||
|
if (st.coordinate_time <= target)
|
||||||
|
reached = 1;
|
||||||
|
}
|
||||||
|
sum_wall = b_now() - start_wall;
|
||||||
|
if (step_index >= MAX_OBS_STEPS)
|
||||||
|
reached = 0;
|
||||||
|
if (!isfinite(h_first)) {
|
||||||
|
h_first = NAN;
|
||||||
|
h_max = NAN;
|
||||||
|
}
|
||||||
|
if (!isfinite(h_min) || h_min == INFINITY)
|
||||||
|
h_min = NAN;
|
||||||
|
if (h_last < 0.0)
|
||||||
|
h_last = NAN;
|
||||||
|
fprintf(sf,
|
||||||
|
"%s,%d,%d,%.17g,%.17g,%.17g,%d,%d,%d,%.17g,%.17g,%.17g,%.17g,"
|
||||||
|
"%u,%lu,%u,%u,%.6g,%.17g,%.6g\n",
|
||||||
|
c->name, di, ref.outcome, ref.stop_coordinate_time, span, target,
|
||||||
|
step_index, reached, terminated_reason, h_min, h_max, h_first,
|
||||||
|
h_last, boundary_steps, sum_rhs, sum_rej, max_rej_delta, null_max,
|
||||||
|
st.coordinate_time, sum_wall);
|
||||||
|
printf("B %s dir=%d ref=%d refstop=%.9g span=%.6g T=%.6g target=%.6g "
|
||||||
|
"steps=%d reached=%d term=%d h=[%.6g,%.6g] first=%.6g last=%.6g "
|
||||||
|
"boundary=%u rhs=%lu rej=%u nullmax=%.3g final_t=%.9g wall=%.4fs\n",
|
||||||
|
c->name, di, ref.outcome, ref.stop_coordinate_time, span, finite_T,
|
||||||
|
target, step_index, reached, terminated_reason, h_min, h_max,
|
||||||
|
h_first, h_last, boundary_steps, sum_rhs, sum_rej, null_max,
|
||||||
|
st.coordinate_time, sum_wall);
|
||||||
|
fflush(stdout);
|
||||||
|
total_steps += step_index;
|
||||||
|
spacetime_free_slab(slab);
|
||||||
|
}
|
||||||
|
spacetime_destroy(&source);
|
||||||
|
}
|
||||||
|
fclose(hf);
|
||||||
|
fclose(sf);
|
||||||
|
printf("TOTAL_OBSERVED_STEPS %ld\n", total_steps);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
* Standalone critical-classification reference check.
|
||||||
|
*
|
||||||
|
* Three static Schwarzschild cameras (M=1, escape sphere 256):
|
||||||
|
* r30 look 180 (inward), r100 look 180 (inward), r2.1 look 0 (outward),
|
||||||
|
* each aimed at theta_crit exactly and at theta_crit +- 1e-7, where
|
||||||
|
* theta_crit = asin(3 sqrt(3) sqrt(1 - 2/r) / r)
|
||||||
|
* is the local tetrad angle from the camera forward direction.
|
||||||
|
*
|
||||||
|
* For every direction four DP54 configs are run (initial step 0.1,
|
||||||
|
* min_step 1e-14, max_steps 65536, max_lookback_time 6553.6, reject limit 32,
|
||||||
|
* camera-relative dark threshold 8):
|
||||||
|
*
|
||||||
|
* ref_tol1e-12_h0.25 tol 1e-12, max_step 0.25
|
||||||
|
* ref_tol1e-13_h0.125 tol 1e-13, max_step 0.125
|
||||||
|
* tol1e-11_h2 tol 1e-11, max_step 2
|
||||||
|
* tol1e-11_h8 tol 1e-11, max_step 8
|
||||||
|
*
|
||||||
|
* Total 3 cameras * 3 directions * 4 configs = 36 endpoint traces.
|
||||||
|
*
|
||||||
|
* Raw per-run rows go to raw/critical_ref.csv; stdout prints, for all nine
|
||||||
|
* directions, ref_vs_tighter / h2_vs_h8 / ref_vs_h2 / ref_vs_h8 comparisons
|
||||||
|
* (outcome/reason/end, sky angle, relative g, dark stop-time and threshold
|
||||||
|
* shifts) and a NEIGHBOR_REFERENCE_CHECK that verifies the two reference
|
||||||
|
* tiers agree at the +-1e-7 neighbours. The exactly-critical direction is a
|
||||||
|
* separatrix: a class flip or a large direction/stop-time difference there is
|
||||||
|
* reported as EXACT_CRITICAL_REFERENCE_NOT_CONVERGED and is diagnostic only.
|
||||||
|
*
|
||||||
|
* Exit status: 0 when the neighbours' reference tiers agree and no neighbour
|
||||||
|
* returned an error/unresolved endpoint or a zero-step trace; 1 when a
|
||||||
|
* neighbour reference check fails; 2 on setup error. The exact-critical
|
||||||
|
* separatrix is never an assertion.
|
||||||
|
*
|
||||||
|
* Link line (the Schwarzschild backend is textually included):
|
||||||
|
* cc -std=c11 -O2 -Isrc critical_ref_check.c geodesic.c asymptotic.c \
|
||||||
|
* asymptotic_schwarzschild.c spacetime_common.c observer.c -lm
|
||||||
|
*/
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../../src/spacetime_schwarzschild.c"
|
||||||
|
|
||||||
|
#include "geodesic.h"
|
||||||
|
#include "observer.h"
|
||||||
|
#include "spacetime.h"
|
||||||
|
|
||||||
|
#define PI 3.14159265358979323846
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
double tol;
|
||||||
|
double max_step;
|
||||||
|
} CfgDef;
|
||||||
|
|
||||||
|
static const CfgDef cfgs[4] = {
|
||||||
|
{"ref_tol1e-12_h0.25", 1e-12, 0.25},
|
||||||
|
{"ref_tol1e-13_h0.125", 1e-13, 0.125},
|
||||||
|
{"tol1e-11_h2", 1e-11, 2.0},
|
||||||
|
{"tol1e-11_h8", 1e-11, 8.0},
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
double r;
|
||||||
|
double look_ra_deg;
|
||||||
|
} CamDef;
|
||||||
|
|
||||||
|
static const CamDef cams[3] = {
|
||||||
|
{"r30_inward", 30.0, 180.0},
|
||||||
|
{"r100_inward", 100.0, 180.0},
|
||||||
|
{"r2p1_outward", 2.1, 0.0},
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int outcome, reason;
|
||||||
|
unsigned int end_id;
|
||||||
|
double stop_t, g, thr;
|
||||||
|
double L, L0;
|
||||||
|
double n[3];
|
||||||
|
unsigned int steps, rejected;
|
||||||
|
unsigned long rhs;
|
||||||
|
} Res;
|
||||||
|
|
||||||
|
static double b_dot3(const double a[3], const double b[3]) {
|
||||||
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
static double b_ang_delta(const double a[3], const double b[3]) {
|
||||||
|
const double na = sqrt(b_dot3(a, a)), nb = sqrt(b_dot3(b, b));
|
||||||
|
if (!(na > 0.0) || !(nb > 0.0))
|
||||||
|
return NAN;
|
||||||
|
const double cross[3] = {a[1] * b[2] - a[2] * b[1],
|
||||||
|
a[2] * b[0] - a[0] * b[2],
|
||||||
|
a[0] * b[1] - a[1] * b[0]};
|
||||||
|
return atan2(sqrt(b_dot3(cross, cross)) / (na * nb),
|
||||||
|
b_dot3(a, b) / (na * nb));
|
||||||
|
}
|
||||||
|
|
||||||
|
static double critical_angle(double r) {
|
||||||
|
const double b = 3.0 * sqrt(3.0) * sqrt(1.0 - 2.0 / r) / r;
|
||||||
|
return (b < 1.0) ? asin(b) : PI / 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dir_from_theta(double th, double n[3]) {
|
||||||
|
n[0] = cos(th);
|
||||||
|
n[1] = sin(th);
|
||||||
|
n[2] = 0.0;
|
||||||
|
const double nn = sqrt(b_dot3(n, n));
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
n[i] /= nn;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GeodesicTraceConfig make_cfg(const CfgDef *d) {
|
||||||
|
GeodesicTraceConfig c;
|
||||||
|
memset(&c, 0, sizeof c);
|
||||||
|
c.coordinate_time_step = 0.1;
|
||||||
|
c.max_steps = 65536;
|
||||||
|
c.threshold.kind = THRESHOLD_LOG_ENERGY_GROWTH;
|
||||||
|
c.threshold.value = 8.0;
|
||||||
|
c.threshold.policy_version = 3;
|
||||||
|
c.stepper = GEODESIC_STEPPER_DP54;
|
||||||
|
c.atol_x = c.atol_Pi = c.atol_L = c.rtol = d->tol;
|
||||||
|
c.min_step = 1e-14;
|
||||||
|
c.max_step = d->max_step;
|
||||||
|
c.consecutive_rejection_limit = 32;
|
||||||
|
c.max_lookback_time = 6553.6;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int build_observer(const CamDef *cam, const SpacetimeSource *s,
|
||||||
|
ObserverState *o) {
|
||||||
|
const double pos[3] = {cam->r, 0.0, 0.0};
|
||||||
|
MetricData m;
|
||||||
|
if (spacetime_eval(s, 0.0, pos, &m) != SPACETIME_POINT_OK)
|
||||||
|
return -1;
|
||||||
|
ObserverCamera camera;
|
||||||
|
memset(&camera, 0, sizeof camera);
|
||||||
|
camera.position[0] = pos[0];
|
||||||
|
camera.position[1] = pos[1];
|
||||||
|
camera.position[2] = pos[2];
|
||||||
|
camera.look_ra_deg = cam->look_ra_deg;
|
||||||
|
camera.look_dec_deg = 0.0;
|
||||||
|
return observer_from_coordinate_camera(&m, &camera, o, NULL) ==
|
||||||
|
OBSERVER_BUILD_OK
|
||||||
|
? 0
|
||||||
|
: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Res run_one(const SpacetimeSource *s, const ObserverState *o,
|
||||||
|
const double dir[3], const GeodesicTraceConfig *cfg) {
|
||||||
|
Res r;
|
||||||
|
memset(&r, 0, sizeof r);
|
||||||
|
const RayEndpoint e = geodesic_trace_past(s, o, dir, cfg);
|
||||||
|
r.outcome = e.outcome;
|
||||||
|
r.reason = e.reason;
|
||||||
|
r.end_id = e.end_id;
|
||||||
|
r.stop_t = e.stop_coordinate_time;
|
||||||
|
r.g = e.frequency_ratio;
|
||||||
|
r.thr = e.threshold_value;
|
||||||
|
r.L = e.final_log_alpha_p0;
|
||||||
|
r.L0 = e.final_log_alpha_p0_0;
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
r.n[i] = e.n_infinity[i];
|
||||||
|
r.steps = e.accepted_steps;
|
||||||
|
r.rejected = e.rejected_steps;
|
||||||
|
r.rhs = e.rhs_evaluations;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *outcome_name(int o) {
|
||||||
|
switch (o) {
|
||||||
|
case RAY_OUTCOME_ESCAPED:
|
||||||
|
return "ESC";
|
||||||
|
case RAY_OUTCOME_DARK:
|
||||||
|
return "DARK";
|
||||||
|
case RAY_OUTCOME_UNRESOLVED:
|
||||||
|
return "UNRES";
|
||||||
|
default:
|
||||||
|
return "INC";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_pair(const char *cam, int di, double theta, const char *pn,
|
||||||
|
const Res *a, const Res *b) {
|
||||||
|
const int same = a->outcome == b->outcome && a->reason == b->reason &&
|
||||||
|
a->end_id == b->end_id;
|
||||||
|
const int esc = a->outcome == RAY_OUTCOME_ESCAPED &&
|
||||||
|
b->outcome == RAY_OUTCOME_ESCAPED;
|
||||||
|
const double dn = esc ? b_ang_delta(a->n, b->n) : NAN;
|
||||||
|
const double dg =
|
||||||
|
(esc && a->g > 0.0 && b->g > 0.0) ? fabs(a->g / b->g - 1.0) : NAN;
|
||||||
|
const double dstop =
|
||||||
|
(isfinite(a->stop_t) && isfinite(b->stop_t)) ? a->stop_t - b->stop_t
|
||||||
|
: NAN;
|
||||||
|
const double dthr = (isfinite(a->thr) && isfinite(b->thr))
|
||||||
|
? a->thr - b->thr
|
||||||
|
: NAN;
|
||||||
|
printf("CAPAIR camera=%s dir=%d theta=%.17g pair=%s class=%s/%s same=%d "
|
||||||
|
"dn_ang=%.17g dgrel=%.17g dstop_t=%.17g dthr=%.17g end=%u/%u\n",
|
||||||
|
cam, di, theta, pn, outcome_name(a->outcome), outcome_name(b->outcome),
|
||||||
|
same, dn, dg, dstop, dthr, a->end_id, b->end_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A two-reference-tier agreement check for one neighbour direction. Returns
|
||||||
|
* 1 when the pair is a valid, agreeing ESC/DARK reference, 0 otherwise. */
|
||||||
|
static int neighbour_reference_check(const char *cam, int di, double theta,
|
||||||
|
const Res *a, const Res *b) {
|
||||||
|
const int class_same = a->outcome == b->outcome && a->reason == b->reason &&
|
||||||
|
a->end_id == b->end_id;
|
||||||
|
const int clean = (a->outcome == RAY_OUTCOME_ESCAPED ||
|
||||||
|
a->outcome == RAY_OUTCOME_DARK) &&
|
||||||
|
(b->outcome == RAY_OUTCOME_ESCAPED ||
|
||||||
|
b->outcome == RAY_OUTCOME_DARK);
|
||||||
|
const int stepped = a->steps > 0 && b->steps > 0;
|
||||||
|
const int esc = a->outcome == RAY_OUTCOME_ESCAPED &&
|
||||||
|
b->outcome == RAY_OUTCOME_ESCAPED;
|
||||||
|
const double dn = esc ? b_ang_delta(a->n, b->n) : NAN;
|
||||||
|
const double dg =
|
||||||
|
(esc && a->g > 0.0 && b->g > 0.0) ? fabs(a->g / b->g - 1.0) : NAN;
|
||||||
|
const double dstop =
|
||||||
|
(isfinite(a->stop_t) && isfinite(b->stop_t)) ? a->stop_t - b->stop_t
|
||||||
|
: NAN;
|
||||||
|
printf("NEIGHBOR_REFERENCE_CHECK camera=%s dir=%d theta=%.17g "
|
||||||
|
"ref_class0=%s/%d/%u ref_class1=%s/%d/%u same=%d clean=%d stepped=%d "
|
||||||
|
"dn_ang=%.17g dgrel=%.17g dstop_t=%.17g\n",
|
||||||
|
cam, di, theta, outcome_name(a->outcome), a->reason, a->end_id,
|
||||||
|
outcome_name(b->outcome), b->reason, b->end_id, class_same, clean,
|
||||||
|
stepped, dn, dg, dstop);
|
||||||
|
return class_same && clean && stepped;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
SpacetimeSource source;
|
||||||
|
if (spacetime_create_schwarzschild_ks(&source, 1.0, 256.0)) {
|
||||||
|
fprintf(stderr, "FATAL: cannot create Schwarzschild source\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen("raw/critical_ref.csv", "w");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "FATAL: cannot open raw/critical_ref.csv\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
fprintf(f, "camera,dir,theta,cfg,outcome,reason,end_id,stop_t,steps,"
|
||||||
|
"rejected,rhs,nx,ny,nz,g,thr,L,L0\n");
|
||||||
|
|
||||||
|
Res res[3][3][4];
|
||||||
|
double thetas[3][3];
|
||||||
|
for (int ci = 0; ci < 3; ++ci) {
|
||||||
|
ObserverState observer;
|
||||||
|
if (build_observer(&cams[ci], &source, &observer)) {
|
||||||
|
fprintf(stderr, "FATAL: cannot build observer %s\n", cams[ci].name);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
const double tc = critical_angle(cams[ci].r);
|
||||||
|
const double th[3] = {tc - 1e-7, tc, tc + 1e-7};
|
||||||
|
for (int di = 0; di < 3; ++di) {
|
||||||
|
double dir[3];
|
||||||
|
dir_from_theta(th[di], dir);
|
||||||
|
thetas[ci][di] = th[di];
|
||||||
|
for (int fi = 0; fi < 4; ++fi) {
|
||||||
|
const GeodesicTraceConfig cfg = make_cfg(&cfgs[fi]);
|
||||||
|
const Res r = run_one(&source, &observer, dir, &cfg);
|
||||||
|
res[ci][di][fi] = r;
|
||||||
|
fprintf(f, "%s,%d,%.17g,%s,%d,%d,%u,%.17g,%u,%u,%lu,%.17g,%.17g,"
|
||||||
|
"%.17g,%.17g,%.17g,%.17g,%.17g\n",
|
||||||
|
cams[ci].name, di, th[di], cfgs[fi].name, r.outcome, r.reason,
|
||||||
|
r.end_id, r.stop_t, r.steps, r.rejected, r.rhs, r.n[0], r.n[1],
|
||||||
|
r.n[2], r.g, r.thr, r.L, r.L0);
|
||||||
|
printf("RAW camera=%s dir=%d theta=%.17g cfg=%s outcome=%d reason=%d "
|
||||||
|
"end=%u stop_t=%.17g steps=%u rejected=%u rhs=%lu g=%.17g "
|
||||||
|
"thr=%.17g L=%.17g L0=%.17g nx=%.17g ny=%.17g nz=%.17g\n",
|
||||||
|
cams[ci].name, di, th[di], cfgs[fi].name, r.outcome, r.reason,
|
||||||
|
r.end_id, r.stop_t, r.steps, r.rejected, r.rhs, r.g, r.thr, r.L,
|
||||||
|
r.L0, r.n[0], r.n[1], r.n[2]);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
/* All nine directions: ref_vs_tighter, h2_vs_h8, ref_vs_h2, ref_vs_h8. */
|
||||||
|
for (int ci = 0; ci < 3; ++ci) {
|
||||||
|
for (int di = 0; di < 3; ++di) {
|
||||||
|
print_pair(cams[ci].name, di, thetas[ci][di], "ref_vs_tighter",
|
||||||
|
&res[ci][di][0], &res[ci][di][1]);
|
||||||
|
print_pair(cams[ci].name, di, thetas[ci][di], "h2_vs_h8",
|
||||||
|
&res[ci][di][2], &res[ci][di][3]);
|
||||||
|
print_pair(cams[ci].name, di, thetas[ci][di], "ref_vs_h2",
|
||||||
|
&res[ci][di][0], &res[ci][di][2]);
|
||||||
|
print_pair(cams[ci].name, di, thetas[ci][di], "ref_vs_h8",
|
||||||
|
&res[ci][di][0], &res[ci][di][3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Exact-critical: diagnostic only, never asserted. */
|
||||||
|
for (int ci = 0; ci < 3; ++ci) {
|
||||||
|
const Res *a = &res[ci][1][0];
|
||||||
|
const Res *b = &res[ci][1][1];
|
||||||
|
const int same = a->outcome == b->outcome && a->reason == b->reason &&
|
||||||
|
a->end_id == b->end_id;
|
||||||
|
const int esc = a->outcome == RAY_OUTCOME_ESCAPED &&
|
||||||
|
b->outcome == RAY_OUTCOME_ESCAPED;
|
||||||
|
const int dark = a->outcome == RAY_OUTCOME_DARK &&
|
||||||
|
b->outcome == RAY_OUTCOME_DARK;
|
||||||
|
const double dn = esc ? b_ang_delta(a->n, b->n) : NAN;
|
||||||
|
const double dstop =
|
||||||
|
(isfinite(a->stop_t) && isfinite(b->stop_t)) ? a->stop_t - b->stop_t
|
||||||
|
: NAN;
|
||||||
|
const int nonconverged =
|
||||||
|
!same || (esc && !(dn <= 1e-6)) || (dark && fabs(dstop) > 1e-4);
|
||||||
|
printf("EXACT_CRITICAL_DIRECTION camera=%s theta=%.17g ref0=%s/%d/%u "
|
||||||
|
"ref1=%s/%d/%u same=%d dn_ang=%.17g dstop_t=%.17g\n",
|
||||||
|
cams[ci].name, thetas[ci][1], outcome_name(a->outcome), a->reason,
|
||||||
|
a->end_id, outcome_name(b->outcome), b->reason, b->end_id, same, dn,
|
||||||
|
dstop);
|
||||||
|
if (nonconverged)
|
||||||
|
printf("EXACT_CRITICAL_REFERENCE_NOT_CONVERGED camera=%s dn_ang=%.17g "
|
||||||
|
"dstop_t=%.17g class_same=%d\n",
|
||||||
|
cams[ci].name, dn, dstop, same);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Neighbour reference check: must pass; this is the assertion-valid path. */
|
||||||
|
int fail = 0;
|
||||||
|
for (int ci = 0; ci < 3; ++ci) {
|
||||||
|
for (int di = 0; di < 3; di += 2) {
|
||||||
|
if (!neighbour_reference_check(cams[ci].name, di, thetas[ci][di],
|
||||||
|
&res[ci][di][0], &res[ci][di][1]))
|
||||||
|
fail = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spacetime_destroy(&source);
|
||||||
|
printf("CRITICAL_REFERENCE_CHECK status=%d\n", fail ? 1 : 0);
|
||||||
|
printf("CRITICAL_REF_DONE\n");
|
||||||
|
return fail ? 1 : 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/* Diagnostic only: reuse the production regression's invalid-metric fixture. */
|
||||||
|
#define main adaptive_regression_main_not_called
|
||||||
|
#include "../../tests/test_geodesic_adaptive.c"
|
||||||
|
#undef main
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
const double floors[] = {1e-2,1e-4,1e-6,1e-8,1e-10,1e-12,1e-14};
|
||||||
|
for (unsigned i=0;i<sizeof floors/sizeof *floors;++i) {
|
||||||
|
FixtureContext context={.bad_status=SPACETIME_POINT_INVALID_METRIC,
|
||||||
|
.bad_lo=-10,.bad_hi=-.05,.radius=100};
|
||||||
|
SpacetimeSource source={.context=&context,.ops=&fixture_ops};
|
||||||
|
GeodesicTraceConfig config=dp_config(1e-9,.1,10);
|
||||||
|
config.min_step=floors[i]; config.max_step=1;
|
||||||
|
const ObserverState observer=flat_observer_at((double[3]){0,0,0});
|
||||||
|
const double direction[3]={1,0,0};
|
||||||
|
RayEndpoint endpoint=geodesic_trace_past(&source,&observer,direction,&config);
|
||||||
|
printf("FAILURE_FLOOR min=%.0e outcome=%d reason=%d t=%.17g distance_to_invalid=%.17g accepted=%u rejected=%u rhs=%lu\n",
|
||||||
|
floors[i],endpoint.outcome,endpoint.reason,endpoint.stop_coordinate_time,
|
||||||
|
endpoint.stop_coordinate_time+.05,endpoint.accepted_steps,
|
||||||
|
endpoint.rejected_steps,endpoint.rhs_evaluations);
|
||||||
|
if(endpoint.outcome!=RAY_OUTCOME_INCOMPLETE ||
|
||||||
|
endpoint.stop_coordinate_time<=-.05) return 1;
|
||||||
|
}
|
||||||
|
puts("FAILURE_FLOOR_EXIT=0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Pure GRLENS v3 map load/compare helpers.
|
||||||
|
|
||||||
|
No renderer, no environment probing, no data generation: this module is only
|
||||||
|
imported by the benchmark scripts under
|
||||||
|
benchmarks/adaptive_step_bounds_2026-10-05/. Keeping it here means the
|
||||||
|
benchmark never imports an untracked module from local/.
|
||||||
|
"""
|
||||||
|
import collections
|
||||||
|
import hashlib
|
||||||
|
import math
|
||||||
|
import struct
|
||||||
|
import zlib
|
||||||
|
|
||||||
|
|
||||||
|
def load(path):
|
||||||
|
"""Parse one GRLENS v3 map; returns (info dict, {film_pos: vertex tuple})."""
|
||||||
|
data = path.read_bytes()
|
||||||
|
assert data[:8] == b'GRLENS\x01\x00'
|
||||||
|
assert struct.unpack_from('<I', data, 8)[0] == 3
|
||||||
|
assert struct.unpack_from('<Q', data, 32)[0] == 1
|
||||||
|
nv, nt = struct.unpack_from('<QQ', data, 200)
|
||||||
|
end = 224 + nv * 108 + nt * 32
|
||||||
|
assert end + 4 == len(data)
|
||||||
|
assert zlib.crc32(data[224:end]) == struct.unpack_from('<I', data, end)[0]
|
||||||
|
vertices = [struct.unpack_from('<9dIIIQQQ', data, 224 + i * 108)
|
||||||
|
for i in range(nv)]
|
||||||
|
costs = [sum(v[j] for v in vertices) for j in (12, 13, 14)]
|
||||||
|
result = dict(vertices=nv, triangles=nt,
|
||||||
|
outcomes=dict(collections.Counter(v[10] for v in vertices)),
|
||||||
|
reasons=dict(collections.Counter(v[11] for v in vertices)),
|
||||||
|
accepted=costs[0], rejected=costs[1], rhs=costs[2])
|
||||||
|
names = ('atol_x', 'atol_Pi', 'atol_L', 'rtol', 'min_step', 'max_step',
|
||||||
|
'max_lookback_time', 'retry_lookback_increment',
|
||||||
|
'max_total_lookback_time')
|
||||||
|
result['provenance'] = dict(zip(names, struct.unpack_from('<9d', data, 100)))
|
||||||
|
result['provenance'].update(
|
||||||
|
integrator=struct.unpack_from('<I', data, 68)[0],
|
||||||
|
initial_step=struct.unpack_from('<d', data, 88)[0],
|
||||||
|
initial_max_steps=struct.unpack_from('<I', data, 96)[0],
|
||||||
|
threshold=struct.unpack_from('<d', data, 48)[0],
|
||||||
|
retry_step_increment=struct.unpack_from('<I', data, 56)[0],
|
||||||
|
max_total_steps=struct.unpack_from('<I', data, 60)[0])
|
||||||
|
for j, name in ((12, 'accepted'), (13, 'rejected'), (14, 'rhs')):
|
||||||
|
xs = sorted(v[j] for v in vertices)
|
||||||
|
result[name + '_percentiles'] = {
|
||||||
|
str(q): xs[min(len(xs) - 1, int(q * (len(xs) - 1)))]
|
||||||
|
for q in (0, .5, .9, .99, 1)}
|
||||||
|
result['sha256'] = hashlib.sha256(data).hexdigest()
|
||||||
|
result['triangle_sha256'] = hashlib.sha256(
|
||||||
|
data[224 + nv * 108:end]).hexdigest()
|
||||||
|
by_film = {(v[0], v[1]): v for v in vertices}
|
||||||
|
result['unique_film_positions'] = len(by_film)
|
||||||
|
result['duplicate_film_positions'] = len(vertices) - len(by_film)
|
||||||
|
return result, by_film
|
||||||
|
|
||||||
|
|
||||||
|
def compare(a, b):
|
||||||
|
"""Compare two {film_pos: vertex} maps by shared film-coordinate identity."""
|
||||||
|
keys = a.keys() & b.keys()
|
||||||
|
mismatches = 0
|
||||||
|
worst_sky = worst_logg = 0.
|
||||||
|
for k in keys:
|
||||||
|
x, y = a[k], b[k]
|
||||||
|
if x[9:12] != y[9:12]:
|
||||||
|
mismatches += 1
|
||||||
|
elif x[10] == 0:
|
||||||
|
n, m = x[5:8], y[5:8]
|
||||||
|
cross = (n[1] * m[2] - n[2] * m[1], n[2] * m[0] - n[0] * m[2],
|
||||||
|
n[0] * m[1] - n[1] * m[0])
|
||||||
|
angle = math.atan2(math.sqrt(sum(v * v for v in cross)),
|
||||||
|
sum(v * w for v, w in zip(n, m)))
|
||||||
|
worst_sky = max(worst_sky, angle)
|
||||||
|
worst_logg = max(worst_logg, abs(x[8] - y[8]))
|
||||||
|
return dict(shared=len(keys), only_a=len(a) - len(keys),
|
||||||
|
only_b=len(b) - len(keys), terminal_mismatches=mismatches,
|
||||||
|
max_sky_angle=worst_sky, max_logg_difference=worst_logg)
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Record provenance without launching a render.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
record_environment.py [OUT_DIR]
|
||||||
|
|
||||||
|
OUT_DIR defaults to <repo>/local/adaptive_bounds_mesh. Writes metadata.json in
|
||||||
|
OUT_DIR. No renderer or test is run.
|
||||||
|
"""
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
OUT = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else \
|
||||||
|
ROOT / 'local/adaptive_bounds_mesh'
|
||||||
|
PATHS = ['src/geodesic.c', 'src/main.c', 'src/frame.c',
|
||||||
|
'build/Release/schwarzschild_sky']
|
||||||
|
|
||||||
|
metadata = {
|
||||||
|
'recorded_utc': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
|
||||||
|
'git_head': subprocess.check_output(
|
||||||
|
['git', 'rev-parse', 'HEAD'], cwd=ROOT, text=True).strip(),
|
||||||
|
'hashes': {p: hashlib.sha256((ROOT / p).read_bytes()).hexdigest()
|
||||||
|
for p in PATHS},
|
||||||
|
'compiler': subprocess.check_output(['cc', '--version'], text=True),
|
||||||
|
'cpu': subprocess.check_output(['lscpu'], text=True),
|
||||||
|
'scope': '8 bounded 320x180 candidates plus 2 tight references; no 4K here',
|
||||||
|
'threads': 8,
|
||||||
|
'build_command': 'make -j4 BUILD_TYPE=Release SPACETIME=schwarzschild backend',
|
||||||
|
'run_commands': [
|
||||||
|
'python3 benchmarks/adaptive_step_bounds_2026-10-05/run_mesh.py [OUT]',
|
||||||
|
'python3 benchmarks/adaptive_step_bounds_2026-10-05/run_mesh_reference.py [OUT]',
|
||||||
|
'bash benchmarks/adaptive_step_bounds_2026-10-05/run_failure_floor.sh [OUT]'],
|
||||||
|
}
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
(OUT / 'metadata.json').write_text(json.dumps(metadata, indent=2) + '\n')
|
||||||
|
print(json.dumps(metadata, indent=2))
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"upper": 2,
|
||||||
|
"command": "/home/wyj/Code/C/GR_4d_raytracing/build/Release/schwarzschild_sky --integrator dp54 --width 3840 --height 2160 --look-ra-deg 262.5 --look-dec-deg -30 --fov-deg 45 --observer-radius 100 --coarse-cell-pixels 16 --refine-max-level 4 --refine-jacobian-min .2 --catalog /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/single_dim_star.csv --exposure 1 --tone-map reinhard --psf-min-y 1e-20 --psf-relative-tail 1e-4 --ode-min-step 1e-12 --ode-max-step 2 --verbose --lens-map-output /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax2.grlens --output /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax2.png",
|
||||||
|
"state": "completed",
|
||||||
|
"returncode": 0,
|
||||||
|
"wall_seconds": 11.389317202148959
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"upper": 8,
|
||||||
|
"command": "/home/wyj/Code/C/GR_4d_raytracing/build/Release/schwarzschild_sky --integrator dp54 --width 3840 --height 2160 --look-ra-deg 262.5 --look-dec-deg -30 --fov-deg 45 --observer-radius 100 --coarse-cell-pixels 16 --refine-max-level 4 --refine-jacobian-min .2 --catalog /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/single_dim_star.csv --exposure 1 --tone-map reinhard --psf-min-y 1e-20 --psf-relative-tail 1e-4 --ode-min-step 1e-12 --ode-max-step 8 --verbose --lens-map-output /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax8.grlens --output /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax8.png",
|
||||||
|
"state": "completed",
|
||||||
|
"returncode": 0,
|
||||||
|
"wall_seconds": 8.389249739935622
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
{
|
||||||
|
"r100_4k_hmax2": {
|
||||||
|
"vertices": 66045,
|
||||||
|
"triangles": 131338,
|
||||||
|
"outcomes": {
|
||||||
|
"0": 62419,
|
||||||
|
"1": 3626
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"0": 62419,
|
||||||
|
"1": 3626
|
||||||
|
},
|
||||||
|
"accepted": 15768677,
|
||||||
|
"rejected": 97176,
|
||||||
|
"rhs": 130409139,
|
||||||
|
"provenance": {
|
||||||
|
"atol_x": 1e-09,
|
||||||
|
"atol_Pi": 1e-09,
|
||||||
|
"atol_L": 1e-09,
|
||||||
|
"rtol": 1e-09,
|
||||||
|
"min_step": 1e-12,
|
||||||
|
"max_step": 2.0,
|
||||||
|
"max_lookback_time": 6553.6,
|
||||||
|
"retry_lookback_increment": 6553.6,
|
||||||
|
"max_total_lookback_time": 26214.4,
|
||||||
|
"integrator": 1,
|
||||||
|
"initial_step": 0.1,
|
||||||
|
"initial_max_steps": 65536,
|
||||||
|
"threshold": 8.0,
|
||||||
|
"retry_step_increment": 65536,
|
||||||
|
"max_total_steps": 262144
|
||||||
|
},
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 162,
|
||||||
|
"0.5": 212,
|
||||||
|
"0.9": 328,
|
||||||
|
"0.99": 404,
|
||||||
|
"1": 520
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 1,
|
||||||
|
"0.9": 3,
|
||||||
|
"0.99": 4,
|
||||||
|
"1": 5
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 1421,
|
||||||
|
"0.5": 1799,
|
||||||
|
"0.9": 2597,
|
||||||
|
"0.99": 3129,
|
||||||
|
"1": 3941
|
||||||
|
},
|
||||||
|
"sha256": "ef7267074338192f8597b1f2a0300fd36da8e25441e064719c7ad586c481ae7a",
|
||||||
|
"triangle_sha256": "2a943902e9b1401a16bc40fc547c19077bb12e396080074393636ee30761b7b2",
|
||||||
|
"unique_film_positions": 66045,
|
||||||
|
"duplicate_film_positions": 0,
|
||||||
|
"requested_samples_including_nonpersistent_probes": 116308,
|
||||||
|
"initial_samples": 32776,
|
||||||
|
"refinement_samples_per_generation": [
|
||||||
|
32686,
|
||||||
|
7900,
|
||||||
|
13375,
|
||||||
|
24826,
|
||||||
|
4403,
|
||||||
|
261,
|
||||||
|
67,
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"trace_wall_seconds": 10.774,
|
||||||
|
"wall_seconds": 11.389317202148959
|
||||||
|
},
|
||||||
|
"r100_4k_hmax8": {
|
||||||
|
"vertices": 66045,
|
||||||
|
"triangles": 131338,
|
||||||
|
"outcomes": {
|
||||||
|
"0": 62419,
|
||||||
|
"1": 3626
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"0": 62419,
|
||||||
|
"1": 3626
|
||||||
|
},
|
||||||
|
"accepted": 10183020,
|
||||||
|
"rejected": 194781,
|
||||||
|
"rhs": 91991144,
|
||||||
|
"provenance": {
|
||||||
|
"atol_x": 1e-09,
|
||||||
|
"atol_Pi": 1e-09,
|
||||||
|
"atol_L": 1e-09,
|
||||||
|
"rtol": 1e-09,
|
||||||
|
"min_step": 1e-12,
|
||||||
|
"max_step": 8.0,
|
||||||
|
"max_lookback_time": 6553.6,
|
||||||
|
"retry_lookback_increment": 6553.6,
|
||||||
|
"max_total_lookback_time": 26214.4,
|
||||||
|
"integrator": 1,
|
||||||
|
"initial_step": 0.1,
|
||||||
|
"initial_max_steps": 65536,
|
||||||
|
"threshold": 8.0,
|
||||||
|
"retry_step_increment": 65536,
|
||||||
|
"max_total_steps": 262144
|
||||||
|
},
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 80,
|
||||||
|
"0.5": 127,
|
||||||
|
"0.9": 259,
|
||||||
|
"0.99": 337,
|
||||||
|
"1": 432
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 3,
|
||||||
|
"0.9": 5,
|
||||||
|
"0.99": 6,
|
||||||
|
"1": 7
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 868,
|
||||||
|
"0.5": 1204,
|
||||||
|
"0.9": 2114,
|
||||||
|
"0.99": 2646,
|
||||||
|
"1": 3318
|
||||||
|
},
|
||||||
|
"sha256": "b1897493b7fa5b88f86872e81d15ac876818a705fa0fefe8b1ee262da9de59bb",
|
||||||
|
"triangle_sha256": "2a943902e9b1401a16bc40fc547c19077bb12e396080074393636ee30761b7b2",
|
||||||
|
"unique_film_positions": 66045,
|
||||||
|
"duplicate_film_positions": 0,
|
||||||
|
"requested_samples_including_nonpersistent_probes": 116308,
|
||||||
|
"initial_samples": 32776,
|
||||||
|
"refinement_samples_per_generation": [
|
||||||
|
32686,
|
||||||
|
7900,
|
||||||
|
13375,
|
||||||
|
24826,
|
||||||
|
4403,
|
||||||
|
261,
|
||||||
|
67,
|
||||||
|
14
|
||||||
|
],
|
||||||
|
"trace_wall_seconds": 7.805000000000001,
|
||||||
|
"wall_seconds": 8.389249739935622
|
||||||
|
},
|
||||||
|
"comparison": {
|
||||||
|
"shared": 66045,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 7.954413592847793e-07,
|
||||||
|
"max_logg_difference": 3.471110204822381e-11,
|
||||||
|
"triangle_payload_identical": true
|
||||||
|
},
|
||||||
|
"relative_reduction": {
|
||||||
|
"accepted": 0.35422483446138187,
|
||||||
|
"rhs": 0.2945958795111745,
|
||||||
|
"wall_seconds": 0.2634106513116764,
|
||||||
|
"trace_wall_seconds": 0.27557081863746047
|
||||||
|
},
|
||||||
|
"cost_scope": "accepted/rejected/RHS sums cover final persistent vertices only; nonpersistent discarded refinement probes are not in v3 map. Do not interpret them as full-render executed RHS totals."
|
||||||
|
}
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
OMP_NUM_THREADS=16 OMP_DYNAMIC=FALSE /home/wyj/Code/C/GR_4d_raytracing/build/Release/schwarzschild_sky --integrator dp54 --width 3840 --height 2160 --look-ra-deg 262.5 --look-dec-deg -30 --fov-deg 45 --observer-radius 100 --coarse-cell-pixels 16 --refine-max-level 4 --refine-jacobian-min .2 --catalog /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/single_dim_star.csv --exposure 1 --tone-map reinhard --psf-min-y 1e-20 --psf-relative-tail 1e-4 --ode-min-step 1e-12 --ode-max-step 2 --verbose --lens-map-output /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax2.grlens --output /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax2.png
|
||||||
|
Blackbody LUT: 1024 CIE 1931 2-deg 1 nm-linear XYZ nodes, T=[670.146556, 101408.88] K, loaded assets/blackbody/cie1931_2deg_xyz_1024.grbblut in 0.000040 s; payload fnv1a64=0e39867b0e70a809
|
||||||
|
Blackbody backend: lut
|
||||||
|
PSF cache ready: 64x64 phases, radius 25 px, relative tail 1e-04, tail abs 1e-06, boundary 1e-07, build 0.250 s
|
||||||
|
Frame 0: integrator=dp54 step=0.1 max_steps=65536 threshold=8 atol=(x 1e-09, Pi 1e-09, L 1e-09) rtol=1e-09 bounds=[1e-12, 2] max_rejections=32 lookback=6553.6
|
||||||
|
Frame 0: tracing 32776 initial rays from 64800 mesh triangles...
|
||||||
|
Frame 0: initial ray trace finished in 2.562 s.
|
||||||
|
Frame 0: starting adaptive ray-trace refinement (max level 4)...
|
||||||
|
Frame 0: refinement generation 0 tracing 32686 samples from 32776 vertices and 64800 triangles.
|
||||||
|
Frame 0: refinement generation 0 finished; added 3014 vertices, now 35790 vertices and 70828 triangles.
|
||||||
|
Frame 0: refinement generation 1 tracing 7900 samples from 35790 vertices and 70828 triangles.
|
||||||
|
Frame 0: refinement generation 1 finished; added 4852 vertices, now 40642 vertices and 80532 triangles.
|
||||||
|
Frame 0: refinement generation 2 tracing 13375 samples from 40642 vertices and 80532 triangles.
|
||||||
|
Frame 0: refinement generation 2 finished; added 8889 vertices, now 49531 vertices and 98310 triangles.
|
||||||
|
Frame 0: refinement generation 3 tracing 24826 samples from 49531 vertices and 98310 triangles.
|
||||||
|
Frame 0: refinement generation 3 finished; added 16055 vertices, now 65586 vertices and 130420 triangles.
|
||||||
|
Frame 0: refinement generation 4 tracing 4403 samples from 65586 vertices and 130420 triangles.
|
||||||
|
Frame 0: refinement generation 4 finished; added 389 vertices, now 65975 vertices and 131198 triangles.
|
||||||
|
Frame 0: refinement generation 5 tracing 261 samples from 65975 vertices and 131198 triangles.
|
||||||
|
Frame 0: refinement generation 5 finished; added 58 vertices, now 66033 vertices and 131314 triangles.
|
||||||
|
Frame 0: refinement generation 6 tracing 67 samples from 66033 vertices and 131314 triangles.
|
||||||
|
Frame 0: refinement generation 6 finished; added 12 vertices, now 66045 vertices and 131338 triangles.
|
||||||
|
Frame 0: refinement generation 7 tracing 14 samples from 66045 vertices and 131338 triangles.
|
||||||
|
Frame 0: refinement generation 7 finished; added 0 vertices, now 66045 vertices and 131338 triangles.
|
||||||
|
Frame 0: adaptive ray-trace refinement finished in 8.212 s; 66045 vertices, 131338 triangles.
|
||||||
|
Boundary accounting: EEE=122456 DDD=5624 EED/EDD=3258 UUD/UDD=0 U+E=0 UUU=0 error=0; approx-black=0 (0 px^2), retries=0, budget-incomplete=0.
|
||||||
|
Frame 0 trace cost: accepted=15768677 rejected=97176 rhs=130409139 over 66045 vertices (saturated=0).
|
||||||
|
Wrote lens map: /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax2.grlens (66045 vertices, 131338 triangles)
|
||||||
|
Frame 0: traced 66045 lens vertices; starting catalog render.
|
||||||
|
Frame 0: finding and prefetching catalog tiles...
|
||||||
|
Frame 0: catalog prefetch finished (0 candidate tiles).
|
||||||
|
Frame 0: splatting 131338 lens triangles...
|
||||||
|
Frame 0: splat worker 1/16 started.
|
||||||
|
Frame 0: splat worker 1/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 started.
|
||||||
|
Frame 0: splat worker 8/16 started.
|
||||||
|
Frame 0: splat worker 8/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 started.
|
||||||
|
Frame 0: splat worker 13/16 started.
|
||||||
|
Frame 0: splat worker 3/16 started.
|
||||||
|
Frame 0: splat worker 6/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 started.
|
||||||
|
Frame 0: splat worker 11/16 started.
|
||||||
|
Frame 0: splat worker 7/16 started.
|
||||||
|
Frame 0: splat worker 7/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 started.
|
||||||
|
Frame 0: splat worker 15/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 started.
|
||||||
|
Frame 0: splat worker 8/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 started.
|
||||||
|
Frame 0: splat worker 4/16 started.
|
||||||
|
Frame 0: splat worker 13/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 started.
|
||||||
|
Frame 0: splat worker 5/16 started.
|
||||||
|
Frame 0: splat worker 5/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 started.
|
||||||
|
Frame 0: splat worker 16/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 finished after 8555 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 finished after 8230 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 finished after 8192 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 finished after 8468 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 finished after 8207 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 finished after 8824 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 finished after 8382 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 finished after 8004 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 finished after 9239 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 finished after 8561 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 finished after 8804 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 finished after 8429 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 finished after 4096 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 finished after 8201 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 finished after 8290 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 finished after 8856 local triangles.
|
||||||
|
Frame 0: catalog splatting finished in 0.1 s; writing image...
|
||||||
|
Rendered 1965 images from 1 catalog stars to /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax2.png (ok)
|
||||||
|
PSF splats: cached 0, cached wing-clipped 0, direct fallbacks 0, discarded below min-Y 1965
|
||||||
|
Warning: --psf-min-y discarded one or more PSF events.
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
OMP_NUM_THREADS=16 OMP_DYNAMIC=FALSE /home/wyj/Code/C/GR_4d_raytracing/build/Release/schwarzschild_sky --integrator dp54 --width 3840 --height 2160 --look-ra-deg 262.5 --look-dec-deg -30 --fov-deg 45 --observer-radius 100 --coarse-cell-pixels 16 --refine-max-level 4 --refine-jacobian-min .2 --catalog /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/single_dim_star.csv --exposure 1 --tone-map reinhard --psf-min-y 1e-20 --psf-relative-tail 1e-4 --ode-min-step 1e-12 --ode-max-step 8 --verbose --lens-map-output /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax8.grlens --output /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax8.png
|
||||||
|
Blackbody LUT: 1024 CIE 1931 2-deg 1 nm-linear XYZ nodes, T=[670.146556, 101408.88] K, loaded assets/blackbody/cie1931_2deg_xyz_1024.grbblut in 0.000041 s; payload fnv1a64=0e39867b0e70a809
|
||||||
|
Blackbody backend: lut
|
||||||
|
PSF cache ready: 64x64 phases, radius 25 px, relative tail 1e-04, tail abs 1e-06, boundary 1e-07, build 0.223 s
|
||||||
|
Frame 0: integrator=dp54 step=0.1 max_steps=65536 threshold=8 atol=(x 1e-09, Pi 1e-09, L 1e-09) rtol=1e-09 bounds=[1e-12, 8] max_rejections=32 lookback=6553.6
|
||||||
|
Frame 0: tracing 32776 initial rays from 64800 mesh triangles...
|
||||||
|
Frame 0: initial ray trace finished in 1.735 s.
|
||||||
|
Frame 0: starting adaptive ray-trace refinement (max level 4)...
|
||||||
|
Frame 0: refinement generation 0 tracing 32686 samples from 32776 vertices and 64800 triangles.
|
||||||
|
Frame 0: refinement generation 0 finished; added 3014 vertices, now 35790 vertices and 70828 triangles.
|
||||||
|
Frame 0: refinement generation 1 tracing 7900 samples from 35790 vertices and 70828 triangles.
|
||||||
|
Frame 0: refinement generation 1 finished; added 4852 vertices, now 40642 vertices and 80532 triangles.
|
||||||
|
Frame 0: refinement generation 2 tracing 13375 samples from 40642 vertices and 80532 triangles.
|
||||||
|
Frame 0: refinement generation 2 finished; added 8889 vertices, now 49531 vertices and 98310 triangles.
|
||||||
|
Frame 0: refinement generation 3 tracing 24826 samples from 49531 vertices and 98310 triangles.
|
||||||
|
Frame 0: refinement generation 3 finished; added 16055 vertices, now 65586 vertices and 130420 triangles.
|
||||||
|
Frame 0: refinement generation 4 tracing 4403 samples from 65586 vertices and 130420 triangles.
|
||||||
|
Frame 0: refinement generation 4 finished; added 389 vertices, now 65975 vertices and 131198 triangles.
|
||||||
|
Frame 0: refinement generation 5 tracing 261 samples from 65975 vertices and 131198 triangles.
|
||||||
|
Frame 0: refinement generation 5 finished; added 58 vertices, now 66033 vertices and 131314 triangles.
|
||||||
|
Frame 0: refinement generation 6 tracing 67 samples from 66033 vertices and 131314 triangles.
|
||||||
|
Frame 0: refinement generation 6 finished; added 12 vertices, now 66045 vertices and 131338 triangles.
|
||||||
|
Frame 0: refinement generation 7 tracing 14 samples from 66045 vertices and 131338 triangles.
|
||||||
|
Frame 0: refinement generation 7 finished; added 0 vertices, now 66045 vertices and 131338 triangles.
|
||||||
|
Frame 0: adaptive ray-trace refinement finished in 6.070 s; 66045 vertices, 131338 triangles.
|
||||||
|
Boundary accounting: EEE=122456 DDD=5624 EED/EDD=3258 UUD/UDD=0 U+E=0 UUU=0 error=0; approx-black=0 (0 px^2), retries=0, budget-incomplete=0.
|
||||||
|
Frame 0 trace cost: accepted=10183020 rejected=194781 rhs=91991144 over 66045 vertices (saturated=0).
|
||||||
|
Wrote lens map: /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax8.grlens (66045 vertices, 131338 triangles)
|
||||||
|
Frame 0: traced 66045 lens vertices; starting catalog render.
|
||||||
|
Frame 0: finding and prefetching catalog tiles...
|
||||||
|
Frame 0: catalog prefetch finished (0 candidate tiles).
|
||||||
|
Frame 0: splatting 131338 lens triangles...
|
||||||
|
Frame 0: splat worker 1/16 started.
|
||||||
|
Frame 0: splat worker 1/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 started.
|
||||||
|
Frame 0: splat worker 10/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 started.
|
||||||
|
Frame 0: splat worker 2/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 started.
|
||||||
|
Frame 0: splat worker 12/16 started.
|
||||||
|
Frame 0: splat worker 12/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 started.
|
||||||
|
Frame 0: splat worker 16/16 started.
|
||||||
|
Frame 0: splat worker 16/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 started.
|
||||||
|
Frame 0: splat worker 8/16 started.
|
||||||
|
Frame 0: splat worker 16/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 started.
|
||||||
|
Frame 0: splat worker 5/16 started.
|
||||||
|
Frame 0: splat worker 6/16 started.
|
||||||
|
Frame 0: splat worker 6/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 started.
|
||||||
|
Frame 0: splat worker 7/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 started.
|
||||||
|
Frame 0: splat worker 3/16 started.
|
||||||
|
Frame 0: splat worker 8/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 started.
|
||||||
|
Frame 0: splat worker 8/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 8 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 16 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 32 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 64 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 128 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 256 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 512 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 1024 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 2048 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 reached 4096 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 reached 8192 local triangles.
|
||||||
|
Frame 0: splat worker 10/16 finished after 10255 local triangles.
|
||||||
|
Frame 0: splat worker 13/16 finished after 7729 local triangles.
|
||||||
|
Frame 0: splat worker 14/16 finished after 8310 local triangles.
|
||||||
|
Frame 0: splat worker 3/16 finished after 8102 local triangles.
|
||||||
|
Frame 0: splat worker 12/16 finished after 5601 local triangles.
|
||||||
|
Frame 0: splat worker 2/16 finished after 6132 local triangles.
|
||||||
|
Frame 0: splat worker 7/16 finished after 8294 local triangles.
|
||||||
|
Frame 0: splat worker 6/16 finished after 7791 local triangles.
|
||||||
|
Frame 0: splat worker 5/16 finished after 8901 local triangles.
|
||||||
|
Frame 0: splat worker 4/16 finished after 8159 local triangles.
|
||||||
|
Frame 0: splat worker 1/16 finished after 7930 local triangles.
|
||||||
|
Frame 0: splat worker 16/16 finished after 12209 local triangles.
|
||||||
|
Frame 0: splat worker 15/16 finished after 7871 local triangles.
|
||||||
|
Frame 0: splat worker 9/16 finished after 7811 local triangles.
|
||||||
|
Frame 0: splat worker 11/16 finished after 8075 local triangles.
|
||||||
|
Frame 0: splat worker 8/16 finished after 8168 local triangles.
|
||||||
|
Frame 0: catalog splatting finished in 0.1 s; writing image...
|
||||||
|
Rendered 1954 images from 1 catalog stars to /home/wyj/Code/C/GR_4d_raytracing/local/step_bounds_4k/r100_4k_hmax8.png (ok)
|
||||||
|
PSF splats: cached 0, cached wing-clipped 0, direct fallbacks 0, discarded below min-Y 1954
|
||||||
|
Warning: --psf-min-y discarded one or more PSF events.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"binary_sha256": "72ba409cd60bc72a7f0ca16f736cab6be6d4ab3f42a11d00647eeb03cc7a7e2a",
|
||||||
|
"utc": "2026-10-05T22:19:23Z",
|
||||||
|
"source_sha256": {
|
||||||
|
"src/main.c": "6cf3f6354b52b5eb029e1f3605c403c4161bb3df5d4202a47b97409318358ff9",
|
||||||
|
"src/geodesic.c": "25f24a2e1c9ce49508fed230dfb3f6d9986e92bb4a5e6347bb2356ac0ee5fffa",
|
||||||
|
"src/frame.c": "317cf2a777be139a2cab6a1b9f00094b7834fbb0382389960526ee3281ca55bf"
|
||||||
|
},
|
||||||
|
"catalog": "one negligible synthetic point; no survey catalog",
|
||||||
|
"scope": "README R100 45-degree 3840x2160 coarse16 refine4 jacobian0.2",
|
||||||
|
"threads": 16,
|
||||||
|
"max_attempts": 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
r100_4k_hmax2 {"vertices": 66045, "triangles": 131338, "outcomes": {"0": 62419, "1": 3626}, "reasons": {"0": 62419, "1": 3626}, "accepted": 15768677, "rejected": 97176, "rhs": 130409139, "provenance": {"atol_x": 1e-09, "atol_Pi": 1e-09, "atol_L": 1e-09, "rtol": 1e-09, "min_step": 1e-12, "max_step": 2.0, "max_lookback_time": 6553.6, "retry_lookback_increment": 6553.6, "max_total_lookback_time": 26214.4, "integrator": 1, "initial_step": 0.1, "initial_max_steps": 65536, "threshold": 8.0, "retry_step_increment": 65536, "max_total_steps": 262144}, "accepted_percentiles": {"0": 162, "0.5": 212, "0.9": 328, "0.99": 404, "1": 520}, "rejected_percentiles": {"0": 0, "0.5": 1, "0.9": 3, "0.99": 4, "1": 5}, "rhs_percentiles": {"0": 1421, "0.5": 1799, "0.9": 2597, "0.99": 3129, "1": 3941}, "sha256": "ef7267074338192f8597b1f2a0300fd36da8e25441e064719c7ad586c481ae7a", "unique_film_positions": 66045, "duplicate_film_positions": 0, "wall_seconds": 11.389317202148959}
|
||||||
|
r100_4k_hmax8 {"vertices": 66045, "triangles": 131338, "outcomes": {"0": 62419, "1": 3626}, "reasons": {"0": 62419, "1": 3626}, "accepted": 10183020, "rejected": 194781, "rhs": 91991144, "provenance": {"atol_x": 1e-09, "atol_Pi": 1e-09, "atol_L": 1e-09, "rtol": 1e-09, "min_step": 1e-12, "max_step": 8.0, "max_lookback_time": 6553.6, "retry_lookback_increment": 6553.6, "max_total_lookback_time": 26214.4, "integrator": 1, "initial_step": 0.1, "initial_max_steps": 65536, "threshold": 8.0, "retry_step_increment": 65536, "max_total_steps": 262144}, "accepted_percentiles": {"0": 80, "0.5": 127, "0.9": 259, "0.99": 337, "1": 432}, "rejected_percentiles": {"0": 0, "0.5": 3, "0.9": 5, "0.99": 6, "1": 7}, "rhs_percentiles": {"0": 868, "0.5": 1204, "0.9": 2114, "0.99": 2646, "1": 3318}, "sha256": "b1897493b7fa5b88f86872e81d15ac876818a705fa0fefe8b1ee262da9de59bb", "unique_film_positions": 66045, "duplicate_film_positions": 0, "wall_seconds": 8.389249739935622}
|
||||||
|
comparison {"shared": 66045, "only_a": 0, "only_b": 0, "terminal_mismatches": 0, "max_sky_angle": 7.954413592847793e-07, "max_logg_difference": 3.471110204822381e-11}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
camera,dir,theta,cfg,outcome,reason,end_id,stop_t,steps,rejected,rhs,nx,ny,nz,g,thr,L,L0
|
||||||
|
r30_inward,0,0.16812279429621627,ref_tol1e-12_h0.25,1,1,4294967295,-142.17574796859728,2081,0,14854,0,0,0,0,8.0000000000000195,8.0658840965825682,0.065884096582549498
|
||||||
|
r30_inward,0,0.16812279429621627,ref_tol1e-13_h0.125,1,1,4294967295,-142.17574845681202,3332,0,23611,0,0,0,0,8.0000000000000249,8.0658840965825735,0.065884096582549498
|
||||||
|
r30_inward,0,0.16812279429621627,tol1e-11_h2,1,1,4294967295,-142.17574172483768,1304,0,9415,0,0,0,0,8.0000000000000266,8.0658840965825753,0.065884096582549498
|
||||||
|
r30_inward,0,0.16812279429621627,tol1e-11_h8,1,1,4294967295,-142.17574172483768,1304,0,9415,0,0,0,0,8.0000000000000266,8.0658840965825753,0.065884096582549498
|
||||||
|
r30_inward,1,0.16812289429621627,ref_tol1e-12_h0.25,1,1,4294967295,-225.85293500418322,3746,0,26509,0,0,0,0,8.0000000000000338,8.0658840955358357,0.065884095535802364
|
||||||
|
r30_inward,1,0.16812289429621627,ref_tol1e-13_h0.125,1,1,4294967295,-238.90906331559862,6388,0,45003,0,0,0,0,8.000000000000016,8.065884095535818,0.065884095535802364
|
||||||
|
r30_inward,1,0.16812289429621627,tol1e-11_h2,1,1,4294967295,-212.59582609170599,2180,0,15547,0,0,0,0,8.0000000000000071,8.0658840955358091,0.065884095535802364
|
||||||
|
r30_inward,1,0.16812289429621627,tol1e-11_h8,1,1,4294967295,-212.59582609170599,2180,0,15547,0,0,0,0,8.0000000000000071,8.0658840955358091,0.065884095535802364
|
||||||
|
r30_inward,2,0.16812299429621627,ref_tol1e-12_h0.25,0,0,0,-370.18047830118235,2790,1,19831,-0.35873499147611138,-6.5068267720987458e-16,-0.9334394495041628,1.0350983390130453,nan,-0.038385896473527227,0.065884094489054593
|
||||||
|
r30_inward,2,0.16812299429621627,ref_tol1e-13_h0.125,0,0,0,-370.1804778092,4857,1,34300,-0.35873507984449715,-6.5068265353608199e-16,-0.93343941554284182,1.035098339013504,nan,-0.038385896473972475,0.065884094489054593
|
||||||
|
r30_inward,2,0.16812299429621627,tol1e-11_h2,0,0,0,-370.18048452857704,1299,1,9387,-0.3587338729380895,-6.5068297686427377e-16,-0.93343987937458439,1.0350983390054869,nan,-0.038385896466199748,0.065884094489054593
|
||||||
|
r30_inward,2,0.16812299429621627,tol1e-11_h8,0,0,0,-370.1804845285946,1257,1,9100,-0.35873387293809145,-6.5068297686427416e-16,-0.93343987937458361,1.035098339005424,nan,-0.038385896466138665,0.065884094489054593
|
||||||
|
r100_inward,0,0.051461896376274734,ref_tol1e-12_h0.25,1,1,4294967295,-211.027405235164,2252,0,16051,0,0,0,0,8.0000000000000266,8.0199767087115159,0.01997670871149013
|
||||||
|
r100_inward,0,0.051461896376274734,ref_tol1e-13_h0.125,1,1,4294967295,-211.02740538583069,3727,0,26376,0,0,0,0,8.0000000000000142,8.0199767087115035,0.01997670871149013
|
||||||
|
r100_inward,0,0.051461896376274734,tol1e-11_h2,1,1,4294967295,-211.02740354768991,1292,0,9331,0,0,0,0,8.0000000000000533,8.0199767087115426,0.01997670871149013
|
||||||
|
r100_inward,0,0.051461896376274734,tol1e-11_h8,1,1,4294967295,-211.02740354768991,1292,0,9331,0,0,0,0,8.0000000000000533,8.0199767087115426,0.01997670871149013
|
||||||
|
r100_inward,1,0.051461996376274736,ref_tol1e-12_h0.25,1,1,4294967295,-301.07740508539132,4045,0,28602,0,0,0,0,8.0000000000000018,8.0199767086106277,0.019976708610626077
|
||||||
|
r100_inward,1,0.051461996376274736,ref_tol1e-13_h0.125,1,1,4294967295,-313.77734009633099,6986,0,49189,0,0,0,0,8.0000000000000018,8.0199767086106277,0.019976708610626077
|
||||||
|
r100_inward,1,0.051461996376274736,tol1e-11_h2,1,1,4294967295,-288.21364790845217,2256,0,16079,0,0,0,0,8.0000000000000639,8.0199767086106899,0.019976708610626077
|
||||||
|
r100_inward,1,0.051461996376274736,tol1e-11_h8,1,1,4294967295,-288.21364790845217,2256,0,16079,0,0,0,0,8.0000000000000639,8.0199767086106899,0.019976708610626077
|
||||||
|
r100_inward,2,0.051462096376274739,ref_tol1e-12_h0.25,0,0,0,-439.31355204311825,2969,0,21077,-0.99110324423183982,-3.1326762563025509e-16,-0.13309530146899301,1.0101525445517785,nan,-0.013990814384499865,0.019976708509762027
|
||||||
|
r100_inward,2,0.051462096376274739,ref_tol1e-13_h0.125,0,0,0,-439.31355190087947,5265,0,37149,-0.99110324787406912,-3.132675617927086e-16,-0.13309527434688151,1.010152544552184,nan,-0.013990814384902493,0.019976708509762027
|
||||||
|
r100_inward,2,0.051462096376274739,tol1e-11_h2,0,0,0,-439.31355372933643,1291,1,9338,-0.99110320105936889,-3.1326838231562615e-16,-0.13309562295534913,1.010152544545182,nan,-0.013990814377948021,0.019976708509762027
|
||||||
|
r100_inward,2,0.051462096376274739,tol1e-11_h8,0,0,0,-439.31355372935258,1250,1,9051,-0.991103201059369,-3.1326838231562231e-16,-0.13309562295534744,1.0101525445451216,nan,-0.013990814377887956,0.019976708509762027
|
||||||
|
r2p1_outward,0,0.57037671003940071,ref_tol1e-12_h0.25,0,0,0,-333.45070432558816,2639,1,18774,-0.30976840652656795,0,-0.95081203942629522,4.5825756949539365,nan,-1.5261506795942201,-0.42981831573151047
|
||||||
|
r2p1_outward,0,0.57037671003940071,ref_tol1e-13_h0.125,0,0,0,-333.45070506871724,4589,2,32431,-0.30976827139480229,0,-0.95081208345133916,4.5825756949557528,nan,-1.5261506795946143,-0.42981831573151047
|
||||||
|
r2p1_outward,0,0.57037671003940071,tol1e-11_h2,0,0,0,-333.45070071486469,1210,2,8778,-0.30976906608911198,0,-0.95081182454483582,4.5825756949192931,nan,-1.5261506795866686,-0.42981831573151047
|
||||||
|
r2p1_outward,0,0.57037671003940071,tol1e-11_h8,0,0,0,-333.45070071488124,1169,2,8491,-0.30976906647032454,0,-0.95081182442063883,4.5825756949190151,nan,-1.5261506795866076,-0.42981831573151047
|
||||||
|
r2p1_outward,1,0.57037681003940066,ref_tol1e-12_h0.25,0,0,0,-414.94010328784253,4263,2,30149,0.3336576345143959,0,0.94269432104487505,4.5825756949507124,nan,-1.5261506795930104,-0.42981805651739968
|
||||||
|
r2p1_outward,1,0.57037681003940066,ref_tol1e-13_h0.125,0,0,0,-427.08073320404128,7560,1,53221,-0.91087431940825703,0,-0.41268386719442363,4.5825756949554943,nan,-1.5261506795940556,-0.42981805651739968
|
||||||
|
r2p1_outward,1,0.57037681003940066,tol1e-11_h2,0,0,0,-406.06581257014602,2120,2,15141,0.88820167266587602,0,-0.45945379383953305,4.58257569487448,nan,-1.5261506795763404,-0.42981805651739968
|
||||||
|
r2p1_outward,1,0.57037681003940066,tol1e-11_h8,0,0,0,-406.06581257016262,2078,2,14854,0.88817826517728515,0,-0.4594990416384655,4.5825756948742002,nan,-1.5261506795762789,-0.42981805651739968
|
||||||
|
r2p1_outward,2,0.57037691003940061,ref_tol1e-12_h0.25,1,1,4294967295,-109.41561097431348,1950,1,13944,0,0,0,0,8.0000000000000195,7.5701822026967047,-0.42981779730331554
|
||||||
|
r2p1_outward,2,0.57037691003940061,ref_tol1e-13_h0.125,1,1,4294967295,-109.41561022532379,3098,1,21980,0,0,0,0,8.000000000000016,7.5701822026967012,-0.42981779730331554
|
||||||
|
r2p1_outward,2,0.57037691003940061,tol1e-11_h2,1,1,4294967295,-109.41561457850582,1228,1,8890,0,0,0,0,8.0000000000000195,7.5701822026967038,-0.42981779730331554
|
||||||
|
r2p1_outward,2,0.57037691003940061,tol1e-11_h8,1,1,4294967295,-109.41561457850582,1228,1,8890,0,0,0,0,8.0000000000000195,7.5701822026967038,-0.42981779730331554
|
||||||
|
@@ -0,0 +1,96 @@
|
|||||||
|
### building critical_ref_check
|
||||||
|
+ cc -std=c11 -O2 -Wall -Wextra -Wpedantic -I/home/wyj/Code/C/GR_4d_raytracing/src /home/wyj/Code/C/GR_4d_raytracing/benchmarks/adaptive_step_bounds_2026-10-05/critical_ref_check.c /home/wyj/Code/C/GR_4d_raytracing/src/geodesic.c /home/wyj/Code/C/GR_4d_raytracing/src/asymptotic.c /home/wyj/Code/C/GR_4d_raytracing/src/asymptotic_schwarzschild.c /home/wyj/Code/C/GR_4d_raytracing/src/spacetime_common.c /home/wyj/Code/C/GR_4d_raytracing/src/observer.c -lm -o /tmp/opencode/step_bounds/critical_ref_check
|
||||||
|
+ echo '### command: critical_ref_check'
|
||||||
|
### command: critical_ref_check
|
||||||
|
+ /tmp/opencode/step_bounds/critical_ref_check
|
||||||
|
RAW camera=r30_inward dir=0 theta=0.16812279429621627 cfg=ref_tol1e-12_h0.25 outcome=1 reason=1 end=4294967295 stop_t=-142.17574796859728 steps=2081 rejected=0 rhs=14854 g=0 thr=8.0000000000000195 L=8.0658840965825682 L0=0.065884096582549498 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r30_inward dir=0 theta=0.16812279429621627 cfg=ref_tol1e-13_h0.125 outcome=1 reason=1 end=4294967295 stop_t=-142.17574845681202 steps=3332 rejected=0 rhs=23611 g=0 thr=8.0000000000000249 L=8.0658840965825735 L0=0.065884096582549498 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r30_inward dir=0 theta=0.16812279429621627 cfg=tol1e-11_h2 outcome=1 reason=1 end=4294967295 stop_t=-142.17574172483768 steps=1304 rejected=0 rhs=9415 g=0 thr=8.0000000000000266 L=8.0658840965825753 L0=0.065884096582549498 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r30_inward dir=0 theta=0.16812279429621627 cfg=tol1e-11_h8 outcome=1 reason=1 end=4294967295 stop_t=-142.17574172483768 steps=1304 rejected=0 rhs=9415 g=0 thr=8.0000000000000266 L=8.0658840965825753 L0=0.065884096582549498 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r30_inward dir=1 theta=0.16812289429621627 cfg=ref_tol1e-12_h0.25 outcome=1 reason=1 end=4294967295 stop_t=-225.85293500418322 steps=3746 rejected=0 rhs=26509 g=0 thr=8.0000000000000338 L=8.0658840955358357 L0=0.065884095535802364 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r30_inward dir=1 theta=0.16812289429621627 cfg=ref_tol1e-13_h0.125 outcome=1 reason=1 end=4294967295 stop_t=-238.90906331559862 steps=6388 rejected=0 rhs=45003 g=0 thr=8.000000000000016 L=8.065884095535818 L0=0.065884095535802364 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r30_inward dir=1 theta=0.16812289429621627 cfg=tol1e-11_h2 outcome=1 reason=1 end=4294967295 stop_t=-212.59582609170599 steps=2180 rejected=0 rhs=15547 g=0 thr=8.0000000000000071 L=8.0658840955358091 L0=0.065884095535802364 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r30_inward dir=1 theta=0.16812289429621627 cfg=tol1e-11_h8 outcome=1 reason=1 end=4294967295 stop_t=-212.59582609170599 steps=2180 rejected=0 rhs=15547 g=0 thr=8.0000000000000071 L=8.0658840955358091 L0=0.065884095535802364 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r30_inward dir=2 theta=0.16812299429621627 cfg=ref_tol1e-12_h0.25 outcome=0 reason=0 end=0 stop_t=-370.18047830118235 steps=2790 rejected=1 rhs=19831 g=1.0350983390130453 thr=nan L=-0.038385896473527227 L0=0.065884094489054593 nx=-0.35873499147611138 ny=-6.5068267720987458e-16 nz=-0.9334394495041628
|
||||||
|
RAW camera=r30_inward dir=2 theta=0.16812299429621627 cfg=ref_tol1e-13_h0.125 outcome=0 reason=0 end=0 stop_t=-370.1804778092 steps=4857 rejected=1 rhs=34300 g=1.035098339013504 thr=nan L=-0.038385896473972475 L0=0.065884094489054593 nx=-0.35873507984449715 ny=-6.5068265353608199e-16 nz=-0.93343941554284182
|
||||||
|
RAW camera=r30_inward dir=2 theta=0.16812299429621627 cfg=tol1e-11_h2 outcome=0 reason=0 end=0 stop_t=-370.18048452857704 steps=1299 rejected=1 rhs=9387 g=1.0350983390054869 thr=nan L=-0.038385896466199748 L0=0.065884094489054593 nx=-0.3587338729380895 ny=-6.5068297686427377e-16 nz=-0.93343987937458439
|
||||||
|
RAW camera=r30_inward dir=2 theta=0.16812299429621627 cfg=tol1e-11_h8 outcome=0 reason=0 end=0 stop_t=-370.1804845285946 steps=1257 rejected=1 rhs=9100 g=1.035098339005424 thr=nan L=-0.038385896466138665 L0=0.065884094489054593 nx=-0.35873387293809145 ny=-6.5068297686427416e-16 nz=-0.93343987937458361
|
||||||
|
RAW camera=r100_inward dir=0 theta=0.051461896376274734 cfg=ref_tol1e-12_h0.25 outcome=1 reason=1 end=4294967295 stop_t=-211.027405235164 steps=2252 rejected=0 rhs=16051 g=0 thr=8.0000000000000266 L=8.0199767087115159 L0=0.01997670871149013 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r100_inward dir=0 theta=0.051461896376274734 cfg=ref_tol1e-13_h0.125 outcome=1 reason=1 end=4294967295 stop_t=-211.02740538583069 steps=3727 rejected=0 rhs=26376 g=0 thr=8.0000000000000142 L=8.0199767087115035 L0=0.01997670871149013 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r100_inward dir=0 theta=0.051461896376274734 cfg=tol1e-11_h2 outcome=1 reason=1 end=4294967295 stop_t=-211.02740354768991 steps=1292 rejected=0 rhs=9331 g=0 thr=8.0000000000000533 L=8.0199767087115426 L0=0.01997670871149013 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r100_inward dir=0 theta=0.051461896376274734 cfg=tol1e-11_h8 outcome=1 reason=1 end=4294967295 stop_t=-211.02740354768991 steps=1292 rejected=0 rhs=9331 g=0 thr=8.0000000000000533 L=8.0199767087115426 L0=0.01997670871149013 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r100_inward dir=1 theta=0.051461996376274736 cfg=ref_tol1e-12_h0.25 outcome=1 reason=1 end=4294967295 stop_t=-301.07740508539132 steps=4045 rejected=0 rhs=28602 g=0 thr=8.0000000000000018 L=8.0199767086106277 L0=0.019976708610626077 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r100_inward dir=1 theta=0.051461996376274736 cfg=ref_tol1e-13_h0.125 outcome=1 reason=1 end=4294967295 stop_t=-313.77734009633099 steps=6986 rejected=0 rhs=49189 g=0 thr=8.0000000000000018 L=8.0199767086106277 L0=0.019976708610626077 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r100_inward dir=1 theta=0.051461996376274736 cfg=tol1e-11_h2 outcome=1 reason=1 end=4294967295 stop_t=-288.21364790845217 steps=2256 rejected=0 rhs=16079 g=0 thr=8.0000000000000639 L=8.0199767086106899 L0=0.019976708610626077 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r100_inward dir=1 theta=0.051461996376274736 cfg=tol1e-11_h8 outcome=1 reason=1 end=4294967295 stop_t=-288.21364790845217 steps=2256 rejected=0 rhs=16079 g=0 thr=8.0000000000000639 L=8.0199767086106899 L0=0.019976708610626077 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r100_inward dir=2 theta=0.051462096376274739 cfg=ref_tol1e-12_h0.25 outcome=0 reason=0 end=0 stop_t=-439.31355204311825 steps=2969 rejected=0 rhs=21077 g=1.0101525445517785 thr=nan L=-0.013990814384499865 L0=0.019976708509762027 nx=-0.99110324423183982 ny=-3.1326762563025509e-16 nz=-0.13309530146899301
|
||||||
|
RAW camera=r100_inward dir=2 theta=0.051462096376274739 cfg=ref_tol1e-13_h0.125 outcome=0 reason=0 end=0 stop_t=-439.31355190087947 steps=5265 rejected=0 rhs=37149 g=1.010152544552184 thr=nan L=-0.013990814384902493 L0=0.019976708509762027 nx=-0.99110324787406912 ny=-3.132675617927086e-16 nz=-0.13309527434688151
|
||||||
|
RAW camera=r100_inward dir=2 theta=0.051462096376274739 cfg=tol1e-11_h2 outcome=0 reason=0 end=0 stop_t=-439.31355372933643 steps=1291 rejected=1 rhs=9338 g=1.010152544545182 thr=nan L=-0.013990814377948021 L0=0.019976708509762027 nx=-0.99110320105936889 ny=-3.1326838231562615e-16 nz=-0.13309562295534913
|
||||||
|
RAW camera=r100_inward dir=2 theta=0.051462096376274739 cfg=tol1e-11_h8 outcome=0 reason=0 end=0 stop_t=-439.31355372935258 steps=1250 rejected=1 rhs=9051 g=1.0101525445451216 thr=nan L=-0.013990814377887956 L0=0.019976708509762027 nx=-0.991103201059369 ny=-3.1326838231562231e-16 nz=-0.13309562295534744
|
||||||
|
RAW camera=r2p1_outward dir=0 theta=0.57037671003940071 cfg=ref_tol1e-12_h0.25 outcome=0 reason=0 end=0 stop_t=-333.45070432558816 steps=2639 rejected=1 rhs=18774 g=4.5825756949539365 thr=nan L=-1.5261506795942201 L0=-0.42981831573151047 nx=-0.30976840652656795 ny=0 nz=-0.95081203942629522
|
||||||
|
RAW camera=r2p1_outward dir=0 theta=0.57037671003940071 cfg=ref_tol1e-13_h0.125 outcome=0 reason=0 end=0 stop_t=-333.45070506871724 steps=4589 rejected=2 rhs=32431 g=4.5825756949557528 thr=nan L=-1.5261506795946143 L0=-0.42981831573151047 nx=-0.30976827139480229 ny=0 nz=-0.95081208345133916
|
||||||
|
RAW camera=r2p1_outward dir=0 theta=0.57037671003940071 cfg=tol1e-11_h2 outcome=0 reason=0 end=0 stop_t=-333.45070071486469 steps=1210 rejected=2 rhs=8778 g=4.5825756949192931 thr=nan L=-1.5261506795866686 L0=-0.42981831573151047 nx=-0.30976906608911198 ny=0 nz=-0.95081182454483582
|
||||||
|
RAW camera=r2p1_outward dir=0 theta=0.57037671003940071 cfg=tol1e-11_h8 outcome=0 reason=0 end=0 stop_t=-333.45070071488124 steps=1169 rejected=2 rhs=8491 g=4.5825756949190151 thr=nan L=-1.5261506795866076 L0=-0.42981831573151047 nx=-0.30976906647032454 ny=0 nz=-0.95081182442063883
|
||||||
|
RAW camera=r2p1_outward dir=1 theta=0.57037681003940066 cfg=ref_tol1e-12_h0.25 outcome=0 reason=0 end=0 stop_t=-414.94010328784253 steps=4263 rejected=2 rhs=30149 g=4.5825756949507124 thr=nan L=-1.5261506795930104 L0=-0.42981805651739968 nx=0.3336576345143959 ny=0 nz=0.94269432104487505
|
||||||
|
RAW camera=r2p1_outward dir=1 theta=0.57037681003940066 cfg=ref_tol1e-13_h0.125 outcome=0 reason=0 end=0 stop_t=-427.08073320404128 steps=7560 rejected=1 rhs=53221 g=4.5825756949554943 thr=nan L=-1.5261506795940556 L0=-0.42981805651739968 nx=-0.91087431940825703 ny=0 nz=-0.41268386719442363
|
||||||
|
RAW camera=r2p1_outward dir=1 theta=0.57037681003940066 cfg=tol1e-11_h2 outcome=0 reason=0 end=0 stop_t=-406.06581257014602 steps=2120 rejected=2 rhs=15141 g=4.58257569487448 thr=nan L=-1.5261506795763404 L0=-0.42981805651739968 nx=0.88820167266587602 ny=0 nz=-0.45945379383953305
|
||||||
|
RAW camera=r2p1_outward dir=1 theta=0.57037681003940066 cfg=tol1e-11_h8 outcome=0 reason=0 end=0 stop_t=-406.06581257016262 steps=2078 rejected=2 rhs=14854 g=4.5825756948742002 thr=nan L=-1.5261506795762789 L0=-0.42981805651739968 nx=0.88817826517728515 ny=0 nz=-0.4594990416384655
|
||||||
|
RAW camera=r2p1_outward dir=2 theta=0.57037691003940061 cfg=ref_tol1e-12_h0.25 outcome=1 reason=1 end=4294967295 stop_t=-109.41561097431348 steps=1950 rejected=1 rhs=13944 g=0 thr=8.0000000000000195 L=7.5701822026967047 L0=-0.42981779730331554 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r2p1_outward dir=2 theta=0.57037691003940061 cfg=ref_tol1e-13_h0.125 outcome=1 reason=1 end=4294967295 stop_t=-109.41561022532379 steps=3098 rejected=1 rhs=21980 g=0 thr=8.000000000000016 L=7.5701822026967012 L0=-0.42981779730331554 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r2p1_outward dir=2 theta=0.57037691003940061 cfg=tol1e-11_h2 outcome=1 reason=1 end=4294967295 stop_t=-109.41561457850582 steps=1228 rejected=1 rhs=8890 g=0 thr=8.0000000000000195 L=7.5701822026967038 L0=-0.42981779730331554 nx=0 ny=0 nz=0
|
||||||
|
RAW camera=r2p1_outward dir=2 theta=0.57037691003940061 cfg=tol1e-11_h8 outcome=1 reason=1 end=4294967295 stop_t=-109.41561457850582 steps=1228 rejected=1 rhs=8890 g=0 thr=8.0000000000000195 L=7.5701822026967038 L0=-0.42981779730331554 nx=0 ny=0 nz=0
|
||||||
|
CAPAIR camera=r30_inward dir=0 theta=0.16812279429621627 pair=ref_vs_tighter class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=4.8821473797033832e-07 dthr=-5.3290705182007514e-15 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r30_inward dir=0 theta=0.16812279429621627 pair=h2_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=0 dthr=0 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r30_inward dir=0 theta=0.16812279429621627 pair=ref_vs_h2 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-6.2437596000108897e-06 dthr=-7.1054273576010019e-15 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r30_inward dir=0 theta=0.16812279429621627 pair=ref_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-6.2437596000108897e-06 dthr=-7.1054273576010019e-15 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r30_inward dir=1 theta=0.16812289429621627 pair=ref_vs_tighter class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=13.056128311415392 dthr=1.7763568394002505e-14 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r30_inward dir=1 theta=0.16812289429621627 pair=h2_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=0 dthr=0 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r30_inward dir=1 theta=0.16812289429621627 pair=ref_vs_h2 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-13.257108912477236 dthr=2.6645352591003757e-14 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r30_inward dir=1 theta=0.16812289429621627 pair=ref_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-13.257108912477236 dthr=2.6645352591003757e-14 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r30_inward dir=2 theta=0.16812299429621627 pair=ref_vs_tighter class=ESC/ESC same=1 dn_ang=9.4669651562462453e-08 dgrel=4.4320103143036249e-13 dstop_t=-4.9198234819414211e-07 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r30_inward dir=2 theta=0.16812299429621627 pair=h2_vs_h8 class=ESC/ESC same=1 dn_ang=2.0539125955565396e-15 dgrel=6.0618177144533547e-14 dstop_t=1.7564616427989677e-11 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r30_inward dir=2 theta=0.16812299429621627 pair=ref_vs_h2 class=ESC/ESC same=1 dn_ang=1.198297077398556e-06 dgrel=7.3021588775645796e-12 dstop_t=6.2273946923596668e-06 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r30_inward dir=2 theta=0.16812299429621627 pair=ref_vs_h8 class=ESC/ESC same=1 dn_ang=1.1982970752891323e-06 dgrel=7.3627770547091131e-12 dstop_t=6.2274122569760948e-06 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r100_inward dir=0 theta=0.051461896376274734 pair=ref_vs_tighter class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=1.5066669334373728e-07 dthr=1.2434497875801753e-14 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r100_inward dir=0 theta=0.051461896376274734 pair=h2_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=0 dthr=0 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r100_inward dir=0 theta=0.051461896376274734 pair=ref_vs_h2 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-1.6874740822458989e-06 dthr=-2.6645352591003757e-14 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r100_inward dir=0 theta=0.051461896376274734 pair=ref_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-1.6874740822458989e-06 dthr=-2.6645352591003757e-14 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r100_inward dir=1 theta=0.051461996376274736 pair=ref_vs_tighter class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=12.699935010939669 dthr=0 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r100_inward dir=1 theta=0.051461996376274736 pair=h2_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=0 dthr=0 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r100_inward dir=1 theta=0.051461996376274736 pair=ref_vs_h2 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-12.863757176939146 dthr=-6.2172489379008766e-14 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r100_inward dir=1 theta=0.051461996376274736 pair=ref_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-12.863757176939146 dthr=-6.2172489379008766e-14 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r100_inward dir=2 theta=0.051462096376274739 pair=ref_vs_tighter class=ESC/ESC same=1 dn_ang=2.7365576305005138e-08 dgrel=4.0134562340199409e-13 dstop_t=-1.4223877542463015e-07 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r100_inward dir=2 theta=0.051462096376274739 pair=h2_vs_h8 class=ESC/ESC same=1 dn_ang=1.6930901125533633e-15 dgrel=5.9729998724833422e-14 dstop_t=1.6143530956469476e-11 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r100_inward dir=2 theta=0.051462096376274739 pair=ref_vs_h2 class=ESC/ESC same=1 dn_ang=3.243722235535319e-07 dgrel=6.5301097862402457e-12 dstop_t=1.6862181837495882e-06 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r100_inward dir=2 theta=0.051462096376274739 pair=ref_vs_h8 class=ESC/ESC same=1 dn_ang=3.2437222186044184e-07 dgrel=6.5900618295700042e-12 dstop_t=1.6862343272805447e-06 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=0 theta=0.57037671003940071 pair=ref_vs_tighter class=ESC/ESC same=1 dn_ang=1.4212247739786624e-07 dgrel=3.9634961979118088e-13 dstop_t=7.4312907827334129e-07 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=0 theta=0.57037671003940071 pair=h2_vs_h8 class=ESC/ESC same=1 dn_ang=4.0093378617100928e-10 dgrel=6.0618177144533547e-14 dstop_t=1.6541434888495132e-11 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=0 theta=0.57037671003940071 pair=ref_vs_h2 class=ESC/ESC same=1 dn_ang=6.9368349486792499e-07 dgrel=7.5597306192776159e-12 dstop_t=-3.6107234677729139e-06 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=0 theta=0.57037671003940071 pair=ref_vs_h8 class=ESC/ESC same=1 dn_ang=6.9408442870960736e-07 dgrel=7.6205708410270745e-12 dstop_t=-3.6107069263380254e-06 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=1 theta=0.57037681003940066 pair=ref_vs_tighter class=ESC/ESC same=1 dn_ang=2.3363758065620761 dgrel=1.0434986208451846e-12 dstop_t=12.140629916198748 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=1 theta=0.57037681003940066 pair=h2_vs_h8 class=ESC/ESC same=1 dn_ang=5.0943830155578499e-05 dgrel=6.106226635438361e-14 dstop_t=1.659827830735594e-11 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=1 theta=0.57037681003940066 pair=ref_vs_h2 class=ESC/ESC same=1 dn_ang=1.7079955663413957 dgrel=1.6635359756378421e-11 dstop_t=-8.8742907176965105 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=1 theta=0.57037681003940066 pair=ref_vs_h8 class=ESC/ESC same=1 dn_ang=1.7080465101715514 dgrel=1.6696422022732804e-11 dstop_t=-8.8742907176799122 dthr=nan end=0/0
|
||||||
|
CAPAIR camera=r2p1_outward dir=2 theta=0.57037691003940061 pair=ref_vs_tighter class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=-7.4898969160130946e-07 dthr=3.5527136788005009e-15 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r2p1_outward dir=2 theta=0.57037691003940061 pair=h2_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=0 dthr=0 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r2p1_outward dir=2 theta=0.57037691003940061 pair=ref_vs_h2 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=3.6041923436869183e-06 dthr=0 end=4294967295/4294967295
|
||||||
|
CAPAIR camera=r2p1_outward dir=2 theta=0.57037691003940061 pair=ref_vs_h8 class=DARK/DARK same=1 dn_ang=nan dgrel=nan dstop_t=3.6041923436869183e-06 dthr=0 end=4294967295/4294967295
|
||||||
|
EXACT_CRITICAL_DIRECTION camera=r30_inward theta=0.16812289429621627 ref0=DARK/1/4294967295 ref1=DARK/1/4294967295 same=1 dn_ang=nan dstop_t=13.056128311415392
|
||||||
|
EXACT_CRITICAL_REFERENCE_NOT_CONVERGED camera=r30_inward dn_ang=nan dstop_t=13.056128311415392 class_same=1
|
||||||
|
EXACT_CRITICAL_DIRECTION camera=r100_inward theta=0.051461996376274736 ref0=DARK/1/4294967295 ref1=DARK/1/4294967295 same=1 dn_ang=nan dstop_t=12.699935010939669
|
||||||
|
EXACT_CRITICAL_REFERENCE_NOT_CONVERGED camera=r100_inward dn_ang=nan dstop_t=12.699935010939669 class_same=1
|
||||||
|
EXACT_CRITICAL_DIRECTION camera=r2p1_outward theta=0.57037681003940066 ref0=ESC/0/0 ref1=ESC/0/0 same=1 dn_ang=2.3363758065620761 dstop_t=12.140629916198748
|
||||||
|
EXACT_CRITICAL_REFERENCE_NOT_CONVERGED camera=r2p1_outward dn_ang=2.3363758065620761 dstop_t=12.140629916198748 class_same=1
|
||||||
|
NEIGHBOR_REFERENCE_CHECK camera=r30_inward dir=0 theta=0.16812279429621627 ref_class0=DARK/1/4294967295 ref_class1=DARK/1/4294967295 same=1 clean=1 stepped=1 dn_ang=nan dgrel=nan dstop_t=4.8821473797033832e-07
|
||||||
|
NEIGHBOR_REFERENCE_CHECK camera=r30_inward dir=2 theta=0.16812299429621627 ref_class0=ESC/0/0 ref_class1=ESC/0/0 same=1 clean=1 stepped=1 dn_ang=9.4669651562462453e-08 dgrel=4.4320103143036249e-13 dstop_t=-4.9198234819414211e-07
|
||||||
|
NEIGHBOR_REFERENCE_CHECK camera=r100_inward dir=0 theta=0.051461896376274734 ref_class0=DARK/1/4294967295 ref_class1=DARK/1/4294967295 same=1 clean=1 stepped=1 dn_ang=nan dgrel=nan dstop_t=1.5066669334373728e-07
|
||||||
|
NEIGHBOR_REFERENCE_CHECK camera=r100_inward dir=2 theta=0.051462096376274739 ref_class0=ESC/0/0 ref_class1=ESC/0/0 same=1 clean=1 stepped=1 dn_ang=2.7365576305005138e-08 dgrel=4.0134562340199409e-13 dstop_t=-1.4223877542463015e-07
|
||||||
|
NEIGHBOR_REFERENCE_CHECK camera=r2p1_outward dir=0 theta=0.57037671003940071 ref_class0=ESC/0/0 ref_class1=ESC/0/0 same=1 clean=1 stepped=1 dn_ang=1.4212247739786624e-07 dgrel=3.9634961979118088e-13 dstop_t=7.4312907827334129e-07
|
||||||
|
NEIGHBOR_REFERENCE_CHECK camera=r2p1_outward dir=2 theta=0.57037691003940061 ref_class0=DARK/1/4294967295 ref_class1=DARK/1/4294967295 same=1 clean=1 stepped=1 dn_ang=nan dgrel=nan dstop_t=-7.4898969160130946e-07
|
||||||
|
CRITICAL_REFERENCE_CHECK status=0
|
||||||
|
CRITICAL_REF_DONE
|
||||||
|
|
||||||
|
real 0m0.418s
|
||||||
|
user 0m0.402s
|
||||||
|
sys 0m0.016s
|
||||||
|
+ set +x
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
### command: a_public schwarzschild
|
||||||
|
+ /tmp/opencode/step_bounds/a_public schwarzschild
|
||||||
|
REF r30_inward dir=0 theta=0 outcome=1 reason=1 stop_t=-69.5728394 steps=531 rejected=0 rhs=4004 g=0 thr=8
|
||||||
|
REF r30_inward dir=1 theta=3.14159 outcome=0 reason=0 stop_t=-226 steps=905 rejected=0 rhs=6629 g=1.03509833901 thr=nan
|
||||||
|
REF r30_inward dir=2 theta=1.5708 outcome=0 reason=0 stop_t=-256.70592 steps=1028 rejected=0 rhs=7490 g=1.03509833901 thr=nan
|
||||||
|
REF r30_inward dir=3 theta=0.168123 outcome=1 reason=1 stop_t=-225.852935 steps=3746 rejected=0 rhs=26509 g=0 thr=8
|
||||||
|
REF r30_inward dir=4 theta=0.167123 outcome=1 reason=1 stop_t=-94.2779103 steps=1127 rejected=0 rhs=8176 g=0 thr=8
|
||||||
|
REF r30_inward dir=5 theta=0.169123 outcome=0 reason=0 stop_t=-322.366447 steps=1834 rejected=0 rhs=13132 g=1.03509833901 thr=nan
|
||||||
|
REF r30_inward dir=6 theta=0.168113 outcome=1 reason=1 stop_t=-118.245807 steps=1606 rejected=0 rhs=11529 g=0 thr=8
|
||||||
|
REF r30_inward dir=7 theta=0.168133 outcome=0 reason=0 stop_t=-346.252134 steps=2312 rejected=1 rhs=16485 g=1.03509833901 thr=nan
|
||||||
|
REF r30_inward dir=8 theta=0.168123 outcome=1 reason=1 stop_t=-142.175748 steps=2081 rejected=0 rhs=14854 g=0 thr=8
|
||||||
|
REF r30_inward dir=9 theta=0.168123 outcome=0 reason=0 stop_t=-370.180478 steps=2790 rejected=1 rhs=19831 g=1.03509833901 thr=nan
|
||||||
|
REF r30_inward dir=10 theta=0.218123 outcome=0 reason=0 stop_t=-302.584521 steps=1409 rejected=1 rhs=10164 g=1.03509833901 thr=nan
|
||||||
|
REF r30_inward dir=11 theta=0.118123 outcome=1 reason=1 stop_t=-73.7563113 steps=665 rejected=0 rhs=4942 g=0 thr=8
|
||||||
|
REF r100_inward dir=0 theta=0 outcome=1 reason=1 stop_t=-144.299101 steps=830 rejected=0 rhs=6097 g=0 thr=8
|
||||||
|
REF r100_inward dir=1 theta=3.14159 outcome=0 reason=0 stop_t=-156 steps=625 rejected=0 rhs=4669 g=1.01015254455 thr=nan
|
||||||
|
REF r100_inward dir=2 theta=1.5708 outcome=0 reason=0 stop_t=-237.678408 steps=952 rejected=0 rhs=6958 g=1.01015254455 thr=nan
|
||||||
|
REF r100_inward dir=3 theta=0.051462 outcome=1 reason=1 stop_t=-301.077405 steps=4045 rejected=0 rhs=28602 g=0 thr=8
|
||||||
|
REF r100_inward dir=4 theta=0.050462 outcome=1 reason=1 stop_t=-163.061409 steps=1292 rejected=0 rhs=9331 g=0 thr=8
|
||||||
|
REF r100_inward dir=5 theta=0.052462 outcome=0 reason=0 stop_t=-391.57927 steps=2014 rejected=1 rhs=14399 g=1.01015254455 thr=nan
|
||||||
|
REF r100_inward dir=6 theta=0.051452 outcome=1 reason=1 stop_t=-187.095903 steps=1773 rejected=0 rhs=12698 g=0 thr=8
|
||||||
|
REF r100_inward dir=7 theta=0.051472 outcome=0 reason=0 stop_t=-415.386875 steps=2493 rejected=0 rhs=17745 g=1.01015254455 thr=nan
|
||||||
|
REF r100_inward dir=8 theta=0.0514619 outcome=1 reason=1 stop_t=-211.027405 steps=2252 rejected=0 rhs=16051 g=0 thr=8
|
||||||
|
REF r100_inward dir=9 theta=0.0514621 outcome=0 reason=0 stop_t=-439.313552 steps=2969 rejected=0 rhs=21077 g=1.01015254455 thr=nan
|
||||||
|
REF r100_inward dir=10 theta=0.101462 outcome=0 reason=0 stop_t=-372.348056 steps=1571 rejected=0 rhs=11291 g=1.01015254455 thr=nan
|
||||||
|
REF r100_inward dir=11 theta=0.001462 outcome=1 reason=1 stop_t=-144.304446 steps=830 rejected=0 rhs=6097 g=0 thr=8
|
||||||
|
REF r2p1_outward dir=0 theta=0 outcome=0 reason=0 stop_t=-253.9 steps=1120 rejected=1 rhs=8141 g=4.58257569496 thr=nan
|
||||||
|
REF r2p1_outward dir=1 theta=3.14159 outcome=1 reason=1 stop_t=-32.2468847 steps=186 rejected=0 rhs=1589 g=0 thr=8
|
||||||
|
REF r2p1_outward dir=2 theta=1.5708 outcome=1 reason=1 stop_t=-32.7725901 steps=316 rejected=1 rhs=2506 g=0 thr=8
|
||||||
|
REF r2p1_outward dir=3 theta=0.570377 outcome=0 reason=0 stop_t=-414.940103 steps=4263 rejected=2 rhs=30149 g=4.58257569495 thr=nan
|
||||||
|
REF r2p1_outward dir=4 theta=0.569377 outcome=0 reason=0 stop_t=-285.577403 steps=1686 rejected=1 rhs=12103 g=4.58257569496 thr=nan
|
||||||
|
REF r2p1_outward dir=5 theta=0.571377 outcome=1 reason=1 stop_t=-61.5813727 steps=995 rejected=1 rhs=7259 g=0 thr=8
|
||||||
|
REF r2p1_outward dir=6 theta=0.570367 outcome=0 reason=0 stop_t=-309.521289 steps=2162 rejected=2 rhs=15442 g=4.58257569495 thr=nan
|
||||||
|
REF r2p1_outward dir=7 theta=0.570387 outcome=1 reason=1 stop_t=-85.4867841 steps=1474 rejected=1 rhs=10612 g=0 thr=8
|
||||||
|
REF r2p1_outward dir=8 theta=0.570377 outcome=0 reason=0 stop_t=-333.450704 steps=2639 rejected=1 rhs=18774 g=4.58257569495 thr=nan
|
||||||
|
REF r2p1_outward dir=9 theta=0.570377 outcome=1 reason=1 stop_t=-109.415611 steps=1950 rejected=1 rhs=13944 g=0 thr=8
|
||||||
|
REF r2p1_outward dir=10 theta=0.620377 outcome=1 reason=1 stop_t=-41.9883684 steps=585 rejected=1 rhs=4389 g=0 thr=8
|
||||||
|
REF r2p1_outward dir=11 theta=0.520377 outcome=0 reason=0 stop_t=-264.96182 steps=1303 rejected=2 rhs=9429 g=4.58257569496 thr=nan
|
||||||
|
REF r1p5_freefall dir=0 theta=0 outcome=1 reason=1 stop_t=-30.6580907 steps=231 rejected=1 rhs=1911 g=0 thr=8
|
||||||
|
REF r1p5_freefall dir=1 theta=1.5708 outcome=0 reason=0 stop_t=-255.249558 steps=1130 rejected=1 rhs=8211 g=1 thr=nan
|
||||||
|
REF r1p5_freefall dir=2 theta=3.14159 outcome=0 reason=0 stop_t=-254.5 steps=1143 rejected=1 rhs=8302 g=0.464101615138 thr=nan
|
||||||
|
REF r1p5_freefall dir=3 theta=2.35619 outcome=0 reason=0 stop_t=-254.612997 steps=1127 rejected=1 rhs=8190 g=0.550510257217 thr=nan
|
||||||
|
SUMMARY upper r30_inward upper=0.25 min=1e-12 n=12 mismatch=0 max_dn_ang=8.66705e-05 max_dgrel=2.2616e-09 max_dstopT=35.0811 sum_rhs=76510 esc=6 dark=6 unres=0 inc=0 wall=0.041s
|
||||||
|
SUMMARY upper r30_inward upper=0.5 min=1e-12 n=12 mismatch=0 max_dn_ang=0.00018656 max_dgrel=2.26833e-09 max_dstopT=39.0614 sum_rhs=49063 esc=6 dark=6 unres=0 inc=0 wall=0.027s
|
||||||
|
SUMMARY upper r30_inward upper=1 min=1e-12 n=12 mismatch=0 max_dn_ang=0.000280143 max_dgrel=2.2658e-09 max_dstopT=41.1726 sum_rhs=36974 esc=6 dark=6 unres=0 inc=0 wall=0.020s
|
||||||
|
SUMMARY upper r30_inward upper=2 min=1e-12 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY upper r30_inward upper=4 min=1e-12 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24952e-09 max_dstopT=41.2044 sum_rhs=29617 esc=6 dark=6 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY upper r30_inward upper=8 min=1e-12 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.25767e-09 max_dstopT=41.2044 sum_rhs=28714 esc=6 dark=6 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY upper r30_inward upper=16 min=1e-12 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.26556e-09 max_dstopT=41.2044 sum_rhs=28455 esc=6 dark=6 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r30_inward upper=32 min=1e-12 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.26605e-09 max_dstopT=41.2044 sum_rhs=28434 esc=6 dark=6 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r30_inward upper=64 min=1e-12 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.26605e-09 max_dstopT=41.2044 sum_rhs=28434 esc=6 dark=6 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r100_inward upper=0.25 min=1e-12 n=12 mismatch=0 max_dn_ang=2.60363e-05 max_dgrel=2.04765e-09 max_dstopT=35.2041 sum_rhs=93464 esc=6 dark=6 unres=0 inc=0 wall=0.050s
|
||||||
|
SUMMARY upper r100_inward upper=0.5 min=1e-12 n=12 mismatch=0 max_dn_ang=5.69583e-05 max_dgrel=2.05623e-09 max_dstopT=39.2691 sum_rhs=56595 esc=6 dark=6 unres=0 inc=0 wall=0.030s
|
||||||
|
SUMMARY upper r100_inward upper=1 min=1e-12 n=12 mismatch=0 max_dn_ang=8.34774e-05 max_dgrel=2.05088e-09 max_dstopT=41.2546 sum_rhs=39788 esc=6 dark=6 unres=0 inc=0 wall=0.022s
|
||||||
|
SUMMARY upper r100_inward upper=2 min=1e-12 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY upper r100_inward upper=4 min=1e-12 n=12 mismatch=0 max_dn_ang=8.08898e-05 max_dgrel=2.02847e-09 max_dstopT=41.091 sum_rhs=29393 esc=6 dark=6 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY upper r100_inward upper=8 min=1e-12 n=12 mismatch=0 max_dn_ang=8.03365e-05 max_dgrel=2.03431e-09 max_dstopT=41.0553 sum_rhs=28427 esc=6 dark=6 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r100_inward upper=16 min=1e-12 n=12 mismatch=0 max_dn_ang=8.03365e-05 max_dgrel=2.04195e-09 max_dstopT=41.0553 sum_rhs=28189 esc=6 dark=6 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r100_inward upper=32 min=1e-12 n=12 mismatch=0 max_dn_ang=8.03365e-05 max_dgrel=2.04297e-09 max_dstopT=41.0553 sum_rhs=28182 esc=6 dark=6 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r100_inward upper=64 min=1e-12 n=12 mismatch=0 max_dn_ang=8.03365e-05 max_dgrel=2.04297e-09 max_dstopT=41.0553 sum_rhs=28182 esc=6 dark=6 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r2p1_outward upper=0.25 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287223 max_dgrel=2.66126e-09 max_dstopT=263.145 sum_rhs=62258 esc=5 dark=7 unres=0 inc=0 wall=0.034s
|
||||||
|
SUMMARY upper r2p1_outward upper=0.5 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287221 max_dgrel=2.64443e-09 max_dstopT=263.145 sum_rhs=42490 esc=5 dark=7 unres=0 inc=0 wall=0.023s
|
||||||
|
SUMMARY upper r2p1_outward upper=1 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287221 max_dgrel=2.61531e-09 max_dstopT=263.145 sum_rhs=33544 esc=5 dark=7 unres=0 inc=0 wall=0.019s
|
||||||
|
SUMMARY upper r2p1_outward upper=2 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY upper r2p1_outward upper=4 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287221 max_dgrel=2.59774e-09 max_dstopT=263.145 sum_rhs=27580 esc=5 dark=7 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r2p1_outward upper=8 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287221 max_dgrel=2.60591e-09 max_dstopT=263.145 sum_rhs=26831 esc=5 dark=7 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r2p1_outward upper=16 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287223 max_dgrel=2.61374e-09 max_dstopT=263.145 sum_rhs=26614 esc=5 dark=7 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r2p1_outward upper=32 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287221 max_dgrel=2.6148e-09 max_dstopT=263.145 sum_rhs=26607 esc=5 dark=7 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r2p1_outward upper=64 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287221 max_dgrel=2.6148e-09 max_dstopT=263.145 sum_rhs=26607 esc=5 dark=7 unres=0 inc=0 wall=0.015s
|
||||||
|
SUMMARY upper r1p5_freefall upper=0.25 min=1e-12 n=4 mismatch=0 max_dn_ang=1.00222e-10 max_dgrel=3.16466e-10 max_dstopT=2.6078e-08 sum_rhs=23597 esc=3 dark=1 unres=0 inc=0 wall=0.014s
|
||||||
|
SUMMARY upper r1p5_freefall upper=0.5 min=1e-12 n=4 mismatch=0 max_dn_ang=8.87544e-11 max_dgrel=3.65847e-10 max_dstopT=3.08873e-08 sum_rhs=12747 esc=3 dark=1 unres=0 inc=0 wall=0.008s
|
||||||
|
SUMMARY upper r1p5_freefall upper=1 min=1e-12 n=4 mismatch=0 max_dn_ang=8.18746e-11 max_dgrel=3.81078e-10 max_dstopT=2.81655e-08 sum_rhs=7553 esc=3 dark=1 unres=0 inc=0 wall=0.005s
|
||||||
|
SUMMARY upper r1p5_freefall upper=2 min=1e-12 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY upper r1p5_freefall upper=4 min=1e-12 n=4 mismatch=0 max_dn_ang=8.1566e-11 max_dgrel=3.6318e-10 max_dstopT=2.34608e-08 sum_rhs=4039 esc=3 dark=1 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper r1p5_freefall upper=8 min=1e-12 n=4 mismatch=0 max_dn_ang=8.15091e-11 max_dgrel=3.54659e-10 max_dstopT=2.12507e-08 sum_rhs=3591 esc=3 dark=1 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper r1p5_freefall upper=16 min=1e-12 n=4 mismatch=0 max_dn_ang=8.14607e-11 max_dgrel=3.46852e-10 max_dstopT=1.92511e-08 sum_rhs=3465 esc=3 dark=1 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper r1p5_freefall upper=32 min=1e-12 n=4 mismatch=0 max_dn_ang=8.1455e-11 max_dgrel=3.45979e-10 max_dstopT=1.94793e-08 sum_rhs=3458 esc=3 dark=1 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper r1p5_freefall upper=64 min=1e-12 n=4 mismatch=0 max_dn_ang=8.1455e-11 max_dgrel=3.45979e-10 max_dstopT=1.94793e-08 sum_rhs=3458 esc=3 dark=1 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY min r30_inward upper=2 min=0.1 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=0.01 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=0.001 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=0.0001 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=1e-05 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=1e-06 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=1e-08 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=1e-10 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=1e-12 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r30_inward upper=2 min=1e-14 n=12 mismatch=0 max_dn_ang=0.000281866 max_dgrel=2.24374e-09 max_dstopT=41.2044 sum_rhs=31843 esc=6 dark=6 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r100_inward upper=2 min=0.1 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=0.01 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=0.001 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=0.0001 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=1e-05 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=1e-06 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=1e-08 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=1e-10 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=1e-12 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r100_inward upper=2 min=1e-14 n=12 mismatch=0 max_dn_ang=8.28604e-05 max_dgrel=2.0262e-09 max_dstopT=41.2161 sum_rhs=32389 esc=6 dark=6 unres=0 inc=0 wall=0.018s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=0.1 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=0.01 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=0.001 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=0.0001 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.017s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=1e-05 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=1e-06 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=1e-08 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=1e-10 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=1e-12 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY min r2p1_outward upper=2 min=1e-14 n=12 mismatch=1 max_dn_ang=0.000287222 max_dgrel=2.59243e-09 max_dstopT=263.145 sum_rhs=29421 esc=5 dark=7 unres=0 inc=0 wall=0.016s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=0.1 n=4 mismatch=1 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=254.3 sum_rhs=3654 esc=2 dark=1 unres=0 inc=1 wall=0.002s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=0.01 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=0.001 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=0.0001 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=1e-05 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=1e-06 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=1e-08 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=1e-10 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=1e-12 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY min r1p5_freefall upper=2 min=1e-14 n=4 mismatch=0 max_dn_ang=8.165e-11 max_dgrel=3.7195e-10 max_dstopT=2.57141e-08 sum_rhs=5131 esc=3 dark=1 unres=0 inc=0 wall=0.003s
|
||||||
|
RK4 r30_inward dir=8 theta=0.168123 o01=1/1 o005=1/1 hhalve_dn=nan hhalve_dgrel=nan vsdp_dn=nan vsdp_dgrel=nan vsdp_class=1
|
||||||
|
RK4 r30_inward dir=9 theta=0.168123 o01=0/0 o005=0/0 hhalve_dn=1.89584e-07 hhalve_dgrel=7.32747e-15 vsdp_dn=7.95167e-08 vsdp_dgrel=4.66294e-13 vsdp_class=1
|
||||||
|
RK4 r30_inward dir=6 theta=0.168113 o01=1/1 o005=1/1 hhalve_dn=nan hhalve_dgrel=nan vsdp_dn=nan vsdp_dgrel=nan vsdp_class=1
|
||||||
|
RK4 r30_inward dir=7 theta=0.168133 o01=0/0 o005=0/0 hhalve_dn=1.73965e-09 hhalve_dgrel=7.9492e-14 vsdp_dn=7.86496e-10 vsdp_dgrel=2.6934e-13 vsdp_class=1
|
||||||
|
RK4 r2p1_outward dir=8 theta=0.570377 o01=0/0 o005=0/0 hhalve_dn=1.03961e-05 hhalve_dgrel=1.66234e-12 vsdp_dn=8.49321e-07 vsdp_dgrel=5.46896e-13 vsdp_class=1
|
||||||
|
RK4 r2p1_outward dir=9 theta=0.570377 o01=1/1 o005=1/1 hhalve_dn=nan hhalve_dgrel=nan vsdp_dn=nan vsdp_dgrel=nan vsdp_class=1
|
||||||
|
RK4 r2p1_outward dir=6 theta=0.570367 o01=0/0 o005=0/0 hhalve_dn=1.03971e-07 hhalve_dgrel=1.61182e-12 vsdp_dn=8.47692e-09 vsdp_dgrel=3.02647e-13 vsdp_class=1
|
||||||
|
RK4 r2p1_outward dir=7 theta=0.570387 o01=1/1 o005=1/1 hhalve_dn=nan hhalve_dgrel=nan vsdp_dn=nan vsdp_dgrel=nan vsdp_class=1
|
||||||
|
TOTAL_RAYS 816
|
||||||
|
|
||||||
|
real 0m2.428s
|
||||||
|
user 0m2.423s
|
||||||
|
sys 0m0.004s
|
||||||
|
+ set +x
|
||||||
|
### command: a_public minkowski
|
||||||
|
+ /tmp/opencode/step_bounds/a_public minkowski
|
||||||
|
SUMMARY mink upper=1 min=0.1 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=4886 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=1 min=1e-06 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=4886 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=1 min=1e-12 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=4886 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=4 min=0.1 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=2590 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=4 min=1e-06 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=2590 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=4 min=1e-12 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=2590 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=16 min=0.1 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=2037 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=16 min=1e-06 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=2037 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=16 min=1e-12 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=2037 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=64 min=0.1 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=1932 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=64 min=1e-06 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=1932 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=64 min=1e-12 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=1932 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=256 min=0.1 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=1932 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=256 min=1e-06 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=1932 esc=6 dark=0 unres=0 inc=0
|
||||||
|
SUMMARY mink upper=256 min=1e-12 n=6 mismatch=0 max_dn_ang=0 max_dgrel=0 sum_rhs=1932 esc=6 dark=0 unres=0 inc=0
|
||||||
|
TOTAL_RAYS 186
|
||||||
|
|
||||||
|
real 0m0.013s
|
||||||
|
user 0m0.013s
|
||||||
|
sys 0m0.000s
|
||||||
|
+ set +x
|
||||||
|
### command: a_public alcubierre
|
||||||
|
+ /tmp/opencode/step_bounds/a_public alcubierre
|
||||||
|
REF alc_v3_s1 dir=0 theta=nan outcome=0 reason=0 stop_t=-16.4338937 steps=347 rejected=1 rhs=2730 g=1.3 thr=nan
|
||||||
|
REF alc_v3_s1 dir=1 theta=nan outcome=0 reason=0 stop_t=-29.3767055 steps=597 rejected=1 rhs=4480 g=0.7 thr=nan
|
||||||
|
REF alc_v3_s1 dir=2 theta=nan outcome=0 reason=0 stop_t=-20.2190145 steps=414 rejected=0 rhs=3192 g=1 thr=nan
|
||||||
|
REF alc_v3_s1 dir=3 theta=nan outcome=0 reason=0 stop_t=-20.2190145 steps=414 rejected=0 rhs=3192 g=1 thr=nan
|
||||||
|
REF alc_v3_s1 dir=4 theta=nan outcome=0 reason=0 stop_t=-17.6897755 steps=367 rejected=0 rhs=2863 g=1.17815368048 thr=nan
|
||||||
|
REF alc_v3_s1 dir=5 theta=nan outcome=0 reason=0 stop_t=-24.329102 steps=497 rejected=1 rhs=3780 g=0.822613315483 thr=nan
|
||||||
|
REF alc_v3_s10 dir=0 theta=nan outcome=0 reason=0 stop_t=-2.53543426 steps=523 rejected=3 rhs=3976 g=1.3 thr=nan
|
||||||
|
REF alc_v3_s10 dir=1 theta=nan outcome=0 reason=0 stop_t=-3.84949982 steps=775 rejected=0 rhs=5719 g=0.7 thr=nan
|
||||||
|
REF alc_v3_s10 dir=2 theta=nan outcome=0 reason=0 stop_t=-2.94282517 steps=589 rejected=0 rhs=4417 g=1 thr=nan
|
||||||
|
REF alc_v3_s10 dir=3 theta=nan outcome=0 reason=0 stop_t=-2.94282517 steps=589 rejected=0 rhs=4417 g=1 thr=nan
|
||||||
|
REF alc_v3_s10 dir=4 theta=nan outcome=0 reason=0 stop_t=-2.67090915 steps=543 rejected=2 rhs=4109 g=1.17959135733 thr=nan
|
||||||
|
REF alc_v3_s10 dir=5 theta=nan outcome=0 reason=0 stop_t=-3.3698049 steps=677 rejected=0 rhs=5033 g=0.820579506843 thr=nan
|
||||||
|
REF alc_v9_s1 dir=0 theta=nan outcome=0 reason=0 stop_t=-11.5627491 steps=283 rejected=1 rhs=2282 g=1.9 thr=nan
|
||||||
|
REF alc_v9_s1 dir=1 theta=nan outcome=0 reason=0 stop_t=-189.149503 steps=3825 rejected=1 rhs=27069 g=0.1 thr=nan
|
||||||
|
REF alc_v9_s1 dir=2 theta=nan outcome=0 reason=0 stop_t=-16.1619146 steps=351 rejected=4 rhs=2772 g=1 thr=nan
|
||||||
|
REF alc_v9_s1 dir=3 theta=nan outcome=0 reason=0 stop_t=-16.1619146 steps=351 rejected=4 rhs=2772 g=1 thr=nan
|
||||||
|
REF alc_v9_s1 dir=4 theta=nan outcome=0 reason=0 stop_t=-13.0192142 steps=308 rejected=1 rhs=2457 g=1.5041731473 thr=nan
|
||||||
|
REF alc_v9_s1 dir=5 theta=nan outcome=0 reason=0 stop_t=-22.987334 steps=491 rejected=1 rhs=3738 g=0.54079971046 thr=nan
|
||||||
|
REF alc_v9_s10 dir=0 theta=nan outcome=0 reason=0 stop_t=-2.03742978 steps=452 rejected=5 rhs=3493 g=1.9 thr=nan
|
||||||
|
REF alc_v9_s10 dir=1 theta=nan outcome=0 reason=0 stop_t=-19.9638367 steps=4013 rejected=0 rhs=28385 g=0.1 thr=nan
|
||||||
|
REF alc_v9_s10 dir=2 theta=nan outcome=0 reason=0 stop_t=-2.62069451 steps=525 rejected=0 rhs=3969 g=1 thr=nan
|
||||||
|
REF alc_v9_s10 dir=3 theta=nan outcome=0 reason=0 stop_t=-2.62069451 steps=525 rejected=0 rhs=3969 g=1 thr=nan
|
||||||
|
REF alc_v9_s10 dir=4 theta=nan outcome=0 reason=0 stop_t=-2.20704191 steps=469 rejected=3 rhs=3598 g=1.5316539409 thr=nan
|
||||||
|
REF alc_v9_s10 dir=5 theta=nan outcome=0 reason=0 stop_t=-3.67922549 steps=742 rejected=0 rhs=5488 g=0.483265790771 thr=nan
|
||||||
|
REF alc_v9_s100 dir=0 theta=nan outcome=0 reason=0 stop_t=-1.10374298 steps=2252 rejected=5 rhs=16093 g=1.9 thr=nan
|
||||||
|
REF alc_v9_s100 dir=1 theta=nan outcome=0 reason=0 stop_t=-2.89638367 steps=5813 rejected=0 rhs=40978 g=0.1 thr=nan
|
||||||
|
REF alc_v9_s100 dir=2 theta=nan outcome=0 reason=0 stop_t=-1.18800796 steps=2377 rejected=0 rhs=16926 g=1 thr=nan
|
||||||
|
REF alc_v9_s100 dir=3 theta=nan outcome=0 reason=0 stop_t=-1.18800796 steps=2377 rejected=0 rhs=16926 g=1 thr=nan
|
||||||
|
REF alc_v9_s100 dir=4 theta=nan outcome=0 reason=0 stop_t=-1.12678339 steps=2281 rejected=2 rhs=16275 g=1.53910006629 thr=nan
|
||||||
|
REF alc_v9_s100 dir=5 theta=nan outcome=0 reason=0 stop_t=-1.36694611 steps=2740 rejected=0 rhs=19474 g=0.462933441354 thr=nan
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.05 min=0.0001 n=6 mismatch=0 max_dn_ang=7.54397e-14 max_dgrel=7.62723e-13 max_dstopT=1.98952e-13 sum_rhs=19740 esc=6 dark=0 unres=0 inc=0 wall=0.005s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.05 min=1e-08 n=6 mismatch=0 max_dn_ang=7.54397e-14 max_dgrel=7.62723e-13 max_dstopT=1.98952e-13 sum_rhs=19740 esc=6 dark=0 unres=0 inc=0 wall=0.005s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.05 min=1e-12 n=6 mismatch=0 max_dn_ang=7.54397e-14 max_dgrel=7.62723e-13 max_dstopT=1.98952e-13 sum_rhs=19740 esc=6 dark=0 unres=0 inc=0 wall=0.005s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.2 min=0.0001 n=6 mismatch=0 max_dn_ang=1.2079e-10 max_dgrel=3.45157e-10 max_dstopT=4.09095e-10 sum_rhs=6475 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.2 min=1e-08 n=6 mismatch=0 max_dn_ang=1.2079e-10 max_dgrel=3.45157e-10 max_dstopT=4.09095e-10 sum_rhs=6475 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.2 min=1e-12 n=6 mismatch=0 max_dn_ang=1.2079e-10 max_dgrel=3.45157e-10 max_dstopT=4.09095e-10 sum_rhs=6475 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.4 min=0.0001 n=6 mismatch=0 max_dn_ang=1.02989e-10 max_dgrel=3.46442e-10 max_dstopT=3.14323e-10 sum_rhs=4613 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.4 min=1e-08 n=6 mismatch=0 max_dn_ang=1.02989e-10 max_dgrel=3.46442e-10 max_dstopT=3.14323e-10 sum_rhs=4613 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.4 min=1e-12 n=6 mismatch=0 max_dn_ang=1.02989e-10 max_dgrel=3.46442e-10 max_dstopT=3.14323e-10 sum_rhs=4613 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.8 min=0.0001 n=6 mismatch=0 max_dn_ang=7.88763e-11 max_dgrel=7.95433e-10 max_dstopT=7.3689e-10 sum_rhs=3794 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.8 min=1e-08 n=6 mismatch=0 max_dn_ang=7.88763e-11 max_dgrel=7.95433e-10 max_dstopT=7.3689e-10 sum_rhs=3794 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=0.8 min=1e-12 n=6 mismatch=0 max_dn_ang=7.88763e-11 max_dgrel=7.95433e-10 max_dstopT=7.3689e-10 sum_rhs=3794 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=1.6 min=0.0001 n=6 mismatch=0 max_dn_ang=1.23935e-10 max_dgrel=1.11826e-09 max_dstopT=1.14768e-09 sum_rhs=3430 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=1.6 min=1e-08 n=6 mismatch=0 max_dn_ang=1.23935e-10 max_dgrel=1.11826e-09 max_dstopT=1.14768e-09 sum_rhs=3430 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=1.6 min=1e-12 n=6 mismatch=0 max_dn_ang=1.23935e-10 max_dgrel=1.11826e-09 max_dstopT=1.14768e-09 sum_rhs=3430 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=3.2 min=0.0001 n=6 mismatch=0 max_dn_ang=1.54539e-10 max_dgrel=1.25996e-09 max_dstopT=1.3457e-09 sum_rhs=3290 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=3.2 min=1e-08 n=6 mismatch=0 max_dn_ang=1.54539e-10 max_dgrel=1.25996e-09 max_dstopT=1.3457e-09 sum_rhs=3290 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s1 upper=3.2 min=1e-12 n=6 mismatch=0 max_dn_ang=1.54539e-10 max_dgrel=1.25996e-09 max_dstopT=1.3457e-09 sum_rhs=3290 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.005 min=0.0001 n=6 mismatch=0 max_dn_ang=5.82867e-15 max_dgrel=3.10862e-14 max_dstopT=4.66294e-14 sum_rhs=27412 esc=6 dark=0 unres=0 inc=0 wall=0.006s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.005 min=1e-08 n=6 mismatch=0 max_dn_ang=5.82867e-15 max_dgrel=3.10862e-14 max_dstopT=4.66294e-14 sum_rhs=27412 esc=6 dark=0 unres=0 inc=0 wall=0.006s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.005 min=1e-12 n=6 mismatch=0 max_dn_ang=5.82867e-15 max_dgrel=3.10862e-14 max_dstopT=4.66294e-14 sum_rhs=27412 esc=6 dark=0 unres=0 inc=0 wall=0.006s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.02 min=0.0001 n=6 mismatch=0 max_dn_ang=6.29929e-12 max_dgrel=2.40162e-10 max_dstopT=1.39897e-11 sum_rhs=8337 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.02 min=1e-08 n=6 mismatch=0 max_dn_ang=6.29929e-12 max_dgrel=2.40162e-10 max_dstopT=1.39897e-11 sum_rhs=8337 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.02 min=1e-12 n=6 mismatch=0 max_dn_ang=6.29929e-12 max_dgrel=2.40162e-10 max_dstopT=1.39897e-11 sum_rhs=8337 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.04 min=0.0001 n=6 mismatch=0 max_dn_ang=3.28758e-11 max_dgrel=3.85361e-10 max_dstopT=6.29403e-11 sum_rhs=5621 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.04 min=1e-08 n=6 mismatch=0 max_dn_ang=3.28758e-11 max_dgrel=3.85361e-10 max_dstopT=6.29403e-11 sum_rhs=5621 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.04 min=1e-12 n=6 mismatch=0 max_dn_ang=3.28758e-11 max_dgrel=3.85361e-10 max_dstopT=6.29403e-11 sum_rhs=5621 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.08 min=0.0001 n=6 mismatch=0 max_dn_ang=1.04151e-11 max_dgrel=2.78111e-10 max_dstopT=8.02363e-11 sum_rhs=4648 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.08 min=1e-08 n=6 mismatch=0 max_dn_ang=1.04151e-11 max_dgrel=2.78111e-10 max_dstopT=8.02363e-11 sum_rhs=4648 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.08 min=1e-12 n=6 mismatch=0 max_dn_ang=1.04151e-11 max_dgrel=2.78111e-10 max_dstopT=8.02363e-11 sum_rhs=4648 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.16 min=0.0001 n=6 mismatch=0 max_dn_ang=1.13121e-11 max_dgrel=7.59968e-10 max_dstopT=9.53793e-11 sum_rhs=4270 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.16 min=1e-08 n=6 mismatch=0 max_dn_ang=1.13121e-11 max_dgrel=7.59968e-10 max_dstopT=9.53793e-11 sum_rhs=4270 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.16 min=1e-12 n=6 mismatch=0 max_dn_ang=1.13121e-11 max_dgrel=7.59968e-10 max_dstopT=9.53793e-11 sum_rhs=4270 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.32 min=0.0001 n=6 mismatch=0 max_dn_ang=3.13081e-11 max_dgrel=9.77839e-10 max_dstopT=1.04124e-10 sum_rhs=4116 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.32 min=1e-08 n=6 mismatch=0 max_dn_ang=3.13081e-11 max_dgrel=9.77839e-10 max_dstopT=1.04124e-10 sum_rhs=4116 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v3_s10 upper=0.32 min=1e-12 n=6 mismatch=0 max_dn_ang=3.13081e-11 max_dgrel=9.77839e-10 max_dstopT=1.04124e-10 sum_rhs=4116 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.05 min=0.0001 n=6 mismatch=0 max_dn_ang=6.63192e-13 max_dgrel=2.59086e-11 max_dstopT=1.38662e-11 sum_rhs=39452 esc=6 dark=0 unres=0 inc=0 wall=0.010s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.05 min=1e-08 n=6 mismatch=0 max_dn_ang=6.63192e-13 max_dgrel=2.59086e-11 max_dstopT=1.38662e-11 sum_rhs=39452 esc=6 dark=0 unres=0 inc=0 wall=0.010s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.05 min=1e-12 n=6 mismatch=0 max_dn_ang=6.63192e-13 max_dgrel=2.59086e-11 max_dstopT=1.38662e-11 sum_rhs=39452 esc=6 dark=0 unres=0 inc=0 wall=0.010s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.2 min=0.0001 n=6 mismatch=0 max_dn_ang=1.07764e-10 max_dgrel=2.07282e-09 max_dstopT=6.80462e-10 sum_rhs=11690 esc=6 dark=0 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.2 min=1e-08 n=6 mismatch=0 max_dn_ang=1.07764e-10 max_dgrel=2.07282e-09 max_dstopT=6.80462e-10 sum_rhs=11690 esc=6 dark=0 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.2 min=1e-12 n=6 mismatch=0 max_dn_ang=1.07764e-10 max_dgrel=2.07282e-09 max_dstopT=6.80462e-10 sum_rhs=11690 esc=6 dark=0 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.4 min=0.0001 n=6 mismatch=0 max_dn_ang=6.25e-11 max_dgrel=2.46644e-09 max_dstopT=1.08309e-09 sum_rhs=7413 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.4 min=1e-08 n=6 mismatch=0 max_dn_ang=6.25e-11 max_dgrel=2.46644e-09 max_dstopT=1.08309e-09 sum_rhs=7413 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.4 min=1e-12 n=6 mismatch=0 max_dn_ang=6.25e-11 max_dgrel=2.46644e-09 max_dstopT=1.08309e-09 sum_rhs=7413 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.8 min=0.0001 n=6 mismatch=0 max_dn_ang=5.34924e-11 max_dgrel=2.71772e-09 max_dstopT=1.1859e-09 sum_rhs=5369 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.8 min=1e-08 n=6 mismatch=0 max_dn_ang=5.34924e-11 max_dgrel=2.71772e-09 max_dstopT=1.1859e-09 sum_rhs=5369 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=0.8 min=1e-12 n=6 mismatch=0 max_dn_ang=5.34924e-11 max_dgrel=2.71772e-09 max_dstopT=1.1859e-09 sum_rhs=5369 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=1.6 min=0.0001 n=6 mismatch=0 max_dn_ang=1.03537e-10 max_dgrel=2.8194e-09 max_dstopT=9.54927e-10 sum_rhs=4431 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=1.6 min=1e-08 n=6 mismatch=0 max_dn_ang=1.03537e-10 max_dgrel=2.8194e-09 max_dstopT=9.54927e-10 sum_rhs=4431 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=1.6 min=1e-12 n=6 mismatch=0 max_dn_ang=1.03537e-10 max_dgrel=2.8194e-09 max_dstopT=9.54927e-10 sum_rhs=4431 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=3.2 min=0.0001 n=6 mismatch=0 max_dn_ang=1.23927e-10 max_dgrel=2.82251e-09 max_dstopT=3.24928e-09 sum_rhs=3983 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=3.2 min=1e-08 n=6 mismatch=0 max_dn_ang=1.23927e-10 max_dgrel=2.82251e-09 max_dstopT=3.24928e-09 sum_rhs=3983 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s1 upper=3.2 min=1e-12 n=6 mismatch=0 max_dn_ang=1.23927e-10 max_dgrel=2.82251e-09 max_dstopT=3.24928e-09 sum_rhs=3983 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.005 min=0.0001 n=6 mismatch=0 max_dn_ang=8.9373e-14 max_dgrel=1.10281e-11 max_dstopT=3.55271e-13 sum_rhs=48167 esc=6 dark=0 unres=0 inc=0 wall=0.011s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.005 min=1e-08 n=6 mismatch=0 max_dn_ang=8.9373e-14 max_dgrel=1.10281e-11 max_dstopT=3.55271e-13 sum_rhs=48167 esc=6 dark=0 unres=0 inc=0 wall=0.011s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.005 min=1e-12 n=6 mismatch=0 max_dn_ang=8.9373e-14 max_dgrel=1.10281e-11 max_dstopT=3.55271e-13 sum_rhs=48167 esc=6 dark=0 unres=0 inc=0 wall=0.011s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.02 min=0.0001 n=6 mismatch=0 max_dn_ang=5.33142e-11 max_dgrel=6.90633e-10 max_dstopT=1.09151e-10 sum_rhs=13692 esc=6 dark=0 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.02 min=1e-08 n=6 mismatch=0 max_dn_ang=5.33142e-11 max_dgrel=6.90633e-10 max_dstopT=1.09151e-10 sum_rhs=13692 esc=6 dark=0 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.02 min=1e-12 n=6 mismatch=0 max_dn_ang=5.33142e-11 max_dgrel=6.90633e-10 max_dstopT=1.09151e-10 sum_rhs=13692 esc=6 dark=0 unres=0 inc=0 wall=0.003s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.04 min=0.0001 n=6 mismatch=0 max_dn_ang=1.75204e-10 max_dgrel=9.74943e-10 max_dstopT=3.64615e-10 sum_rhs=8484 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.04 min=1e-08 n=6 mismatch=0 max_dn_ang=1.75204e-10 max_dgrel=9.74943e-10 max_dstopT=3.64615e-10 sum_rhs=8484 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.04 min=1e-12 n=6 mismatch=0 max_dn_ang=1.75204e-10 max_dgrel=9.74943e-10 max_dstopT=3.64615e-10 sum_rhs=8484 esc=6 dark=0 unres=0 inc=0 wall=0.002s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.08 min=0.0001 n=6 mismatch=0 max_dn_ang=1.1957e-10 max_dgrel=1.45708e-09 max_dstopT=2.69508e-10 sum_rhs=6251 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.08 min=1e-08 n=6 mismatch=0 max_dn_ang=1.1957e-10 max_dgrel=1.45708e-09 max_dstopT=2.69508e-10 sum_rhs=6251 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.08 min=1e-12 n=6 mismatch=0 max_dn_ang=1.1957e-10 max_dgrel=1.45708e-09 max_dstopT=2.69508e-10 sum_rhs=6251 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.16 min=0.0001 n=6 mismatch=0 max_dn_ang=1.72733e-11 max_dgrel=1.07679e-09 max_dstopT=1.26013e-10 sum_rhs=5278 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.16 min=1e-08 n=6 mismatch=0 max_dn_ang=1.72733e-11 max_dgrel=1.07679e-09 max_dstopT=1.26013e-10 sum_rhs=5278 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.16 min=1e-12 n=6 mismatch=0 max_dn_ang=1.72733e-11 max_dgrel=1.07679e-09 max_dstopT=1.26013e-10 sum_rhs=5278 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.32 min=0.0001 n=6 mismatch=0 max_dn_ang=5.49931e-11 max_dgrel=8.67977e-10 max_dstopT=2.55501e-10 sum_rhs=4872 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.32 min=1e-08 n=6 mismatch=0 max_dn_ang=5.49931e-11 max_dgrel=8.67977e-10 max_dstopT=2.55501e-10 sum_rhs=4872 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY upper alc_v9_s10 upper=0.32 min=1e-12 n=6 mismatch=0 max_dn_ang=5.49931e-11 max_dgrel=8.67977e-10 max_dstopT=2.55501e-10 sum_rhs=4872 esc=6 dark=0 unres=0 inc=0 wall=0.001s
|
||||||
|
SUMMARY min_stress alc_v9_s100 upper=0.004 min=0.0001 n=6 mismatch=0 max_dn_ang=1.69451e-11 max_dgrel=1.33161e-09 max_dstopT=1.05733e-11 sum_rhs=18095 esc=6 dark=0 unres=0 inc=0 wall=0.004s
|
||||||
|
SUMMARY min_stress alc_v9_s100 upper=0.004 min=1e-05 n=6 mismatch=0 max_dn_ang=1.69451e-11 max_dgrel=1.33161e-09 max_dstopT=1.05733e-11 sum_rhs=18095 esc=6 dark=0 unres=0 inc=0 wall=0.004s
|
||||||
|
SUMMARY min_stress alc_v9_s100 upper=0.004 min=1e-06 n=6 mismatch=0 max_dn_ang=1.69451e-11 max_dgrel=1.33161e-09 max_dstopT=1.05733e-11 sum_rhs=18095 esc=6 dark=0 unres=0 inc=0 wall=0.004s
|
||||||
|
SUMMARY min_stress alc_v9_s100 upper=0.004 min=1e-08 n=6 mismatch=0 max_dn_ang=1.69451e-11 max_dgrel=1.33161e-09 max_dstopT=1.05733e-11 sum_rhs=18095 esc=6 dark=0 unres=0 inc=0 wall=0.004s
|
||||||
|
SUMMARY min_stress alc_v9_s100 upper=0.004 min=1e-12 n=6 mismatch=0 max_dn_ang=1.69451e-11 max_dgrel=1.33161e-09 max_dstopT=1.05733e-11 sum_rhs=18095 esc=6 dark=0 unres=0 inc=0 wall=0.004s
|
||||||
|
SUMMARY min_stress alc_v9_s100 upper=0.004 min=1e-14 n=6 mismatch=0 max_dn_ang=1.69451e-11 max_dgrel=1.33161e-09 max_dstopT=1.05733e-11 sum_rhs=18095 esc=6 dark=0 unres=0 inc=0 wall=0.004s
|
||||||
|
TOTAL_RAYS 498
|
||||||
|
|
||||||
|
real 0m0.264s
|
||||||
|
user 0m0.254s
|
||||||
|
sys 0m0.010s
|
||||||
|
+ set +x
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
### command: b_actual
|
||||||
|
+ /tmp/opencode/step_bounds/b_actual
|
||||||
|
B r30_inward dir=0 ref=1 refstop=-69.5728394 span=69.5728 T=20 target=-20 steps=17 reached=1 term=-1 h=[0.1,1.72575] first=0.1 last=0.839319 boundary=1 rhs=119 rej=0 nullmax=3.01e-12 final_t=-20 wall=0.0001s
|
||||||
|
B r30_inward dir=1 ref=0 refstop=-226 span=226 T=20 target=-20 steps=13 reached=1 term=-1 h=[0.1,2] first=0.1 last=0.123959 boundary=1 rhs=91 rej=0 nullmax=8.69e-12 final_t=-20 wall=0.0001s
|
||||||
|
B r30_inward dir=2 ref=1 refstop=-142.175748 span=142.176 T=20 target=-20 steps=20 reached=1 term=-1 h=[0.1,1.40832] first=0.1 last=0.637699 boundary=1 rhs=140 rej=0 nullmax=1.53e-11 final_t=-20 wall=0.0001s
|
||||||
|
B r30_inward dir=3 ref=0 refstop=-370.180478 span=370.18 T=20 target=-20 steps=20 reached=1 term=-1 h=[0.1,1.40832] first=0.1 last=0.6377 boundary=1 rhs=140 rej=0 nullmax=1.53e-11 final_t=-20 wall=0.0001s
|
||||||
|
B r30_inward dir=4 ref=1 refstop=-118.245807 span=118.246 T=20 target=-20 steps=20 reached=1 term=-1 h=[0.1,1.40833] first=0.1 last=0.637634 boundary=1 rhs=140 rej=0 nullmax=1.53e-11 final_t=-20 wall=0.0001s
|
||||||
|
B r30_inward dir=5 ref=0 refstop=-346.252134 span=346.252 T=20 target=-20 steps=20 reached=1 term=-1 h=[0.1,1.40831] first=0.1 last=0.637765 boundary=1 rhs=140 rej=0 nullmax=1.53e-11 final_t=-20 wall=0.0001s
|
||||||
|
B r100_inward dir=0 ref=1 refstop=-144.299101 span=144.299 T=20 target=-20 steps=12 reached=1 term=-1 h=[0.1,2] first=0.1 last=1.4 boundary=1 rhs=84 rej=0 nullmax=1.45e-14 final_t=-20 wall=0.0001s
|
||||||
|
B r100_inward dir=1 ref=0 refstop=-156 span=156 T=20 target=-20 steps=12 reached=1 term=-1 h=[0.1,2] first=0.1 last=1.4 boundary=1 rhs=84 rej=0 nullmax=7.66e-15 final_t=-20 wall=0.0001s
|
||||||
|
B r100_inward dir=2 ref=1 refstop=-301.077405 span=301.077 T=20 target=-20 steps=12 reached=1 term=-1 h=[0.1,2] first=0.1 last=1.4 boundary=1 rhs=84 rej=0 nullmax=1.4e-14 final_t=-20 wall=0.0001s
|
||||||
|
B r100_inward dir=3 ref=1 refstop=-211.027405 span=211.027 T=20 target=-20 steps=12 reached=1 term=-1 h=[0.1,2] first=0.1 last=1.4 boundary=1 rhs=84 rej=0 nullmax=1.32e-14 final_t=-20 wall=0.0001s
|
||||||
|
B r2p1_outward dir=0 ref=0 refstop=-253.9 span=253.9 T=20 target=-20 steps=46 reached=1 term=-1 h=[0.1,1.0708] first=0.1 last=1.06594 boundary=1 rhs=322 rej=0 nullmax=6.27e-11 final_t=-20 wall=0.0002s
|
||||||
|
B r2p1_outward dir=1 ref=0 refstop=-414.940103 span=414.94 T=20 target=-20 steps=105 reached=1 term=-1 h=[0.1,0.211533] first=0.1 last=0.192781 boundary=1 rhs=735 rej=0 nullmax=4.7e-11 final_t=-20 wall=0.0005s
|
||||||
|
B r2p1_outward dir=2 ref=0 refstop=-333.450704 span=333.451 T=20 target=-20 steps=105 reached=1 term=-1 h=[0.1,0.211533] first=0.1 last=0.192739 boundary=1 rhs=735 rej=0 nullmax=4.7e-11 final_t=-20 wall=0.0005s
|
||||||
|
B r2p1_outward dir=3 ref=1 refstop=-109.415611 span=109.416 T=20 target=-20 steps=105 reached=1 term=-1 h=[0.1,0.211532] first=0.1 last=0.192823 boundary=1 rhs=735 rej=0 nullmax=4.7e-11 final_t=-20 wall=0.0005s
|
||||||
|
B r2p1_outward dir=4 ref=1 refstop=-32.2468847 span=32.2469 T=20 target=-20 steps=37 reached=1 term=-1 h=[0.1,0.899361] first=0.1 last=0.332712 boundary=1 rhs=259 rej=0 nullmax=2.99e-11 final_t=-20 wall=0.0002s
|
||||||
|
B r1p5_freefall dir=0 ref=1 refstop=-30.6580907 span=30.6581 T=20 target=-20 steps=49 reached=1 term=-1 h=[0.1,0.695968] first=0.1 last=0.106174 boundary=1 rhs=343 rej=0 nullmax=4.94e-10 final_t=-20 wall=0.0002s
|
||||||
|
B r1p5_freefall dir=1 ref=0 refstop=-254.5 span=254.5 T=20 target=-20 steps=52 reached=1 term=-1 h=[0.0920967,1.08419] first=0.1 last=0.22147 boundary=1 rhs=364 rej=0 nullmax=4.03e-11 final_t=-20 wall=0.0002s
|
||||||
|
B mink_moving dir=0 ref=0 refstop=-51.2640254 span=51.264 T=20 target=-20 steps=3 reached=1 term=-1 h=[1,14] first=1 last=14 boundary=1 rhs=21 rej=0 nullmax=2.22e-16 final_t=-20 wall=0.0000s
|
||||||
|
B mink_moving dir=1 ref=0 refstop=-71.5846741 span=71.5847 T=20 target=-20 steps=3 reached=1 term=-1 h=[1,14] first=1 last=14 boundary=1 rhs=21 rej=0 nullmax=0 final_t=-20 wall=0.0000s
|
||||||
|
B alc_v3_s1 dir=0 ref=0 refstop=-16.4338937 span=16.4339 T=16.4339 target=-16.4339 steps=56 reached=1 term=-1 h=[0.05,0.4] first=0.05 last=0.203538 boundary=1 rhs=406 rej=2 nullmax=0 final_t=-16.4338937 wall=0.0001s
|
||||||
|
B alc_v3_s1 dir=1 ref=0 refstop=-29.3767055 span=29.3767 T=20 target=-20 steps=62 reached=1 term=-1 h=[0.05,0.4] first=0.05 last=0.27784 boundary=1 rhs=441 rej=1 nullmax=0 final_t=-20 wall=0.0001s
|
||||||
|
B alc_v9_s10 dir=0 ref=0 refstop=-2.03742978 span=2.03743 T=2.03743 target=-2.03743 steps=77 reached=1 term=-1 h=[0.005,0.04] first=0.005 last=0.0388523 boundary=1 rhs=588 rej=7 nullmax=0 final_t=-2.03742978 wall=0.0001s
|
||||||
|
B alc_v9_s10 dir=1 ref=0 refstop=-19.9638367 span=19.9638 T=19.9638 target=-19.9638 steps=521 reached=1 term=-1 h=[0.005,0.04] first=0.005 last=0.0365282 boundary=1 rhs=3682 rej=5 nullmax=2.22e-16 final_t=-19.9638367 wall=0.0009s
|
||||||
|
B alc_v9_s100 dir=0 ref=0 refstop=-1.10374298 span=1.10374 T=1.10374 target=-1.10374 steps=302 reached=1 term=-1 h=[0.0005,0.004] first=0.0005 last=0.00388798 boundary=1 rhs=2163 rej=7 nullmax=0 final_t=-1.10374298 wall=0.0005s
|
||||||
|
B alc_v9_s100 dir=1 ref=0 refstop=-2.89638367 span=2.89638 T=2.89638 target=-2.89638 steps=746 reached=1 term=-1 h=[0.0005,0.004] first=0.0005 last=0.00365282 boundary=1 rhs=5257 rej=5 nullmax=2.22e-16 final_t=-2.89638367 wall=0.0012s
|
||||||
|
TOTAL_OBSERVED_STEPS 2427
|
||||||
|
|
||||||
|
real 0m0.152s
|
||||||
|
user 0m0.145s
|
||||||
|
sys 0m0.006s
|
||||||
|
+ set +x
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
{
|
||||||
|
"r100_tight_reference": {
|
||||||
|
"vertices": 3158,
|
||||||
|
"triangles": 6188,
|
||||||
|
"outcomes": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"accepted": 2908050,
|
||||||
|
"rejected": 1963,
|
||||||
|
"rhs": 21294763,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 659,
|
||||||
|
"0.5": 885,
|
||||||
|
"0.9": 1166,
|
||||||
|
"0.99": 1410,
|
||||||
|
"1": 1609
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 0,
|
||||||
|
"0.9": 2,
|
||||||
|
"0.99": 3,
|
||||||
|
"1": 4
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 4900,
|
||||||
|
"0.5": 6496,
|
||||||
|
"0.9": 8463,
|
||||||
|
"0.99": 10171,
|
||||||
|
"1": 11564
|
||||||
|
},
|
||||||
|
"sha256": "a4f7def4212a7dae2b6290fd8635a5f1b087e11b0f8043e60e48fec71ecdb6e4",
|
||||||
|
"wall_seconds": 2.6278538939077407
|
||||||
|
},
|
||||||
|
"r100_ref_vs_0.5": {
|
||||||
|
"shared": 3158,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 6.236425088081268e-08,
|
||||||
|
"max_logg_difference": 8.506182824080666e-10
|
||||||
|
},
|
||||||
|
"r100_ref_vs_2": {
|
||||||
|
"shared": 3158,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 9.216337364737666e-08,
|
||||||
|
"max_logg_difference": 8.199086565935376e-10
|
||||||
|
},
|
||||||
|
"r100_ref_vs_8": {
|
||||||
|
"shared": 3158,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 8.743723551600822e-08,
|
||||||
|
"max_logg_difference": 8.257244662329688e-10
|
||||||
|
},
|
||||||
|
"r100_ref_vs_32": {
|
||||||
|
"shared": 3158,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 8.743704837242435e-08,
|
||||||
|
"max_logg_difference": 8.34318713074933e-10
|
||||||
|
},
|
||||||
|
"r2p1_tight_reference": {
|
||||||
|
"vertices": 5496,
|
||||||
|
"triangles": 10816,
|
||||||
|
"outcomes": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"accepted": 4515098,
|
||||||
|
"rejected": 8672,
|
||||||
|
"rhs": 33269502,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 419,
|
||||||
|
"0.5": 805,
|
||||||
|
"0.9": 1034,
|
||||||
|
"0.99": 1253,
|
||||||
|
"1": 1860
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 1,
|
||||||
|
"0.5": 2,
|
||||||
|
"0.9": 2,
|
||||||
|
"0.99": 3,
|
||||||
|
"1": 3
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 3227,
|
||||||
|
"0.5": 5936,
|
||||||
|
"0.9": 7546,
|
||||||
|
"0.99": 9072,
|
||||||
|
"1": 13328
|
||||||
|
},
|
||||||
|
"sha256": "a81aac81cff2891627e21c22998ceb51d65ef779bb013922cadeb97140274cba",
|
||||||
|
"wall_seconds": 3.180392162874341
|
||||||
|
},
|
||||||
|
"r2p1_ref_vs_0.5": {
|
||||||
|
"shared": 5496,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 1.4772143877471049e-05,
|
||||||
|
"max_logg_difference": 2.098608620215714e-09
|
||||||
|
},
|
||||||
|
"r2p1_ref_vs_2": {
|
||||||
|
"shared": 5496,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 1.4772101910544689e-05,
|
||||||
|
"max_logg_difference": 2.0455042104572385e-09
|
||||||
|
},
|
||||||
|
"r2p1_ref_vs_8": {
|
||||||
|
"shared": 5496,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 1.4772018211627154e-05,
|
||||||
|
"max_logg_difference": 2.059625359152051e-09
|
||||||
|
},
|
||||||
|
"r2p1_ref_vs_32": {
|
||||||
|
"shared": 5496,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 1.4772020763985666e-05,
|
||||||
|
"max_logg_difference": 2.068350379857975e-09
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,354 @@
|
|||||||
|
{
|
||||||
|
"r100_hmax0.5": {
|
||||||
|
"vertices": 3158,
|
||||||
|
"triangles": 6188,
|
||||||
|
"outcomes": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"accepted": 2269662,
|
||||||
|
"rejected": 177,
|
||||||
|
"rhs": 16813349,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 312,
|
||||||
|
"0.5": 736,
|
||||||
|
"0.9": 786,
|
||||||
|
"0.99": 848,
|
||||||
|
"1": 899
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 0,
|
||||||
|
"0.9": 0,
|
||||||
|
"0.99": 1,
|
||||||
|
"1": 1
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 2471,
|
||||||
|
"0.5": 5446,
|
||||||
|
"0.9": 5803,
|
||||||
|
"0.99": 6223,
|
||||||
|
"1": 6587
|
||||||
|
},
|
||||||
|
"sha256": "787386a026203d846debf25a6a4f431a131b06bd3ab464f75f3e17a1d379992a",
|
||||||
|
"wall_seconds": 2.0714269301388413
|
||||||
|
},
|
||||||
|
"r100_hmax2": {
|
||||||
|
"vertices": 3158,
|
||||||
|
"triangles": 6188,
|
||||||
|
"outcomes": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"accepted": 723677,
|
||||||
|
"rejected": 5690,
|
||||||
|
"rhs": 6030185,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 165,
|
||||||
|
"0.5": 220,
|
||||||
|
"0.9": 290,
|
||||||
|
"0.99": 348,
|
||||||
|
"1": 397
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 2,
|
||||||
|
"0.9": 4,
|
||||||
|
"0.99": 5,
|
||||||
|
"1": 5
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 1442,
|
||||||
|
"0.5": 1855,
|
||||||
|
"0.9": 2324,
|
||||||
|
"0.99": 2737,
|
||||||
|
"1": 3073
|
||||||
|
},
|
||||||
|
"sha256": "187c3cbba6a18d88608cd3859da94d88b58ce9d65e0d800d84b3254a6b139151",
|
||||||
|
"wall_seconds": 0.9786226029973477
|
||||||
|
},
|
||||||
|
"r100_hmax8": {
|
||||||
|
"vertices": 3158,
|
||||||
|
"triangles": 6188,
|
||||||
|
"outcomes": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"accepted": 463004,
|
||||||
|
"rejected": 9336,
|
||||||
|
"rhs": 4230835,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 80,
|
||||||
|
"0.5": 133,
|
||||||
|
"0.9": 225,
|
||||||
|
"0.99": 286,
|
||||||
|
"1": 357
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 3,
|
||||||
|
"0.9": 5,
|
||||||
|
"0.99": 6,
|
||||||
|
"1": 7
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 868,
|
||||||
|
"0.5": 1253,
|
||||||
|
"0.9": 1869,
|
||||||
|
"0.99": 2289,
|
||||||
|
"1": 2786
|
||||||
|
},
|
||||||
|
"sha256": "4c7e9d401f2af237129a6a677ca94ed1ee41472594db57852a08647b1dc34aad",
|
||||||
|
"wall_seconds": 0.8228706018999219
|
||||||
|
},
|
||||||
|
"r100_hmax32": {
|
||||||
|
"vertices": 3158,
|
||||||
|
"triangles": 6188,
|
||||||
|
"outcomes": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"0": 2906,
|
||||||
|
"1": 252
|
||||||
|
},
|
||||||
|
"accepted": 441750,
|
||||||
|
"rejected": 9336,
|
||||||
|
"rhs": 4081609,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 72,
|
||||||
|
"0.5": 126,
|
||||||
|
"0.9": 222,
|
||||||
|
"0.99": 285,
|
||||||
|
"1": 357
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 3,
|
||||||
|
"0.9": 5,
|
||||||
|
"0.99": 6,
|
||||||
|
"1": 7
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 812,
|
||||||
|
"0.5": 1204,
|
||||||
|
"0.9": 1848,
|
||||||
|
"0.99": 2282,
|
||||||
|
"1": 2786
|
||||||
|
},
|
||||||
|
"sha256": "3742efd56893bec9e62a01668915ef7dda613d6504b2057043eb97c9b38334f3",
|
||||||
|
"wall_seconds": 0.8300854018889368
|
||||||
|
},
|
||||||
|
"r100_2_vs_0.5": {
|
||||||
|
"shared": 3158,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 3.077090601306577e-08,
|
||||||
|
"max_logg_difference": 5.28674309191457e-11
|
||||||
|
},
|
||||||
|
"r100_2_vs_8": {
|
||||||
|
"shared": 3158,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 7.063214322895989e-09,
|
||||||
|
"max_logg_difference": 3.2702011237839557e-11
|
||||||
|
},
|
||||||
|
"r100_2_vs_32": {
|
||||||
|
"shared": 3158,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 7.063404202987903e-09,
|
||||||
|
"max_logg_difference": 2.477072019724247e-11
|
||||||
|
},
|
||||||
|
"r2p1_hmax0.5": {
|
||||||
|
"vertices": 5496,
|
||||||
|
"triangles": 10816,
|
||||||
|
"outcomes": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"accepted": 2646842,
|
||||||
|
"rejected": 830,
|
||||||
|
"rhs": 20136508,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 116,
|
||||||
|
"0.5": 552,
|
||||||
|
"0.9": 618,
|
||||||
|
"0.99": 672,
|
||||||
|
"1": 823
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 0,
|
||||||
|
"0.9": 1,
|
||||||
|
"0.99": 1,
|
||||||
|
"1": 2
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 1099,
|
||||||
|
"0.5": 4158,
|
||||||
|
"0.9": 4620,
|
||||||
|
"0.99": 4991,
|
||||||
|
"1": 6055
|
||||||
|
},
|
||||||
|
"sha256": "3a77a1e7dee3cd18d3ab8a408826aba932f912dc88749989e0c307013d6e7e81",
|
||||||
|
"wall_seconds": 1.973590083885938
|
||||||
|
},
|
||||||
|
"r2p1_hmax2": {
|
||||||
|
"vertices": 5496,
|
||||||
|
"triangles": 10816,
|
||||||
|
"outcomes": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"accepted": 1131104,
|
||||||
|
"rejected": 4004,
|
||||||
|
"rhs": 9548434,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 109,
|
||||||
|
"0.5": 202,
|
||||||
|
"0.9": 258,
|
||||||
|
"0.99": 311,
|
||||||
|
"1": 460
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 1,
|
||||||
|
"0.9": 1,
|
||||||
|
"0.99": 2,
|
||||||
|
"1": 2
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 1050,
|
||||||
|
"0.5": 1708,
|
||||||
|
"0.9": 2100,
|
||||||
|
"0.99": 2478,
|
||||||
|
"1": 3521
|
||||||
|
},
|
||||||
|
"sha256": "899331ea41d1612cf66bc7664b50e866f4f3bc7309e9c206440f801238ca455c",
|
||||||
|
"wall_seconds": 1.177934248931706
|
||||||
|
},
|
||||||
|
"r2p1_hmax8": {
|
||||||
|
"vertices": 5496,
|
||||||
|
"triangles": 10816,
|
||||||
|
"outcomes": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"accepted": 822680,
|
||||||
|
"rejected": 4004,
|
||||||
|
"rhs": 7389760,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 87,
|
||||||
|
"0.5": 137,
|
||||||
|
"0.9": 212,
|
||||||
|
"0.99": 265,
|
||||||
|
"1": 386
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 1,
|
||||||
|
"0.9": 1,
|
||||||
|
"0.99": 2,
|
||||||
|
"1": 2
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 910,
|
||||||
|
"0.5": 1260,
|
||||||
|
"0.9": 1778,
|
||||||
|
"0.99": 2142,
|
||||||
|
"1": 3003
|
||||||
|
},
|
||||||
|
"sha256": "49edfbe9dfb2948d3472e6ef6287bed103332758953756a7e4089316caa0b1b6",
|
||||||
|
"wall_seconds": 0.9704615350347012
|
||||||
|
},
|
||||||
|
"r2p1_hmax32": {
|
||||||
|
"vertices": 5496,
|
||||||
|
"triangles": 10816,
|
||||||
|
"outcomes": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"1": 1336,
|
||||||
|
"0": 4160
|
||||||
|
},
|
||||||
|
"accepted": 795354,
|
||||||
|
"rejected": 4004,
|
||||||
|
"rhs": 7197806,
|
||||||
|
"accepted_percentiles": {
|
||||||
|
"0": 81,
|
||||||
|
"0.5": 132,
|
||||||
|
"0.9": 210,
|
||||||
|
"0.99": 261,
|
||||||
|
"1": 379
|
||||||
|
},
|
||||||
|
"rejected_percentiles": {
|
||||||
|
"0": 0,
|
||||||
|
"0.5": 1,
|
||||||
|
"0.9": 1,
|
||||||
|
"0.99": 2,
|
||||||
|
"1": 2
|
||||||
|
},
|
||||||
|
"rhs_percentiles": {
|
||||||
|
"0": 861,
|
||||||
|
"0.5": 1218,
|
||||||
|
"0.9": 1757,
|
||||||
|
"0.99": 2128,
|
||||||
|
"1": 2954
|
||||||
|
},
|
||||||
|
"sha256": "74bbb1e969644d49b7fdf5a6a7a5930ca8b962ec91628cd91feeb9df039100e7",
|
||||||
|
"wall_seconds": 0.9720155198592693
|
||||||
|
},
|
||||||
|
"r2p1_2_vs_0.5": {
|
||||||
|
"shared": 5496,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 1.046601929593161e-10,
|
||||||
|
"max_logg_difference": 6.900746640781108e-11
|
||||||
|
},
|
||||||
|
"r2p1_2_vs_8": {
|
||||||
|
"shared": 5496,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 8.369894549651799e-11,
|
||||||
|
"max_logg_difference": 1.9082291302652266e-11
|
||||||
|
},
|
||||||
|
"r2p1_2_vs_32": {
|
||||||
|
"shared": 5496,
|
||||||
|
"only_a": 0,
|
||||||
|
"only_b": 0,
|
||||||
|
"terminal_mismatches": 0,
|
||||||
|
"max_sky_angle": 8.114658658759588e-11,
|
||||||
|
"max_logg_difference": 2.823297151621773e-11
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Experiment A/B environment and source identity
|
||||||
|
date_utc: 2026-10-05T22:15:50Z
|
||||||
|
host: Linux ATRI-gentoo 6.18.48-gentoo #1 SMP PREEMPT_DYNAMIC Mon Aug 31 13:33:24 EDT 2026 x86_64 12th Gen Intel(R) Core(TM) i7-12700K GenuineIntel GNU/Linux
|
||||||
|
nproc: 16
|
||||||
|
cc:
|
||||||
|
cc (Gentoo 16.2.1_p20260926 p1) 16.2.1 20260926
|
||||||
|
Copyright (C) 2026 Free Software Foundation, Inc.
|
||||||
|
This is free software; see the source for copying conditions. There is NO
|
||||||
|
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
|
||||||
|
git_head: c894fdb11a0845558fdb67b71a9bd019a2d94ed4
|
||||||
|
git_status_short:
|
||||||
|
M Makefile
|
||||||
|
M mk/reference_images.mk
|
||||||
|
M nr_spacetime_movie_renderer_design.md
|
||||||
|
M src/asymptotic.c
|
||||||
|
M src/frame.c
|
||||||
|
M src/frame.h
|
||||||
|
M src/geodesic.c
|
||||||
|
M src/geodesic.h
|
||||||
|
M src/lens_map.c
|
||||||
|
M src/lens_map.h
|
||||||
|
M src/main.c
|
||||||
|
M src/ray.c
|
||||||
|
M src/ray.h
|
||||||
|
M tests/test_asymptotic.c
|
||||||
|
M tests/test_camera_cli.py
|
||||||
|
M tests/test_frame.c
|
||||||
|
M usage.md
|
||||||
|
?? nmesh_spacetime_output_format.md
|
||||||
|
?? tests/test_adaptive_cli.py
|
||||||
|
?? tests/test_geodesic_adaptive.c
|
||||||
|
|
||||||
|
# sha256 of the sources consumed by the harnesses
|
||||||
|
25f24a2e1c9ce49508fed230dfb3f6d9986e92bb4a5e6347bb2356ac0ee5fffa src/geodesic.c
|
||||||
|
1e43b95346f484050354631e8682f9793e618cbbd1de6338bd15e092216ae6fb src/geodesic.h
|
||||||
|
e6c0616461507adb1141ca3caa7e76f30e2497c4d53acfef092597fb60431a4a src/asymptotic.c
|
||||||
|
db029ef837f12800bbf81fc74e7bab6eb9f18e42a53ceb5f205867d8a329321d src/asymptotic.h
|
||||||
|
1792a17f432ceee32ee9c802486ecf9d64d96307c249e0d5cfa563ef4a0fefd5 src/asymptotic_schwarzschild.c
|
||||||
|
cc9ad0b04e11bd08bcf238901125e76a26ec332cd7fe72871e7c46fb7a322aec src/asymptotic_schwarzschild.h
|
||||||
|
ea0b5838bc56fbfeedec9110cd20653b892127bfc863db91a3a8cabaad4c520b src/asymptotic_gl48.h
|
||||||
|
359066d78a10f9589a220124147cdbefaff8f97028a9fdd2923b474349599752 src/spacetime.h
|
||||||
|
4c7ae6e96fe57e2a2ae2491db924bad56af59abfcc305bbb6ab2609f3b405e0d src/spacetime_common.c
|
||||||
|
690045ed715a951335dc7d654258e0f3b802e0bf6e2815ceb4858fa99cd372d7 src/spacetime_minkowski.c
|
||||||
|
e5b5935d16e24b07cedb25d184e8f7029075aec9496f54c23cb1061971914a72 src/spacetime_schwarzschild.c
|
||||||
|
75956034303fe3bab9324ecb87533e054458e35a26132a3e885233acad785767 src/spacetime_alcubierre.c
|
||||||
|
559f626983c68e06d3223d8381085a0b5ac422529a1ea656f4e24b1b3a50f51a src/observer.c
|
||||||
|
d761aabfbc277b0989bd20302578302d91f8253a9d900943de62ab3edd3f145b src/observer.h
|
||||||
|
|
||||||
|
# sha256 of the harnesses and this script
|
||||||
|
853018775c335180199aa3a0046445a5f795f83d18de0ff6a664a6368d835dbd a_public_endpoints.c
|
||||||
|
10a6558815e3ff5fa114aa8ca6dfe3c7db6e860ecb9f7cab20c59145a662d3d2 b_actual_h.c
|
||||||
|
1cfd93b0c9f187b4c45d169fbeb8c6fea7f02c3317ac24a32691723b0086548c run_experiment.sh
|
||||||
@@ -0,0 +1,318 @@
|
|||||||
|
# Experiment A/B summary tables
|
||||||
|
|
||||||
|
## A Schwarzschild references (DP tol=1e-12, max_step=0.25)
|
||||||
|
|
||||||
|
| case | dir | theta | outcome | reason | stop_t | steps | rej | rhs | g | thr |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| r30_inward | 0 | 0 | DARK | REDSHIFT | -69.57 | 531 | 0 | 4004 | 0 | 8 |
|
||||||
|
| r30_inward | 1 | 3.142 | ESC | NONE | -226 | 905 | 0 | 6629 | 1.035 | nan |
|
||||||
|
| r30_inward | 2 | 1.571 | ESC | NONE | -256.7 | 1028 | 0 | 7490 | 1.035 | nan |
|
||||||
|
| r30_inward | 3 | 0.1681 | DARK | REDSHIFT | -225.9 | 3746 | 0 | 26509 | 0 | 8 |
|
||||||
|
| r30_inward | 4 | 0.1671 | DARK | REDSHIFT | -94.28 | 1127 | 0 | 8176 | 0 | 8 |
|
||||||
|
| r30_inward | 5 | 0.1691 | ESC | NONE | -322.4 | 1834 | 0 | 13132 | 1.035 | nan |
|
||||||
|
| r30_inward | 6 | 0.1681 | DARK | REDSHIFT | -118.2 | 1606 | 0 | 11529 | 0 | 8 |
|
||||||
|
| r30_inward | 7 | 0.1681 | ESC | NONE | -346.3 | 2312 | 1 | 16485 | 1.035 | nan |
|
||||||
|
| r30_inward | 8 | 0.1681 | DARK | REDSHIFT | -142.2 | 2081 | 0 | 14854 | 0 | 8 |
|
||||||
|
| r30_inward | 9 | 0.1681 | ESC | NONE | -370.2 | 2790 | 1 | 19831 | 1.035 | nan |
|
||||||
|
| r30_inward | 10 | 0.2181 | ESC | NONE | -302.6 | 1409 | 1 | 10164 | 1.035 | nan |
|
||||||
|
| r30_inward | 11 | 0.1181 | DARK | REDSHIFT | -73.76 | 665 | 0 | 4942 | 0 | 8 |
|
||||||
|
| r100_inward | 0 | 0 | DARK | REDSHIFT | -144.3 | 830 | 0 | 6097 | 0 | 8 |
|
||||||
|
| r100_inward | 1 | 3.142 | ESC | NONE | -156 | 625 | 0 | 4669 | 1.01 | nan |
|
||||||
|
| r100_inward | 2 | 1.571 | ESC | NONE | -237.7 | 952 | 0 | 6958 | 1.01 | nan |
|
||||||
|
| r100_inward | 3 | 0.05146 | DARK | REDSHIFT | -301.1 | 4045 | 0 | 28602 | 0 | 8 |
|
||||||
|
| r100_inward | 4 | 0.05046 | DARK | REDSHIFT | -163.1 | 1292 | 0 | 9331 | 0 | 8 |
|
||||||
|
| r100_inward | 5 | 0.05246 | ESC | NONE | -391.6 | 2014 | 1 | 14399 | 1.01 | nan |
|
||||||
|
| r100_inward | 6 | 0.05145 | DARK | REDSHIFT | -187.1 | 1773 | 0 | 12698 | 0 | 8 |
|
||||||
|
| r100_inward | 7 | 0.05147 | ESC | NONE | -415.4 | 2493 | 0 | 17745 | 1.01 | nan |
|
||||||
|
| r100_inward | 8 | 0.05146 | DARK | REDSHIFT | -211 | 2252 | 0 | 16051 | 0 | 8 |
|
||||||
|
| r100_inward | 9 | 0.05146 | ESC | NONE | -439.3 | 2969 | 0 | 21077 | 1.01 | nan |
|
||||||
|
| r100_inward | 10 | 0.1015 | ESC | NONE | -372.3 | 1571 | 0 | 11291 | 1.01 | nan |
|
||||||
|
| r100_inward | 11 | 0.001462 | DARK | REDSHIFT | -144.3 | 830 | 0 | 6097 | 0 | 8 |
|
||||||
|
| r2p1_outward | 0 | 0 | ESC | NONE | -253.9 | 1120 | 1 | 8141 | 4.583 | nan |
|
||||||
|
| r2p1_outward | 1 | 3.142 | DARK | REDSHIFT | -32.25 | 186 | 0 | 1589 | 0 | 8 |
|
||||||
|
| r2p1_outward | 2 | 1.571 | DARK | REDSHIFT | -32.77 | 316 | 1 | 2506 | 0 | 8 |
|
||||||
|
| r2p1_outward | 3 | 0.5704 | ESC | NONE | -414.9 | 4263 | 2 | 30149 | 4.583 | nan |
|
||||||
|
| r2p1_outward | 4 | 0.5694 | ESC | NONE | -285.6 | 1686 | 1 | 12103 | 4.583 | nan |
|
||||||
|
| r2p1_outward | 5 | 0.5714 | DARK | REDSHIFT | -61.58 | 995 | 1 | 7259 | 0 | 8 |
|
||||||
|
| r2p1_outward | 6 | 0.5704 | ESC | NONE | -309.5 | 2162 | 2 | 15442 | 4.583 | nan |
|
||||||
|
| r2p1_outward | 7 | 0.5704 | DARK | REDSHIFT | -85.49 | 1474 | 1 | 10612 | 0 | 8 |
|
||||||
|
| r2p1_outward | 8 | 0.5704 | ESC | NONE | -333.5 | 2639 | 1 | 18774 | 4.583 | nan |
|
||||||
|
| r2p1_outward | 9 | 0.5704 | DARK | REDSHIFT | -109.4 | 1950 | 1 | 13944 | 0 | 8 |
|
||||||
|
| r2p1_outward | 10 | 0.6204 | DARK | REDSHIFT | -41.99 | 585 | 1 | 4389 | 0 | 8 |
|
||||||
|
| r2p1_outward | 11 | 0.5204 | ESC | NONE | -265 | 1303 | 2 | 9429 | 4.583 | nan |
|
||||||
|
| r1p5_freefall | 0 | 0 | DARK | REDSHIFT | -30.66 | 231 | 1 | 1911 | 0 | 8 |
|
||||||
|
| r1p5_freefall | 1 | 1.571 | ESC | NONE | -255.2 | 1130 | 1 | 8211 | 1 | nan |
|
||||||
|
| r1p5_freefall | 2 | 3.142 | ESC | NONE | -254.5 | 1143 | 1 | 8302 | 0.4641 | nan |
|
||||||
|
| r1p5_freefall | 3 | 2.356 | ESC | NONE | -254.6 | 1127 | 1 | 8190 | 0.5505 | nan |
|
||||||
|
|
||||||
|
## A Schwarzschild upper scan (min_step=1e-12, tol=1e-9)
|
||||||
|
|
||||||
|
| case | upper | mismatch | max_dn_ang | max_dgrel | max_dstopT | sum_rhs | max_rej | ESC | DARK | UNRES | INC |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| r100_inward | 0.25 | 0 | 2.604e-05 | 2.048e-09 | 35.2 | 93464 | 0 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 0.5 | 0 | 5.696e-05 | 2.056e-09 | 39.27 | 56595 | 0 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 1 | 0 | 8.348e-05 | 2.051e-09 | 41.25 | 39788 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 2 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 4 | 0 | 8.089e-05 | 2.028e-09 | 41.09 | 29393 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 8 | 0 | 8.034e-05 | 2.034e-09 | 41.06 | 28427 | 3 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 16 | 0 | 8.034e-05 | 2.042e-09 | 41.06 | 28189 | 3 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 32 | 0 | 8.034e-05 | 2.043e-09 | 41.06 | 28182 | 3 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 64 | 0 | 8.034e-05 | 2.043e-09 | 41.06 | 28182 | 3 | 6 | 6 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 0.25 | 0 | 1.002e-10 | 3.165e-10 | 2.608e-08 | 23597 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 0.5 | 0 | 8.875e-11 | 3.658e-10 | 3.089e-08 | 12747 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 1 | 0 | 8.187e-11 | 3.811e-10 | 2.817e-08 | 7553 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 2 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 4 | 0 | 8.157e-11 | 3.632e-10 | 2.346e-08 | 4039 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 8 | 0 | 8.151e-11 | 3.547e-10 | 2.125e-08 | 3591 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 16 | 0 | 8.146e-11 | 3.469e-10 | 1.925e-08 | 3465 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 32 | 0 | 8.146e-11 | 3.46e-10 | 1.948e-08 | 3458 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 64 | 0 | 8.146e-11 | 3.46e-10 | 1.948e-08 | 3458 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r2p1_outward | 0.25 | 1 | 0.0002872 | 2.661e-09 | 263.1 | 62258 | 0 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 0.5 | 1 | 0.0002872 | 2.644e-09 | 263.1 | 42490 | 0 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 1 | 1 | 0.0002872 | 2.615e-09 | 263.1 | 33544 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 2 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 4 | 1 | 0.0002872 | 2.598e-09 | 263.1 | 27580 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 8 | 1 | 0.0002872 | 2.606e-09 | 263.1 | 26831 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 16 | 1 | 0.0002872 | 2.614e-09 | 263.1 | 26614 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 32 | 1 | 0.0002872 | 2.615e-09 | 263.1 | 26607 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 64 | 1 | 0.0002872 | 2.615e-09 | 263.1 | 26607 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r30_inward | 0.25 | 0 | 8.667e-05 | 2.262e-09 | 35.08 | 76510 | 0 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 0.5 | 0 | 0.0001866 | 2.268e-09 | 39.06 | 49063 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 1 | 0 | 0.0002801 | 2.266e-09 | 41.17 | 36974 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 2 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 4 | 0 | 0.0002819 | 2.25e-09 | 41.2 | 29617 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 8 | 0 | 0.0002819 | 2.258e-09 | 41.2 | 28714 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 16 | 0 | 0.0002819 | 2.266e-09 | 41.2 | 28455 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 32 | 0 | 0.0002819 | 2.266e-09 | 41.2 | 28434 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 64 | 0 | 0.0002819 | 2.266e-09 | 41.2 | 28434 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
|
||||||
|
## A Schwarzschild min scan (max_step=2, tol=1e-9)
|
||||||
|
|
||||||
|
| case | min_step | mismatch | max_dn_ang | max_dgrel | max_dstopT | sum_rhs | max_rej | ESC | DARK | UNRES | INC |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| r100_inward | 1e-14 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 1e-12 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 1e-10 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 1e-08 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 1e-06 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 1e-05 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 0.0001 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 0.001 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 0.01 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r100_inward | 0.1 | 0 | 8.286e-05 | 2.026e-09 | 41.22 | 32389 | 1 | 6 | 6 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 1e-14 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 1e-12 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 1e-10 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 1e-08 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 1e-06 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 1e-05 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 0.0001 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 0.001 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 0.01 | 0 | 8.165e-11 | 3.719e-10 | 2.571e-08 | 5131 | 0 | 3 | 1 | 0 | 0 |
|
||||||
|
| r1p5_freefall | 0.1 | 1 | 8.165e-11 | 3.719e-10 | 254.3 | 3654 | 0 | 2 | 1 | 0 | 1 |
|
||||||
|
| r2p1_outward | 1e-14 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 1e-12 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 1e-10 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 1e-08 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 1e-06 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 1e-05 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 0.0001 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 0.001 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 0.01 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r2p1_outward | 0.1 | 1 | 0.0002872 | 2.592e-09 | 263.1 | 29421 | 1 | 5 | 7 | 0 | 0 |
|
||||||
|
| r30_inward | 1e-14 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 1e-12 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 1e-10 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 1e-08 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 1e-06 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 1e-05 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 0.0001 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 0.001 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 0.01 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
| r30_inward | 0.1 | 0 | 0.0002819 | 2.244e-09 | 41.2 | 31843 | 2 | 6 | 6 | 0 | 0 |
|
||||||
|
|
||||||
|
## A Schwarzschild sensitive RK4 .01 vs .005
|
||||||
|
|
||||||
|
| case | dir | theta | out.01 | out.005 | hhalve_dn_ang | |dg| | rhs.01 | rhs.005 |
|
||||||
|
|---|---|---|---|---|---|---|---|---|
|
||||||
|
| r2p1_outward | 6 | 0.5704 | ESC | ESC | 1.032e-07 | 7.386e-12 | 124072 | 247880 |
|
||||||
|
| r2p1_outward | 7 | 0.5704 | DARK | DARK | nan | 0 | 34196 | 68392 |
|
||||||
|
| r2p1_outward | 8 | 0.5704 | ESC | ESC | 1.04e-05 | 7.618e-12 | 133644 | 267024 |
|
||||||
|
| r2p1_outward | 9 | 0.5704 | DARK | DARK | nan | 0 | 43768 | 87536 |
|
||||||
|
| r30_inward | 6 | 0.1681 | DARK | DARK | nan | 0 | 47300 | 94600 |
|
||||||
|
| r30_inward | 7 | 0.1681 | ESC | ESC | 0 | 8.238e-14 | 138764 | 277264 |
|
||||||
|
| r30_inward | 8 | 0.1681 | DARK | DARK | nan | 0 | 56872 | 113744 |
|
||||||
|
| r30_inward | 9 | 0.1681 | ESC | ESC | 1.891e-07 | 7.55e-15 | 148336 | 296408 |
|
||||||
|
|
||||||
|
## A Minkowski flat analytic check (n_inf and t)
|
||||||
|
|
||||||
|
| upper | min_step | n | max_dn_ang | max_dgrel | max_t_err |
|
||||||
|
|---|---|---|---|---|---|
|
||||||
|
| 1 | 1e-12 | 6 | 0 | 0 | 5.258e-13 |
|
||||||
|
| 1 | 1e-06 | 6 | 0 | 0 | 5.258e-13 |
|
||||||
|
| 1 | 0.1 | 6 | 0 | 0 | 5.258e-13 |
|
||||||
|
| 4 | 1e-12 | 6 | 0 | 0 | 1.776e-12 |
|
||||||
|
| 4 | 1e-06 | 6 | 0 | 0 | 1.776e-12 |
|
||||||
|
| 4 | 0.1 | 6 | 0 | 0 | 1.776e-12 |
|
||||||
|
| 16 | 1e-12 | 6 | 0 | 0 | 1.3e-11 |
|
||||||
|
| 16 | 1e-06 | 6 | 0 | 0 | 1.3e-11 |
|
||||||
|
| 16 | 0.1 | 6 | 0 | 0 | 1.3e-11 |
|
||||||
|
| 64 | 1e-12 | 6 | 0 | 0 | 3.894e-11 |
|
||||||
|
| 64 | 1e-06 | 6 | 0 | 0 | 3.894e-11 |
|
||||||
|
| 64 | 0.1 | 6 | 0 | 0 | 3.894e-11 |
|
||||||
|
| 256 | 1e-12 | 6 | 0 | 0 | 7.661e-11 |
|
||||||
|
| 256 | 1e-06 | 6 | 0 | 0 | 7.661e-11 |
|
||||||
|
| 256 | 0.1 | 6 | 0 | 0 | 7.661e-11 |
|
||||||
|
|
||||||
|
## A Minkowski flat analytic check (crossing x and t)
|
||||||
|
|
||||||
|
| upper | min_step | n | max_x_err | max_t_err |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| 1 | 1e-12 | 6 | 4.832e-13 | 5.258e-13 |
|
||||||
|
| 1 | 1e-06 | 6 | 4.832e-13 | 5.258e-13 |
|
||||||
|
| 1 | 0.1 | 6 | 4.832e-13 | 5.258e-13 |
|
||||||
|
| 4 | 1e-12 | 6 | 1.72e-12 | 1.776e-12 |
|
||||||
|
| 4 | 1e-06 | 6 | 1.72e-12 | 1.776e-12 |
|
||||||
|
| 4 | 0.1 | 6 | 1.72e-12 | 1.776e-12 |
|
||||||
|
| 16 | 1e-12 | 6 | 1.268e-11 | 1.3e-11 |
|
||||||
|
| 16 | 1e-06 | 6 | 1.268e-11 | 1.3e-11 |
|
||||||
|
| 16 | 0.1 | 6 | 1.268e-11 | 1.3e-11 |
|
||||||
|
| 64 | 1e-12 | 6 | 3.506e-11 | 3.894e-11 |
|
||||||
|
| 64 | 1e-06 | 6 | 3.506e-11 | 3.894e-11 |
|
||||||
|
| 64 | 0.1 | 6 | 3.506e-11 | 3.894e-11 |
|
||||||
|
| 256 | 1e-12 | 6 | 7.061e-11 | 7.661e-11 |
|
||||||
|
| 256 | 1e-06 | 6 | 7.061e-11 | 7.661e-11 |
|
||||||
|
| 256 | 0.1 | 6 | 7.061e-11 | 7.661e-11 |
|
||||||
|
|
||||||
|
## A Alcubierre alc_v3_s1 upper scan
|
||||||
|
|
||||||
|
| case | upper | mismatch | max_dn_ang | max_dgrel | max_dstopT | sum_rhs | max_rej | ESC | DARK | UNRES | INC |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| alc_v3_s1 | 0.05 | 0 | 7.544e-14 | 7.627e-13 | 1.99e-13 | 19740 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.05 | 0 | 7.544e-14 | 7.627e-13 | 1.99e-13 | 19740 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.05 | 0 | 7.544e-14 | 7.627e-13 | 1.99e-13 | 19740 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.2 | 0 | 1.208e-10 | 3.452e-10 | 4.091e-10 | 6475 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.2 | 0 | 1.208e-10 | 3.452e-10 | 4.091e-10 | 6475 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.2 | 0 | 1.208e-10 | 3.452e-10 | 4.091e-10 | 6475 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.4 | 0 | 1.03e-10 | 3.464e-10 | 3.143e-10 | 4613 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.4 | 0 | 1.03e-10 | 3.464e-10 | 3.143e-10 | 4613 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.4 | 0 | 1.03e-10 | 3.464e-10 | 3.143e-10 | 4613 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.8 | 0 | 7.888e-11 | 7.954e-10 | 7.369e-10 | 3794 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.8 | 0 | 7.888e-11 | 7.954e-10 | 7.369e-10 | 3794 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0.8 | 0 | 7.888e-11 | 7.954e-10 | 7.369e-10 | 3794 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 1.6 | 0 | 1.239e-10 | 1.118e-09 | 1.148e-09 | 3430 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 1.6 | 0 | 1.239e-10 | 1.118e-09 | 1.148e-09 | 3430 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 1.6 | 0 | 1.239e-10 | 1.118e-09 | 1.148e-09 | 3430 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 3.2 | 0 | 1.545e-10 | 1.26e-09 | 1.346e-09 | 3290 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 3.2 | 0 | 1.545e-10 | 1.26e-09 | 1.346e-09 | 3290 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 3.2 | 0 | 1.545e-10 | 1.26e-09 | 1.346e-09 | 3290 | 2 | 6 | 0 | 0 | 0 |
|
||||||
|
|
||||||
|
## A Alcubierre alc_v3_s10 upper scan
|
||||||
|
|
||||||
|
| case | upper | mismatch | max_dn_ang | max_dgrel | max_dstopT | sum_rhs | max_rej | ESC | DARK | UNRES | INC |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| alc_v3_s10 | 0.005 | 0 | 5.829e-15 | 3.109e-14 | 4.663e-14 | 27412 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.005 | 0 | 5.829e-15 | 3.109e-14 | 4.663e-14 | 27412 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.005 | 0 | 5.829e-15 | 3.109e-14 | 4.663e-14 | 27412 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.02 | 0 | 6.299e-12 | 2.402e-10 | 1.399e-11 | 8337 | 4 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.02 | 0 | 6.299e-12 | 2.402e-10 | 1.399e-11 | 8337 | 4 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.02 | 0 | 6.299e-12 | 2.402e-10 | 1.399e-11 | 8337 | 4 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.04 | 0 | 3.288e-11 | 3.854e-10 | 6.294e-11 | 5621 | 6 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.04 | 0 | 3.288e-11 | 3.854e-10 | 6.294e-11 | 5621 | 6 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.04 | 0 | 3.288e-11 | 3.854e-10 | 6.294e-11 | 5621 | 6 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.08 | 0 | 1.042e-11 | 2.781e-10 | 8.024e-11 | 4648 | 12 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.08 | 0 | 1.042e-11 | 2.781e-10 | 8.024e-11 | 4648 | 12 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.08 | 0 | 1.042e-11 | 2.781e-10 | 8.024e-11 | 4648 | 12 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.16 | 0 | 1.131e-11 | 7.6e-10 | 9.538e-11 | 4270 | 13 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.16 | 0 | 1.131e-11 | 7.6e-10 | 9.538e-11 | 4270 | 13 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.16 | 0 | 1.131e-11 | 7.6e-10 | 9.538e-11 | 4270 | 13 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.32 | 0 | 3.131e-11 | 9.778e-10 | 1.041e-10 | 4116 | 13 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.32 | 0 | 3.131e-11 | 9.778e-10 | 1.041e-10 | 4116 | 13 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v3_s10 | 0.32 | 0 | 3.131e-11 | 9.778e-10 | 1.041e-10 | 4116 | 13 | 6 | 0 | 0 | 0 |
|
||||||
|
|
||||||
|
## A Alcubierre alc_v9_s1 upper scan
|
||||||
|
|
||||||
|
| case | upper | mismatch | max_dn_ang | max_dgrel | max_dstopT | sum_rhs | max_rej | ESC | DARK | UNRES | INC |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| alc_v9_s1 | 0.05 | 0 | 6.632e-13 | 2.591e-11 | 1.387e-11 | 39452 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.05 | 0 | 6.632e-13 | 2.591e-11 | 1.387e-11 | 39452 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.05 | 0 | 6.632e-13 | 2.591e-11 | 1.387e-11 | 39452 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.2 | 0 | 1.078e-10 | 2.073e-09 | 6.805e-10 | 11690 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.2 | 0 | 1.078e-10 | 2.073e-09 | 6.805e-10 | 11690 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.2 | 0 | 1.078e-10 | 2.073e-09 | 6.805e-10 | 11690 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.4 | 0 | 6.25e-11 | 2.466e-09 | 1.083e-09 | 7413 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.4 | 0 | 6.25e-11 | 2.466e-09 | 1.083e-09 | 7413 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.4 | 0 | 6.25e-11 | 2.466e-09 | 1.083e-09 | 7413 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.8 | 0 | 5.349e-11 | 2.718e-09 | 1.186e-09 | 5369 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.8 | 0 | 5.349e-11 | 2.718e-09 | 1.186e-09 | 5369 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 0.8 | 0 | 5.349e-11 | 2.718e-09 | 1.186e-09 | 5369 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 1.6 | 0 | 1.035e-10 | 2.819e-09 | 9.549e-10 | 4431 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 1.6 | 0 | 1.035e-10 | 2.819e-09 | 9.549e-10 | 4431 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 1.6 | 0 | 1.035e-10 | 2.819e-09 | 9.549e-10 | 4431 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 3.2 | 0 | 1.239e-10 | 2.823e-09 | 3.249e-09 | 3983 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 3.2 | 0 | 1.239e-10 | 2.823e-09 | 3.249e-09 | 3983 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s1 | 3.2 | 0 | 1.239e-10 | 2.823e-09 | 3.249e-09 | 3983 | 3 | 6 | 0 | 0 | 0 |
|
||||||
|
|
||||||
|
## A Alcubierre alc_v9_s10 upper scan
|
||||||
|
|
||||||
|
| case | upper | mismatch | max_dn_ang | max_dgrel | max_dstopT | sum_rhs | max_rej | ESC | DARK | UNRES | INC |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| alc_v9_s10 | 0.005 | 0 | 8.937e-14 | 1.103e-11 | 3.553e-13 | 48167 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.005 | 0 | 8.937e-14 | 1.103e-11 | 3.553e-13 | 48167 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.005 | 0 | 8.937e-14 | 1.103e-11 | 3.553e-13 | 48167 | 0 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.02 | 0 | 5.331e-11 | 6.906e-10 | 1.092e-10 | 13692 | 6 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.02 | 0 | 5.331e-11 | 6.906e-10 | 1.092e-10 | 13692 | 6 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.02 | 0 | 5.331e-11 | 6.906e-10 | 1.092e-10 | 13692 | 6 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.04 | 0 | 1.752e-10 | 9.749e-10 | 3.646e-10 | 8484 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.04 | 0 | 1.752e-10 | 9.749e-10 | 3.646e-10 | 8484 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.04 | 0 | 1.752e-10 | 9.749e-10 | 3.646e-10 | 8484 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.08 | 0 | 1.196e-10 | 1.457e-09 | 2.695e-10 | 6251 | 12 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.08 | 0 | 1.196e-10 | 1.457e-09 | 2.695e-10 | 6251 | 12 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.08 | 0 | 1.196e-10 | 1.457e-09 | 2.695e-10 | 6251 | 12 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.16 | 0 | 1.727e-11 | 1.077e-09 | 1.26e-10 | 5278 | 15 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.16 | 0 | 1.727e-11 | 1.077e-09 | 1.26e-10 | 5278 | 15 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.16 | 0 | 1.727e-11 | 1.077e-09 | 1.26e-10 | 5278 | 15 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.32 | 0 | 5.499e-11 | 8.68e-10 | 2.555e-10 | 4872 | 14 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.32 | 0 | 5.499e-11 | 8.68e-10 | 2.555e-10 | 4872 | 14 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s10 | 0.32 | 0 | 5.499e-11 | 8.68e-10 | 2.555e-10 | 4872 | 14 | 6 | 0 | 0 | 0 |
|
||||||
|
|
||||||
|
## A Alcubierre v9 s100 lower-bound stress (upper=0.004)
|
||||||
|
|
||||||
|
| case | min_step | mismatch | max_dn_ang | max_dgrel | max_dstopT | sum_rhs | max_rej | ESC | DARK | UNRES | INC |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| alc_v9_s100 | 1e-14 | 0 | 1.695e-11 | 1.332e-09 | 1.057e-11 | 18095 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s100 | 1e-12 | 0 | 1.695e-11 | 1.332e-09 | 1.057e-11 | 18095 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s100 | 1e-08 | 0 | 1.695e-11 | 1.332e-09 | 1.057e-11 | 18095 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s100 | 1e-06 | 0 | 1.695e-11 | 1.332e-09 | 1.057e-11 | 18095 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s100 | 1e-05 | 0 | 1.695e-11 | 1.332e-09 | 1.057e-11 | 18095 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
| alc_v9_s100 | 0.0001 | 0 | 1.695e-11 | 1.332e-09 | 1.057e-11 | 18095 | 7 | 6 | 0 | 0 | 0 |
|
||||||
|
|
||||||
|
## B observed accepted step h (finite T=min(20, ref span))
|
||||||
|
|
||||||
|
| case | dir | ref | span | target | steps | reached | term | h_min | h_max | h_first | bnd | rhs | rej | null_max |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| r30_inward | 0 | DARK | 69.57 | -20 | 17 | 1 | -1 | 0.1 | 1.726 | 0.1 | 1 | 119 | 0 | 3.009e-12 |
|
||||||
|
| r30_inward | 1 | ESC | 226 | -20 | 13 | 1 | -1 | 0.1 | 2 | 0.1 | 1 | 91 | 0 | 8.69e-12 |
|
||||||
|
| r30_inward | 2 | DARK | 142.2 | -20 | 20 | 1 | -1 | 0.1 | 1.408 | 0.1 | 1 | 140 | 0 | 1.526e-11 |
|
||||||
|
| r30_inward | 3 | ESC | 370.2 | -20 | 20 | 1 | -1 | 0.1 | 1.408 | 0.1 | 1 | 140 | 0 | 1.526e-11 |
|
||||||
|
| r30_inward | 4 | DARK | 118.2 | -20 | 20 | 1 | -1 | 0.1 | 1.408 | 0.1 | 1 | 140 | 0 | 1.526e-11 |
|
||||||
|
| r30_inward | 5 | ESC | 346.3 | -20 | 20 | 1 | -1 | 0.1 | 1.408 | 0.1 | 1 | 140 | 0 | 1.526e-11 |
|
||||||
|
| r100_inward | 0 | DARK | 144.3 | -20 | 12 | 1 | -1 | 0.1 | 2 | 0.1 | 1 | 84 | 0 | 1.454e-14 |
|
||||||
|
| r100_inward | 1 | ESC | 156 | -20 | 12 | 1 | -1 | 0.1 | 2 | 0.1 | 1 | 84 | 0 | 7.661e-15 |
|
||||||
|
| r100_inward | 2 | DARK | 301.1 | -20 | 12 | 1 | -1 | 0.1 | 2 | 0.1 | 1 | 84 | 0 | 1.399e-14 |
|
||||||
|
| r100_inward | 3 | DARK | 211 | -20 | 12 | 1 | -1 | 0.1 | 2 | 0.1 | 1 | 84 | 0 | 1.321e-14 |
|
||||||
|
| r2p1_outward | 0 | ESC | 253.9 | -20 | 46 | 1 | -1 | 0.1 | 1.071 | 0.1 | 1 | 322 | 0 | 6.274e-11 |
|
||||||
|
| r2p1_outward | 1 | ESC | 414.9 | -20 | 105 | 1 | -1 | 0.1 | 0.2115 | 0.1 | 1 | 735 | 0 | 4.698e-11 |
|
||||||
|
| r2p1_outward | 2 | ESC | 333.5 | -20 | 105 | 1 | -1 | 0.1 | 0.2115 | 0.1 | 1 | 735 | 0 | 4.698e-11 |
|
||||||
|
| r2p1_outward | 3 | DARK | 109.4 | -20 | 105 | 1 | -1 | 0.1 | 0.2115 | 0.1 | 1 | 735 | 0 | 4.698e-11 |
|
||||||
|
| r2p1_outward | 4 | DARK | 32.25 | -20 | 37 | 1 | -1 | 0.1 | 0.8994 | 0.1 | 1 | 259 | 0 | 2.991e-11 |
|
||||||
|
| r1p5_freefall | 0 | DARK | 30.66 | -20 | 49 | 1 | -1 | 0.1 | 0.696 | 0.1 | 1 | 343 | 0 | 4.938e-10 |
|
||||||
|
| r1p5_freefall | 1 | ESC | 254.5 | -20 | 52 | 1 | -1 | 0.0921 | 1.084 | 0.1 | 1 | 364 | 0 | 4.034e-11 |
|
||||||
|
| mink_moving | 0 | ESC | 51.26 | -20 | 3 | 1 | -1 | 1 | 14 | 1 | 1 | 21 | 0 | 2.22e-16 |
|
||||||
|
| mink_moving | 1 | ESC | 71.58 | -20 | 3 | 1 | -1 | 1 | 14 | 1 | 1 | 21 | 0 | 0 |
|
||||||
|
| alc_v3_s1 | 0 | ESC | 16.43 | -16.43 | 56 | 1 | -1 | 0.05 | 0.4 | 0.05 | 1 | 406 | 2 | 0 |
|
||||||
|
| alc_v3_s1 | 1 | ESC | 29.38 | -20 | 62 | 1 | -1 | 0.05 | 0.4 | 0.05 | 1 | 441 | 1 | 0 |
|
||||||
|
| alc_v9_s10 | 0 | ESC | 2.037 | -2.037 | 77 | 1 | -1 | 0.005 | 0.04 | 0.005 | 1 | 588 | 7 | 0 |
|
||||||
|
| alc_v9_s10 | 1 | ESC | 19.96 | -19.96 | 521 | 1 | -1 | 0.005 | 0.04 | 0.005 | 1 | 3682 | 5 | 2.22e-16 |
|
||||||
|
| alc_v9_s100 | 0 | ESC | 1.104 | -1.104 | 302 | 1 | -1 | 0.0005 | 0.004 | 0.0005 | 1 | 2163 | 7 | 0 |
|
||||||
|
| alc_v9_s100 | 1 | ESC | 2.896 | -2.896 | 746 | 1 | -1 | 0.0005 | 0.004 | 0.0005 | 1 | 5257 | 5 | 2.22e-16 |
|
||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""One-task, at-most-two-attempt 4K comparison (R100, 3840x2160, FOV45).
|
||||||
|
|
||||||
|
This driver does NOT run as part of routine verification. It refuses to do
|
||||||
|
anything unless ``--authorize-two-4k`` is passed explicitly, and an attempt
|
||||||
|
ledger makes the task non-repeatable. Any future execution requires a fresh,
|
||||||
|
explicit user authorization for that task; authorization never extends to later
|
||||||
|
tasks or routine tests.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
run_4k_pair.py --authorize-two-4k [--out DIR]
|
||||||
|
|
||||||
|
OUT defaults to <repo>/local/adaptive_bounds_4k (distinct from any older
|
||||||
|
one-off ledger). The renderer binary is expected at
|
||||||
|
build/Release/schwarzschild_sky (see README for the make command).
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from mesh_maps import load, compare
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
ENV = dict(os.environ, OMP_NUM_THREADS='16', OMP_DYNAMIC='FALSE')
|
||||||
|
BUILD_CMD = 'make -j4 BUILD_TYPE=Release SPACETIME=schwarzschild backend'
|
||||||
|
|
||||||
|
REFUSAL = (
|
||||||
|
'REFUSING TO RUN: the 4K hmax 2-vs-8 pair is a one-task, at-most-two-attempt '
|
||||||
|
'experiment. Pass --authorize-two-4k only after an explicit fresh user '
|
||||||
|
'authorization for this task. It is not a routine verification target.')
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser(description=__doc__)
|
||||||
|
ap.add_argument('--authorize-two-4k', action='store_true',
|
||||||
|
help='explicit authorization for the two-attempt 4K pair')
|
||||||
|
ap.add_argument('--out', default=str(ROOT / 'local/adaptive_bounds_4k'),
|
||||||
|
help='output directory (default: local/adaptive_bounds_4k)')
|
||||||
|
args = ap.parse_args()
|
||||||
|
if not args.authorize_two_4k:
|
||||||
|
print(REFUSAL, file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
out = Path(args.out).resolve()
|
||||||
|
binary = ROOT / 'build/Release/schwarzschild_sky'
|
||||||
|
if not binary.exists():
|
||||||
|
print(f'missing {binary}; build it first:\n {BUILD_CMD}',
|
||||||
|
file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
out.mkdir(parents=True, exist_ok=True)
|
||||||
|
ledger = out / 'attempts.json'
|
||||||
|
attempts = json.loads(ledger.read_text()) if ledger.exists() else []
|
||||||
|
if attempts:
|
||||||
|
print('This one-task pair has already been attempted; no reruns '
|
||||||
|
'authorized.', file=sys.stderr)
|
||||||
|
return 3
|
||||||
|
catalog = out / 'single_dim_star.csv'
|
||||||
|
catalog.write_text('longitude_deg,latitude_deg,temperature_K,amplitude\n'
|
||||||
|
'262.5,-30,6000,1e-30\n')
|
||||||
|
with (out / 'cpu.txt').open('w') as f:
|
||||||
|
subprocess.run(['lscpu'], stdout=f, check=True)
|
||||||
|
metadata = {
|
||||||
|
'binary_sha256': hashlib.sha256(binary.read_bytes()).hexdigest(),
|
||||||
|
'utc': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
|
||||||
|
'source_sha256': {
|
||||||
|
p: hashlib.sha256((ROOT / p).read_bytes()).hexdigest()
|
||||||
|
for p in ('src/main.c', 'src/geodesic.c', 'src/frame.c')},
|
||||||
|
'catalog': 'one negligible synthetic point; no survey catalog',
|
||||||
|
'scope': 'README R100 45-degree 3840x2160 coarse16 refine4 jacobian0.2',
|
||||||
|
'threads': 16, 'max_attempts': 2,
|
||||||
|
'authorization': 'explicit --authorize-two-4k for this task only'}
|
||||||
|
(out / 'metadata.json').write_text(json.dumps(metadata, indent=2) + '\n')
|
||||||
|
maps = {}
|
||||||
|
results = {}
|
||||||
|
for upper in (2, 8):
|
||||||
|
name = f'r100_4k_hmax{upper}'
|
||||||
|
cmd = [str(binary), '--integrator', 'dp54', '--width', '3840',
|
||||||
|
'--height', '2160', '--look-ra-deg', '262.5',
|
||||||
|
'--look-dec-deg', '-30', '--fov-deg', '45',
|
||||||
|
'--observer-radius', '100', '--coarse-cell-pixels', '16',
|
||||||
|
'--refine-max-level', '4', '--refine-jacobian-min', '.2',
|
||||||
|
'--catalog', str(catalog), '--exposure', '1',
|
||||||
|
'--tone-map', 'reinhard', '--psf-min-y', '1e-20',
|
||||||
|
'--psf-relative-tail', '1e-4', '--ode-min-step', '1e-12',
|
||||||
|
'--ode-max-step', str(upper), '--verbose',
|
||||||
|
'--lens-map-output', str(out / (name + '.grlens')),
|
||||||
|
'--output', str(out / (name + '.png'))]
|
||||||
|
attempts.append({'upper': upper, 'command': shlex.join(cmd),
|
||||||
|
'state': 'attempted'})
|
||||||
|
ledger.write_text(json.dumps(attempts, indent=2) + '\n')
|
||||||
|
start = time.perf_counter()
|
||||||
|
with (out / (name + '.log')).open('w') as log:
|
||||||
|
log.write('OMP_NUM_THREADS=16 OMP_DYNAMIC=FALSE ' +
|
||||||
|
shlex.join(cmd) + '\n')
|
||||||
|
log.flush()
|
||||||
|
result = subprocess.run(cmd, cwd=ROOT, env=ENV, stdout=log,
|
||||||
|
stderr=subprocess.STDOUT, timeout=900)
|
||||||
|
attempts[-1].update(returncode=result.returncode,
|
||||||
|
wall_seconds=time.perf_counter() - start,
|
||||||
|
state='completed')
|
||||||
|
ledger.write_text(json.dumps(attempts, indent=2) + '\n')
|
||||||
|
if result.returncode:
|
||||||
|
raise SystemExit(f'4K attempt failed: {name}; no automatic retry.')
|
||||||
|
info, maps[upper] = load(out / (name + '.grlens'))
|
||||||
|
info['wall_seconds'] = attempts[-1]['wall_seconds']
|
||||||
|
results[name] = info
|
||||||
|
print(name, json.dumps(info), flush=True)
|
||||||
|
results['comparison'] = compare(maps[2], maps[8])
|
||||||
|
p, q = (results[f'r100_4k_hmax{h}']['provenance'] for h in (2, 8))
|
||||||
|
assert p['max_step'] == 2 and q['max_step'] == 8
|
||||||
|
assert {k: v for k, v in p.items() if k != 'max_step'} == \
|
||||||
|
{k: v for k, v in q.items() if k != 'max_step'}
|
||||||
|
print('comparison', json.dumps(results['comparison']), flush=True)
|
||||||
|
(out / 'summary.json').write_text(json.dumps(results, indent=2) + '\n')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Run the standalone critical-classification reference check
|
||||||
|
# (benchmarks/adaptive_step_bounds_2026-10-05/critical_ref_check.c).
|
||||||
|
#
|
||||||
|
# benchmarks/adaptive_step_bounds_2026-10-05/run_critical_ref.sh [OUT_DIR]
|
||||||
|
#
|
||||||
|
# OUT_DIR defaults to <repo>/local/adaptive_step_bounds_2026-10-05. All output
|
||||||
|
# stays under OUT_DIR; the tracked benchmark directory holds only the sources.
|
||||||
|
# This is a diagnostic probe (see the C file header); it makes no pass/fail
|
||||||
|
# claim about the exactly-critical physical outcome.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SOURCE=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
root=$(cd "$SOURCE/../.." && pwd)
|
||||||
|
OUT=${1:-$root/local/adaptive_step_bounds_2026-10-05}
|
||||||
|
BIN=/tmp/opencode/step_bounds
|
||||||
|
|
||||||
|
mkdir -p "$OUT/raw" "$OUT/logs" "$BIN"
|
||||||
|
cd "$OUT"
|
||||||
|
OUT=$PWD
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "### building critical_ref_check"
|
||||||
|
set -x
|
||||||
|
cc -std=c11 -O2 -Wall -Wextra -Wpedantic -I"$root/src" \
|
||||||
|
"$SOURCE/critical_ref_check.c" "$root/src/geodesic.c" \
|
||||||
|
"$root/src/asymptotic.c" "$root/src/asymptotic_schwarzschild.c" \
|
||||||
|
"$root/src/spacetime_common.c" "$root/src/observer.c" -lm \
|
||||||
|
-o "$BIN/critical_ref_check"
|
||||||
|
echo "### command: critical_ref_check"
|
||||||
|
time "$BIN/critical_ref_check"
|
||||||
|
set +x
|
||||||
|
} > logs/critical_ref.log 2>&1
|
||||||
|
|
||||||
|
cat logs/critical_ref.log
|
||||||
|
echo "outputs under $OUT"
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build and run the failure-path floor diagnostic.
|
||||||
|
#
|
||||||
|
# benchmarks/adaptive_step_bounds_2026-10-05/run_failure_floor.sh [OUT_DIR]
|
||||||
|
#
|
||||||
|
# OUT_DIR defaults to <repo>/local/adaptive_bounds_mesh. All output stays
|
||||||
|
# under OUT_DIR; the tracked benchmark directory holds only the sources.
|
||||||
|
#
|
||||||
|
# failure_floor.c includes ../../tests/test_geodesic_adaptive.c (depth-2 path
|
||||||
|
# valid from this directory) and therefore requires -DGEODESIC_EVENT_TESTING
|
||||||
|
# and the production RayPool source src/ray.c. The two analytic backends are
|
||||||
|
# textually included by the regression file, so they are not linked here.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SOURCE=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
root=$(cd "$SOURCE/../.." && pwd)
|
||||||
|
OUT=${1:-$root/local/adaptive_bounds_mesh}
|
||||||
|
BIN=/tmp/opencode/step_bounds
|
||||||
|
|
||||||
|
mkdir -p "$OUT/logs" "$BIN"
|
||||||
|
cd "$OUT"
|
||||||
|
|
||||||
|
{
|
||||||
|
set -x
|
||||||
|
cc -std=c11 -O2 -Wall -Wextra -Wpedantic -fopenmp -DGEODESIC_EVENT_TESTING \
|
||||||
|
-I"$root/src" \
|
||||||
|
"$SOURCE/failure_floor.c" "$root/src/geodesic.c" "$root/src/ray.c" \
|
||||||
|
"$root/src/spacetime_common.c" "$root/src/observer.c" \
|
||||||
|
"$root/src/asymptotic.c" "$root/src/asymptotic_schwarzschild.c" -lm \
|
||||||
|
-o "$BIN/failure_floor"
|
||||||
|
"$BIN/failure_floor"
|
||||||
|
set +x
|
||||||
|
} > logs/failure_floor.log 2>&1
|
||||||
|
|
||||||
|
cat logs/failure_floor.log
|
||||||
|
echo "outputs under $OUT"
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Long-term reproduction driver for the adaptive step-bound scan (Experiment A/B).
|
||||||
|
#
|
||||||
|
# benchmarks/adaptive_step_bounds_2026-10-05/run_limited.sh [OUT_DIR]
|
||||||
|
#
|
||||||
|
# OUT_DIR defaults to <repo>/local/adaptive_step_bounds_2026-10-05. All build
|
||||||
|
# and run output — env/hash record, build log, stdout logs and per-ray CSV —
|
||||||
|
# is written under OUT_DIR, never into this tracked benchmark directory.
|
||||||
|
# Scratch binaries go to /tmp/opencode/step_bounds.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SOURCE=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
root=$(cd "$SOURCE/../.." && pwd)
|
||||||
|
OUT=${1:-$root/local/adaptive_step_bounds_2026-10-05}
|
||||||
|
BIN=/tmp/opencode/step_bounds
|
||||||
|
|
||||||
|
mkdir -p "$OUT/raw" "$OUT/logs" "$BIN"
|
||||||
|
cd "$OUT"
|
||||||
|
OUT=$PWD
|
||||||
|
|
||||||
|
SRC_COMMON="$root/src/geodesic.c $root/src/asymptotic.c \
|
||||||
|
$root/src/asymptotic_schwarzschild.c $root/src/spacetime_common.c \
|
||||||
|
$root/src/observer.c"
|
||||||
|
|
||||||
|
# --- environment + source identity (full shell output) --------------------
|
||||||
|
{
|
||||||
|
echo "# adaptive_step_bounds_2026-10-05 environment and source identity"
|
||||||
|
echo "date_utc: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
echo "host: $(uname -a)"
|
||||||
|
echo "nproc: $(nproc)"
|
||||||
|
echo "cc:"; cc --version
|
||||||
|
echo
|
||||||
|
echo "git_head: $(git -C "$root" rev-parse HEAD 2>/dev/null || echo none)"
|
||||||
|
echo "git_status_short:"; git -C "$root" status --short 2>/dev/null || true
|
||||||
|
echo
|
||||||
|
echo "# sha256 of the production sources consumed by the harnesses"
|
||||||
|
sha256sum $SRC_COMMON
|
||||||
|
echo
|
||||||
|
echo "# sha256 of the benchmark harnesses"
|
||||||
|
sha256sum "$SOURCE/a_public_endpoints.c" "$SOURCE/b_actual_h.c" \
|
||||||
|
"$SOURCE/summarize.py" "$SOURCE/run_limited.sh"
|
||||||
|
} > logs/env.txt 2>&1
|
||||||
|
cat logs/env.txt
|
||||||
|
|
||||||
|
# --- build ----------------------------------------------------------------
|
||||||
|
{
|
||||||
|
echo "### building a_public_endpoints"
|
||||||
|
set -x
|
||||||
|
cc -std=c11 -O2 -Wall -Wextra -Wpedantic -I"$root/src" \
|
||||||
|
"$SOURCE/a_public_endpoints.c" $SRC_COMMON -lm -o "$BIN/a_public"
|
||||||
|
echo "### building b_actual_h"
|
||||||
|
cc -std=c11 -O2 -Wall -Wextra -Wpedantic -I"$root/src" \
|
||||||
|
"$SOURCE/b_actual_h.c" "$root/src/asymptotic.c" \
|
||||||
|
"$root/src/asymptotic_schwarzschild.c" "$root/src/spacetime_common.c" \
|
||||||
|
"$root/src/observer.c" -lm -o "$BIN/b_actual"
|
||||||
|
set +x
|
||||||
|
} > logs/build.log 2>&1
|
||||||
|
cat logs/build.log
|
||||||
|
|
||||||
|
# --- Experiment A ---------------------------------------------------------
|
||||||
|
{
|
||||||
|
echo "### command: a_public schwarzschild"
|
||||||
|
set -x; time "$BIN/a_public" schwarzschild; set +x
|
||||||
|
echo "### command: a_public minkowski"
|
||||||
|
set -x; time "$BIN/a_public" minkowski; set +x
|
||||||
|
echo "### command: a_public alcubierre"
|
||||||
|
set -x; time "$BIN/a_public" alcubierre; set +x
|
||||||
|
} > logs/expA.log 2>&1
|
||||||
|
grep -E '^(SUMMARY|TOTAL_RAYS|real|user)' logs/expA.log | tail -20
|
||||||
|
|
||||||
|
# --- Experiment B ---------------------------------------------------------
|
||||||
|
{
|
||||||
|
echo "### command: b_actual"
|
||||||
|
set -x; time "$BIN/b_actual"; set +x
|
||||||
|
} > logs/expB.log 2>&1
|
||||||
|
cat logs/expB.log
|
||||||
|
|
||||||
|
# --- summary tables -------------------------------------------------------
|
||||||
|
python3 "$SOURCE/summarize.py" "$OUT"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "rays A = $(grep '^TOTAL_RAYS' logs/expA.log | awk '{s+=$2} END{print s}')"
|
||||||
|
echo "observed steps B = $(grep '^TOTAL_OBSERVED_STEPS' logs/expB.log | awk '{print $2}')"
|
||||||
|
echo "outputs under $OUT"
|
||||||
+84
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Bounded 320x180 adaptive-mesh candidates (8 cases; no 4K, no references).
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
run_mesh.py [OUT_DIR]
|
||||||
|
|
||||||
|
OUT_DIR defaults to <repo>/local/adaptive_bounds_mesh. The renderer binary is
|
||||||
|
expected to already exist at build/Release/schwarzschild_sky; build it with
|
||||||
|
(make command is also in README.md):
|
||||||
|
|
||||||
|
make -j4 BUILD_TYPE=Release SPACETIME=schwarzschild backend
|
||||||
|
|
||||||
|
No survey catalog is used: the script writes a one-point synthetic dim catalog
|
||||||
|
with the required column header (longitude_deg,latitude_deg,temperature_K,
|
||||||
|
amplitude) and a 1e-30 amplitude star. No external CSV is read.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from mesh_maps import load, compare # tracked sibling module (no local/ import)
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
OUT = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else \
|
||||||
|
ROOT / 'local/adaptive_bounds_mesh'
|
||||||
|
BIN = ROOT / 'build/Release/schwarzschild_sky'
|
||||||
|
BUILD_CMD = 'make -j4 BUILD_TYPE=Release SPACETIME=schwarzschild backend'
|
||||||
|
ENV = dict(os.environ, OMP_NUM_THREADS='8', OMP_DYNAMIC='FALSE')
|
||||||
|
|
||||||
|
|
||||||
|
def scene_args(scene):
|
||||||
|
if scene == 'r100':
|
||||||
|
return ['--observer-radius', '100', '--look-ra-deg', '262.5',
|
||||||
|
'--look-dec-deg', '-30', '--fov-deg', '45',
|
||||||
|
'--refine-jacobian-min', '.2']
|
||||||
|
return ['--observer-position', '2.1', '0', '0', '--observer-velocity',
|
||||||
|
'0', '0', '0', '--look-ra-deg', '0', '--look-dec-deg', '0',
|
||||||
|
'--fov-deg', '90']
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not BIN.exists():
|
||||||
|
raise SystemExit(f'missing {BIN}; build it first:\n {BUILD_CMD}')
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
catalog = OUT / 'single_dim_star.csv'
|
||||||
|
catalog.write_text('longitude_deg,latitude_deg,temperature_K,amplitude\n'
|
||||||
|
'262.5,-30,6000,1e-30\n')
|
||||||
|
results = {}
|
||||||
|
for scene in ('r100', 'r2p1'):
|
||||||
|
meshes = {}
|
||||||
|
for upper in (.5, 2, 8, 32):
|
||||||
|
name = f'{scene}_hmax{upper:g}'
|
||||||
|
cmd = [str(BIN), '--integrator', 'dp54',
|
||||||
|
'--width', '320', '--height', '180',
|
||||||
|
'--coarse-cell-pixels', '8', '--refine-max-level', '3',
|
||||||
|
'--catalog', str(catalog), '--exposure', '1',
|
||||||
|
'--psf-min-y', '1e-20', '--psf-relative-tail', '1e-4',
|
||||||
|
'--ode-min-step', '1e-12', '--ode-max-step', str(upper),
|
||||||
|
'--verbose', '--lens-map-output', str(OUT / (name + '.grlens')),
|
||||||
|
'--output', str(OUT / (name + '.png')), *scene_args(scene)]
|
||||||
|
start = time.perf_counter()
|
||||||
|
with (OUT / (name + '.log')).open('w') as log:
|
||||||
|
log.write('OMP_NUM_THREADS=8 OMP_DYNAMIC=FALSE ' +
|
||||||
|
shlex.join(cmd) + '\n')
|
||||||
|
log.flush()
|
||||||
|
subprocess.run(cmd, cwd=ROOT, env=ENV, stdout=log,
|
||||||
|
stderr=subprocess.STDOUT, check=True, timeout=180)
|
||||||
|
info, meshes[upper] = load(OUT / (name + '.grlens'))
|
||||||
|
info['wall_seconds'] = time.perf_counter() - start
|
||||||
|
results[name] = info
|
||||||
|
print(name, json.dumps(info), flush=True)
|
||||||
|
for upper in (.5, 8, 32):
|
||||||
|
comparison = compare(meshes[2], meshes[upper])
|
||||||
|
results[f'{scene}_2_vs_{upper:g}'] = comparison
|
||||||
|
print(f'{scene} 2 vs {upper:g}', json.dumps(comparison), flush=True)
|
||||||
|
(OUT / 'summary.json').write_text(json.dumps(results, indent=2) + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Two bounded tight-tolerance mesh references and comparisons (no 4K).
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
run_mesh_reference.py [OUT_DIR]
|
||||||
|
|
||||||
|
OUT_DIR defaults to <repo>/local/adaptive_bounds_mesh and must already contain
|
||||||
|
the eight ``<scene>_hmax<h>.grlens`` maps from ``run_mesh.py``. The renderer
|
||||||
|
binary is expected at build/Release/schwarzschild_sky (see README for the make
|
||||||
|
command). Same one-point synthetic dim catalog, no external CSV.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
from mesh_maps import load, compare
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
OUT = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else \
|
||||||
|
ROOT / 'local/adaptive_bounds_mesh'
|
||||||
|
BIN = ROOT / 'build/Release/schwarzschild_sky'
|
||||||
|
BUILD_CMD = 'make -j4 BUILD_TYPE=Release SPACETIME=schwarzschild backend'
|
||||||
|
ENV = dict(os.environ, OMP_NUM_THREADS='8', OMP_DYNAMIC='FALSE')
|
||||||
|
|
||||||
|
|
||||||
|
def scene_args(scene):
|
||||||
|
if scene == 'r100':
|
||||||
|
return ['--observer-radius', '100', '--look-ra-deg', '262.5',
|
||||||
|
'--look-dec-deg', '-30', '--fov-deg', '45',
|
||||||
|
'--refine-jacobian-min', '.2']
|
||||||
|
return ['--observer-position', '2.1', '0', '0', '--observer-velocity',
|
||||||
|
'0', '0', '0', '--look-ra-deg', '0', '--look-dec-deg', '0',
|
||||||
|
'--fov-deg', '90']
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not BIN.exists():
|
||||||
|
raise SystemExit(f'missing {BIN}; build it first:\n {BUILD_CMD}')
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
catalog = OUT / 'single_dim_star.csv'
|
||||||
|
if not catalog.exists():
|
||||||
|
catalog.write_text('longitude_deg,latitude_deg,temperature_K,amplitude\n'
|
||||||
|
'262.5,-30,6000,1e-30\n')
|
||||||
|
results = {}
|
||||||
|
for scene in ('r100', 'r2p1'):
|
||||||
|
name = scene + '_tight_reference'
|
||||||
|
cmd = [str(BIN), '--integrator', 'dp54', '--width', '320',
|
||||||
|
'--height', '180', '--coarse-cell-pixels', '8',
|
||||||
|
'--refine-max-level', '3', '--catalog', str(catalog),
|
||||||
|
'--exposure', '1', '--psf-min-y', '1e-20',
|
||||||
|
'--psf-relative-tail', '1e-4', '--ode-min-step', '1e-12',
|
||||||
|
'--ode-max-step', '.5', '--ode-rtol', '1e-12',
|
||||||
|
'--ode-atol-x', '1e-12', '--ode-atol-pi', '1e-12',
|
||||||
|
'--ode-atol-l', '1e-12', '--verbose',
|
||||||
|
'--lens-map-output', str(OUT / (name + '.grlens')),
|
||||||
|
'--output', str(OUT / (name + '.png')), *scene_args(scene)]
|
||||||
|
start = time.perf_counter()
|
||||||
|
with (OUT / (name + '.log')).open('w') as log:
|
||||||
|
log.write('OMP_NUM_THREADS=8 OMP_DYNAMIC=FALSE ' +
|
||||||
|
shlex.join(cmd) + '\n')
|
||||||
|
log.flush()
|
||||||
|
subprocess.run(cmd, cwd=ROOT, env=ENV, stdout=log,
|
||||||
|
stderr=subprocess.STDOUT, check=True, timeout=180)
|
||||||
|
info, ref = load(OUT / (name + '.grlens'))
|
||||||
|
info['wall_seconds'] = time.perf_counter() - start
|
||||||
|
results[name] = info
|
||||||
|
print(name, json.dumps(info), flush=True)
|
||||||
|
for upper in (.5, 2, 8, 32):
|
||||||
|
_, vertices = load(OUT / f'{scene}_hmax{upper:g}.grlens')
|
||||||
|
result = compare(ref, vertices)
|
||||||
|
results[f'{scene}_ref_vs_{upper:g}'] = result
|
||||||
|
print(scene, 'ref vs', upper, json.dumps(result), flush=True)
|
||||||
|
(OUT / 'reference_summary.json').write_text(
|
||||||
|
json.dumps(results, indent=2) + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -0,0 +1,261 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Summarise the adaptive-step-bounds benchmark raw CSV logs.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
summarize.py [OUT_DIR]
|
||||||
|
|
||||||
|
Reads ``OUT_DIR/raw/*.csv`` (written by ``run_limited.sh``) and writes
|
||||||
|
``OUT_DIR/logs/summary.txt``. It has no dependency on any untracked script or
|
||||||
|
on older local data.
|
||||||
|
|
||||||
|
Defaults: OUT_DIR = <repo>/local/adaptive_step_bounds_2026-10-05, derived from
|
||||||
|
this file's location (benchmarks/adaptive_step_bounds_2026-10-05/).
|
||||||
|
"""
|
||||||
|
import csv
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
ROOT = os.path.dirname(os.path.dirname(HERE))
|
||||||
|
DEFAULT_OUT = os.path.join(ROOT, "local", "adaptive_step_bounds_2026-10-05")
|
||||||
|
|
||||||
|
OUTCOME = {0: "ESC", 1: "DARK", 2: "UNRES", 3: "INC"}
|
||||||
|
REASON = {
|
||||||
|
0: "NONE",
|
||||||
|
1: "REDSHIFT",
|
||||||
|
2: "BUDGET",
|
||||||
|
3: "TIMERANGE",
|
||||||
|
4: "DOMAIN",
|
||||||
|
5: "INVMETRIC",
|
||||||
|
6: "INTEGERR",
|
||||||
|
7: "UNSUPPORTED",
|
||||||
|
8: "PROTOCOL",
|
||||||
|
9: "IO",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def fnum(v):
|
||||||
|
if v is None or v == "" or v == "nan":
|
||||||
|
return math.nan
|
||||||
|
return float(v)
|
||||||
|
|
||||||
|
|
||||||
|
def fmt(v):
|
||||||
|
if isinstance(v, float):
|
||||||
|
if math.isnan(v):
|
||||||
|
return "nan"
|
||||||
|
if v == 0:
|
||||||
|
return "0"
|
||||||
|
return f"{v:.4g}"
|
||||||
|
return str(v)
|
||||||
|
|
||||||
|
|
||||||
|
def table(title, header, recs):
|
||||||
|
lines = [f"## {title}", ""]
|
||||||
|
lines.append("| " + " | ".join(header) + " |")
|
||||||
|
lines.append("|" + "|".join(["---"] * len(header)) + "|")
|
||||||
|
for r in recs:
|
||||||
|
lines.append("| " + " | ".join(fmt(x) for x in r) + " |")
|
||||||
|
lines.append("")
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def ang_between(a, b):
|
||||||
|
va = [fnum(a["nx"]), fnum(a["ny"]), fnum(a["nz"])]
|
||||||
|
vb = [fnum(b["nx"]), fnum(b["ny"]), fnum(b["nz"])]
|
||||||
|
na = math.sqrt(sum(x * x for x in va))
|
||||||
|
nb = math.sqrt(sum(x * x for x in vb))
|
||||||
|
if not (na > 0 and nb > 0):
|
||||||
|
return math.nan
|
||||||
|
cross = (va[1]*vb[2]-va[2]*vb[1],
|
||||||
|
va[2]*vb[0]-va[0]*vb[2],
|
||||||
|
va[0]*vb[1]-va[1]*vb[0])
|
||||||
|
dot = sum(x * y for x, y in zip(va, vb))
|
||||||
|
return math.atan2(math.sqrt(sum(x*x for x in cross)), dot)
|
||||||
|
|
||||||
|
|
||||||
|
class Raw:
|
||||||
|
def __init__(self, out_dir):
|
||||||
|
self.raw = os.path.join(out_dir, "raw")
|
||||||
|
self.logs = os.path.join(out_dir, "logs")
|
||||||
|
|
||||||
|
def rows(self, name):
|
||||||
|
with open(os.path.join(self.raw, name)) as f:
|
||||||
|
return list(csv.DictReader(f))
|
||||||
|
|
||||||
|
|
||||||
|
def summarise_agg(raw, name, title, keycol):
|
||||||
|
recs = raw.rows(name)
|
||||||
|
out = []
|
||||||
|
for r in recs:
|
||||||
|
out.append((r["case"], float(r[keycol]), int(r["class_mismatch"]),
|
||||||
|
fnum(r["max_dn_ang"]), fnum(r["max_dgrel"]),
|
||||||
|
fnum(r["max_dstopT"]), int(r["sum_rhs"]),
|
||||||
|
int(r["max_rejected"]), int(r["escaped"]), int(r["dark"]),
|
||||||
|
int(r["unresolved"]), int(r["incomplete"])))
|
||||||
|
out.sort(key=lambda x: (x[0], x[1]))
|
||||||
|
return table(title,
|
||||||
|
["case", keycol, "mismatch", "max_dn_ang", "max_dgrel",
|
||||||
|
"max_dstopT", "sum_rhs", "max_rej", "ESC", "DARK", "UNRES",
|
||||||
|
"INC"], out)
|
||||||
|
|
||||||
|
|
||||||
|
def build(raw):
|
||||||
|
lines = ["# Adaptive-step-bounds benchmark summary tables", ""]
|
||||||
|
|
||||||
|
ref = raw.rows("a_sch_reference.csv")
|
||||||
|
recs = []
|
||||||
|
for r in ref:
|
||||||
|
recs.append((r["case"], int(r["dir"]), fnum(r["theta"]),
|
||||||
|
OUTCOME[int(r["outcome"])], REASON[int(r["reason"])],
|
||||||
|
fnum(r["stop_t"]), int(r["steps"]), int(r["rejected"]),
|
||||||
|
int(r["rhs"]), fnum(r["g"]), fnum(r["thr"])))
|
||||||
|
lines += table("A Schwarzschild references (DP tol=1e-12, max_step=0.25)",
|
||||||
|
["case", "dir", "theta", "outcome", "reason", "stop_t",
|
||||||
|
"steps", "rej", "rhs", "g", "thr"], recs)
|
||||||
|
|
||||||
|
lines += summarise_agg(raw, "a_sch_upper_summary.csv",
|
||||||
|
"A Schwarzschild upper scan (min_step=1e-12, "
|
||||||
|
"tol=1e-9)", "upper")
|
||||||
|
lines += summarise_agg(raw, "a_sch_min_summary.csv",
|
||||||
|
"A Schwarzschild min scan (max_step=2, tol=1e-9)",
|
||||||
|
"min_step")
|
||||||
|
|
||||||
|
rk = raw.rows("a_sch_rk4_sensitive.csv")
|
||||||
|
groups = {}
|
||||||
|
for r in rk:
|
||||||
|
groups.setdefault((r["case"], r["dir"]), {})[r["phase"]] = r
|
||||||
|
recs = []
|
||||||
|
for (case, d), gg in sorted(groups.items()):
|
||||||
|
a = gg.get("rk4_0.01")
|
||||||
|
b = gg.get("rk4_0.005")
|
||||||
|
if not a or not b:
|
||||||
|
continue
|
||||||
|
dn = math.nan if a["outcome"] != b["outcome"] else ang_between(a, b)
|
||||||
|
dg = (math.nan if a["outcome"] != b["outcome"]
|
||||||
|
else abs(fnum(a["g"]) - fnum(b["g"])))
|
||||||
|
recs.append((case, d, fnum(a["theta"]), OUTCOME[int(a["outcome"])],
|
||||||
|
OUTCOME[int(b["outcome"])], dn, dg, int(a["rhs"]),
|
||||||
|
int(b["rhs"])))
|
||||||
|
lines += table("A Schwarzschild sensitive RK4 .01 vs .005",
|
||||||
|
["case", "dir", "theta", "out.01", "out.005",
|
||||||
|
"hhalve_dn_ang", "|dg|", "rhs.01", "rhs.005"], recs)
|
||||||
|
|
||||||
|
mk = raw.rows("a_mink_analytic.csv")
|
||||||
|
mkx = raw.rows("a_mink_analytic_x.csv")
|
||||||
|
groups = {}
|
||||||
|
for r in mk:
|
||||||
|
groups.setdefault((r["upper"], r["min_step"]), []).append(r)
|
||||||
|
recs = []
|
||||||
|
for (u, f), g in sorted(groups.items(),
|
||||||
|
key=lambda kv: (float(kv[0][0]), float(kv[0][1]))):
|
||||||
|
recs.append((u, f, len(g), max(fnum(r["dn_ang"]) for r in g),
|
||||||
|
max(fnum(r["dgrel"]) for r in g),
|
||||||
|
max(fnum(r["t_err"]) for r in g)))
|
||||||
|
lines += table("A Minkowski flat analytic check (n_inf and t)",
|
||||||
|
["upper", "min_step", "n", "max_dn_ang", "max_dgrel",
|
||||||
|
"max_t_err"], recs)
|
||||||
|
groups = {}
|
||||||
|
for r in mkx:
|
||||||
|
groups.setdefault((r["upper"], r["min_step"]), []).append(r)
|
||||||
|
recs = []
|
||||||
|
for (u, f), g in sorted(groups.items(),
|
||||||
|
key=lambda kv: (float(kv[0][0]), float(kv[0][1]))):
|
||||||
|
maxx = max(max(fnum(r["x_err_x"]), fnum(r["x_err_y"]),
|
||||||
|
fnum(r["x_err_z"])) for r in g)
|
||||||
|
recs.append((u, f, len(g), maxx, max(fnum(r["t_err"]) for r in g)))
|
||||||
|
lines += table("A Minkowski flat analytic check (crossing x and t)",
|
||||||
|
["upper", "min_step", "n", "max_x_err", "max_t_err"], recs)
|
||||||
|
|
||||||
|
for case in ["alc_v3_s1", "alc_v3_s10", "alc_v9_s1", "alc_v9_s10"]:
|
||||||
|
lines += summarise_agg(raw, f"a_alc_{case}_upper_summary.csv",
|
||||||
|
f"A Alcubierre {case} upper scan", "upper")
|
||||||
|
lines += summarise_agg(raw, "a_alc_v9_s100_min_summary.csv",
|
||||||
|
"A Alcubierre v9 s100 lower-bound stress "
|
||||||
|
"(upper=0.004)", "min_step")
|
||||||
|
|
||||||
|
b = raw.rows("b_summary.csv")
|
||||||
|
recs = []
|
||||||
|
for r in b:
|
||||||
|
recs.append((r["case"], int(r["dir"]),
|
||||||
|
OUTCOME[int(r["ref_outcome"])], fnum(r["span"]),
|
||||||
|
fnum(r["target"]), int(r["observed_steps"]),
|
||||||
|
int(r["reached_target"]),
|
||||||
|
REASON.get(int(r["terminated_reason"]),
|
||||||
|
r["terminated_reason"]),
|
||||||
|
fnum(r["h_min"]), fnum(r["h_max"]), fnum(r["h_first"]),
|
||||||
|
int(r["boundary_steps"]), int(r["sum_rhs"]),
|
||||||
|
int(r["sum_reject"]), fnum(r["null_residual_max"])))
|
||||||
|
lines += table("B observed accepted step h (finite T=min(20, ref span))",
|
||||||
|
["case", "dir", "ref", "span", "target", "steps", "reached",
|
||||||
|
"term", "h_min", "h_max", "h_first", "bnd", "rhs", "rej",
|
||||||
|
"null_max"], recs)
|
||||||
|
|
||||||
|
if os.path.exists(os.path.join(raw.raw, "critical_ref.csv")):
|
||||||
|
lines += critical_section(raw)
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def critical_section(raw):
|
||||||
|
rows = raw.rows("critical_ref.csv")
|
||||||
|
key = {}
|
||||||
|
for r in rows:
|
||||||
|
key[(r["camera"], int(r["dir"]), r["cfg"])] = r
|
||||||
|
lines = table("critical reference check (raw rows)",
|
||||||
|
["camera", "dir", "theta", "cfg", "outcome", "reason",
|
||||||
|
"end_id", "stop_t", "steps", "rejected", "rhs", "g", "thr",
|
||||||
|
"L", "L0"],
|
||||||
|
[(r["camera"], int(r["dir"]), fnum(r["theta"]), r["cfg"],
|
||||||
|
OUTCOME[int(r["outcome"])], REASON[int(r["reason"])],
|
||||||
|
r["end_id"], fnum(r["stop_t"]), int(r["steps"]),
|
||||||
|
int(r["rejected"]), int(r["rhs"]), fnum(r["g"]),
|
||||||
|
fnum(r["thr"]), fnum(r.get("L")), fnum(r.get("L0")))
|
||||||
|
for r in rows])
|
||||||
|
# pair comparisons
|
||||||
|
pairs = [("ref_tol1e-12_h0.25", "ref_tol1e-13_h0.125"),
|
||||||
|
("tol1e-11_h2", "tol1e-11_h8"),
|
||||||
|
("ref_tol1e-12_h0.25", "tol1e-11_h2"),
|
||||||
|
("ref_tol1e-12_h0.25", "tol1e-11_h8")]
|
||||||
|
for a_cfg, b_cfg in pairs:
|
||||||
|
recs = []
|
||||||
|
for (cam, di, cfg), a in sorted(key.items()):
|
||||||
|
if cfg != a_cfg:
|
||||||
|
continue
|
||||||
|
b = key.get((cam, di, b_cfg))
|
||||||
|
if not b:
|
||||||
|
continue
|
||||||
|
same = a["outcome"] == b["outcome"]
|
||||||
|
dn = ang_between(a, b) if same else math.nan
|
||||||
|
dg = (math.nan if not same else
|
||||||
|
abs(fnum(a["g"]) / fnum(b["g"]) - 1.0)
|
||||||
|
if fnum(a["g"]) > 0 and fnum(b["g"]) > 0 else math.nan)
|
||||||
|
dstop = (fnum(a["stop_t"]) - fnum(b["stop_t"])
|
||||||
|
if fnum(a["stop_t"]) == fnum(a["stop_t"]) and
|
||||||
|
fnum(b["stop_t"]) == fnum(b["stop_t"]) else math.nan)
|
||||||
|
dmar = (fnum(a["thr"]) - fnum(b["thr"])
|
||||||
|
if fnum(a["thr"]) == fnum(a["thr"]) and
|
||||||
|
fnum(b["thr"]) == fnum(b["thr"]) else math.nan)
|
||||||
|
recs.append((cam, di, fnum(a["theta"]),
|
||||||
|
OUTCOME[int(a["outcome"])], OUTCOME[int(b["outcome"])],
|
||||||
|
same, dn, dg, dstop, dmar))
|
||||||
|
lines += table(f"critical pair {a_cfg} vs {b_cfg}",
|
||||||
|
["camera", "dir", "theta", "a", "b", "same",
|
||||||
|
"dn_ang", "dgrel", "dstop_t", "dthr"], recs)
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
out = argv[1] if len(argv) > 1 else DEFAULT_OUT
|
||||||
|
raw = Raw(out)
|
||||||
|
os.makedirs(raw.logs, exist_ok=True)
|
||||||
|
lines = build(raw)
|
||||||
|
path = os.path.join(raw.logs, "summary.txt")
|
||||||
|
with open(path, "w") as f:
|
||||||
|
f.write("\n".join(lines) + "\n")
|
||||||
|
print(f"wrote {path} ({len(lines)} lines)")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main(sys.argv))
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Postprocess existing 4K/limited maps only; never invokes a renderer.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
summarize_4k.py [OUT_DIR]
|
||||||
|
|
||||||
|
OUT_DIR defaults to <repo>/local/adaptive_bounds_4k and must contain
|
||||||
|
``r100_4k_hmax2.grlens``, ``r100_4k_hmax8.grlens`` and ``attempts.json``.
|
||||||
|
Writes summary.json in OUT_DIR.
|
||||||
|
|
||||||
|
Cost scope note: accepted/rejected/RHS sums cover the final persistent map
|
||||||
|
vertices only. Nonpersistent discarded refinement probes are not stored in the
|
||||||
|
v3 map, so these sums are not full-render executed RHS totals.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from mesh_maps import load, compare
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
|
OUT = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else \
|
||||||
|
ROOT / 'local/adaptive_bounds_4k'
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
summaries = {}
|
||||||
|
meshes = {}
|
||||||
|
for upper in (2, 8):
|
||||||
|
name = f'r100_4k_hmax{upper}'
|
||||||
|
summaries[name], meshes[upper] = load(OUT / (name + '.grlens'))
|
||||||
|
text = (OUT / (name + '.log')).read_text()
|
||||||
|
initial = int(re.search(r'tracing (\d+) initial rays', text).group(1))
|
||||||
|
generations = [int(n) for n in re.findall(
|
||||||
|
r'refinement generation \d+ tracing (\d+) samples', text)]
|
||||||
|
summaries[name]['requested_samples_including_nonpersistent_probes'] = \
|
||||||
|
initial + sum(generations)
|
||||||
|
summaries[name]['initial_samples'] = initial
|
||||||
|
summaries[name]['refinement_samples_per_generation'] = generations
|
||||||
|
summaries[name]['trace_wall_seconds'] = sum(
|
||||||
|
float(x) for x in re.findall(
|
||||||
|
r'(?:initial ray trace|adaptive ray-trace refinement) '
|
||||||
|
r'finished in ([\d.]+) s', text))
|
||||||
|
ledger = OUT / 'attempts.json'
|
||||||
|
if ledger.exists():
|
||||||
|
for entry in json.loads(ledger.read_text()):
|
||||||
|
if entry.get('state') == 'completed':
|
||||||
|
summaries[f'r100_4k_hmax{entry["upper"]}']['wall_seconds'] = \
|
||||||
|
entry['wall_seconds']
|
||||||
|
summaries['comparison'] = compare(meshes[2], meshes[8])
|
||||||
|
a, b = (summaries[f'r100_4k_hmax{upper}'] for upper in (2, 8))
|
||||||
|
summaries['relative_reduction'] = {
|
||||||
|
key: 1 - b[key] / a[key]
|
||||||
|
for key in ('accepted', 'rhs', 'wall_seconds', 'trace_wall_seconds')}
|
||||||
|
summaries['comparison']['triangle_payload_identical'] = \
|
||||||
|
a['triangle_sha256'] == b['triangle_sha256']
|
||||||
|
summaries['cost_scope'] = (
|
||||||
|
'accepted/rejected/RHS sums cover final persistent vertices only; '
|
||||||
|
'nonpersistent discarded refinement probes are not in the v3 map. '
|
||||||
|
'Do not interpret them as full-render executed RHS totals.')
|
||||||
|
(OUT / 'summary.json').write_text(json.dumps(summaries, indent=2) + '\n')
|
||||||
|
print(json.dumps(summaries, indent=2))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
REFERENCE_DIR := tests/data/psf_event_sink_reference
|
REFERENCE_DIR := tests/data/psf_event_sink_reference
|
||||||
REFERENCE_TMP_DIR := /tmp/gr_psf_event_sink_reference
|
REFERENCE_TMP_DIR := /tmp/opencode/gr_psf_event_sink_reference
|
||||||
FLOATDIFF_SCRIPT := scripts/fits_floatdiff.py
|
FLOATDIFF_SCRIPT := scripts/fits_floatdiff.py
|
||||||
|
|
||||||
.PHONY: test-reference-images
|
.PHONY: test-reference-images
|
||||||
@@ -9,8 +9,8 @@ test: test-reference-images
|
|||||||
test-reference-images: $(FLOATDIFF_SCRIPT) $(REFERENCE_DIR)/minkowski_ra1_dec1_640x360_HDR.fits $(REFERENCE_DIR)/schwarzschild_ra1_dec1_fov60_640x360_HDR.fits
|
test-reference-images: $(FLOATDIFF_SCRIPT) $(REFERENCE_DIR)/minkowski_ra1_dec1_640x360_HDR.fits $(REFERENCE_DIR)/schwarzschild_ra1_dec1_fov60_640x360_HDR.fits
|
||||||
$(MAKE) SPACETIME=minkowski ENABLE_HDR=1 backend
|
$(MAKE) SPACETIME=minkowski ENABLE_HDR=1 backend
|
||||||
mkdir -p $(REFERENCE_TMP_DIR)
|
mkdir -p $(REFERENCE_TMP_DIR)
|
||||||
OMP_NUM_THREADS=16 $(BUILD_DIR)/minkowski_sky --catalog assets/sky_grid_5deg.csv --output $(REFERENCE_TMP_DIR)/minkowski_ra1_dec1_640x360.$(IMAGE_EXT) --hdr-output --width 640 --height 360 --fov-deg 30 --look-ra-deg 1 --look-dec-deg 1 --exposure 0.1 --observer-radius 30 --observer-velocity 0 0 0 --psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5 --max-magnification 1e300 --max-cache-psf-flux 1 --psf-relative-tail 1e-8 --psf-min-y 0 --coarse-cell-pixels 16 --refine-max-level 0 --refine-angle-abs-deg 0.001 --refine-angle-rel 0.1 --refine-jacobian-min 1e-3 --refine-min-edge-pixels 0.5 --refine-min-area-pixels2 0.25 --catalog-load-workers 4
|
OMP_NUM_THREADS=16 $(BUILD_DIR)/minkowski_sky --integrator rk4 --catalog assets/sky_grid_5deg.csv --output $(REFERENCE_TMP_DIR)/minkowski_ra1_dec1_640x360.$(IMAGE_EXT) --hdr-output --width 640 --height 360 --fov-deg 30 --look-ra-deg 1 --look-dec-deg 1 --exposure 0.1 --observer-radius 30 --observer-velocity 0 0 0 --psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5 --max-magnification 1e300 --max-cache-psf-flux 1 --psf-relative-tail 1e-8 --psf-min-y 0 --coarse-cell-pixels 16 --refine-max-level 0 --refine-angle-abs-deg 0.001 --refine-angle-rel 0.1 --refine-jacobian-min 1e-3 --refine-min-edge-pixels 0.5 --refine-min-area-pixels2 0.25 --catalog-load-workers 4
|
||||||
python3 $(FLOATDIFF_SCRIPT) $(REFERENCE_DIR)/minkowski_ra1_dec1_640x360_HDR.fits $(REFERENCE_TMP_DIR)/minkowski_ra1_dec1_640x360_HDR.fits
|
python3 $(FLOATDIFF_SCRIPT) $(REFERENCE_DIR)/minkowski_ra1_dec1_640x360_HDR.fits $(REFERENCE_TMP_DIR)/minkowski_ra1_dec1_640x360_HDR.fits
|
||||||
$(MAKE) SPACETIME=schwarzschild ENABLE_HDR=1 backend
|
$(MAKE) SPACETIME=schwarzschild ENABLE_HDR=1 backend
|
||||||
OMP_NUM_THREADS=16 $(BUILD_DIR)/schwarzschild_sky --catalog assets/sky_grid_5deg.csv --output $(REFERENCE_TMP_DIR)/schwarzschild_ra1_dec1_fov60_640x360.$(IMAGE_EXT) --hdr-output --width 640 --height 360 --fov-deg 60 --look-ra-deg 1 --look-dec-deg 1 --exposure 0.1 --observer-radius 30 --observer-velocity 0 0 0 --psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5 --max-magnification 1e300 --max-cache-psf-flux 1 --psf-relative-tail 1e-8 --psf-min-y 0 --coarse-cell-pixels 16 --refine-max-level 0 --refine-angle-abs-deg 0.001 --refine-angle-rel 0.1 --refine-jacobian-min 1e-3 --refine-min-edge-pixels 0.5 --refine-min-area-pixels2 0.25 --catalog-load-workers 4
|
OMP_NUM_THREADS=16 $(BUILD_DIR)/schwarzschild_sky --integrator rk4 --catalog assets/sky_grid_5deg.csv --output $(REFERENCE_TMP_DIR)/schwarzschild_ra1_dec1_fov60_640x360.$(IMAGE_EXT) --hdr-output --width 640 --height 360 --fov-deg 60 --look-ra-deg 1 --look-dec-deg 1 --exposure 0.1 --observer-radius 30 --observer-velocity 0 0 0 --psf-fwhm-pixels 2.7 --psf-moffat-beta 4.5 --max-magnification 1e300 --max-cache-psf-flux 1 --psf-relative-tail 1e-8 --psf-min-y 0 --coarse-cell-pixels 16 --refine-max-level 0 --refine-angle-abs-deg 0.001 --refine-angle-rel 0.1 --refine-jacobian-min 1e-3 --refine-min-edge-pixels 0.5 --refine-min-area-pixels2 0.25 --catalog-load-workers 4
|
||||||
python3 $(FLOATDIFF_SCRIPT) $(REFERENCE_DIR)/schwarzschild_ra1_dec1_fov60_640x360_HDR.fits $(REFERENCE_TMP_DIR)/schwarzschild_ra1_dec1_fov60_640x360_HDR.fits
|
python3 $(FLOATDIFF_SCRIPT) $(REFERENCE_DIR)/schwarzschild_ra1_dec1_fov60_640x360_HDR.fits $(REFERENCE_TMP_DIR)/schwarzschild_ra1_dec1_fov60_640x360_HDR.fits
|
||||||
@@ -954,35 +954,34 @@ residual、Chebyshev 表或解析主项;运行期不得建表。
|
|||||||
- 高精度 reference evaluator 在域内不收敛;
|
- 高精度 reference evaluator 在域内不收敛;
|
||||||
- 表在 seam 或 grazing 区域超过误差限。
|
- 表在 seam 或 grazing 区域超过误差限。
|
||||||
|
|
||||||
## 18A.10 当前实现状态
|
## 18A.10 Backend 能力与路由约束
|
||||||
|
|
||||||
- 公共接口(end descriptor、escape worldtube sample、canonical photon state 与
|
- 公共接口以 end descriptor、escape worldtube sample、canonical photon state 与
|
||||||
endpoint `end_id`)已实现;
|
endpoint `end_id` 分离远端声明、几何事件、状态转接与终态来源;
|
||||||
- $M=0$ 固定球与匀速移动球的 camera pre-route、directed inside -> outside
|
- $M=0$ 固定球与匀速移动球的 camera pre-route、directed inside -> outside
|
||||||
crossing、`PENDING_ENTRY` 生命周期已实现,并接入 Minkowski 与 Alcubierre;
|
crossing 与 `PENDING_ENTRY` 生命周期采用同一几何约定,适用于 Minkowski 与
|
||||||
- 单帧与 movie 共用同一 pre-route/生命周期实现;`make test` 全绿;
|
Alcubierre 的平直外区;
|
||||||
|
- 单帧与 movie 必须共用同一 pre-route/生命周期实现;
|
||||||
- $M>0$ 固定同心 Schwarzschild monopole 外区以**解析 Carlson 椭圆积分**实现
|
- $M>0$ 固定同心 Schwarzschild monopole 外区以**解析 Carlson 椭圆积分**实现
|
||||||
(见 18A.11),接入解析 Kerr–Schild backend;相机位于 escape 球外的
|
(见 18A.11),接入解析 Kerr–Schild backend;相机位于 escape 球外的
|
||||||
pre-route、entry 传播、directed crossing 与 infinity endpoint 均可用;
|
pre-route、entry 传播、directed crossing 与 infinity endpoint 均可用;
|
||||||
- 任意加速 worldtube 的 bracketed root driver 已实现并由 synthetic accelerated
|
- worldtube 的运动能力必须显式声明。分段匀速、线性半径变化可在各段内求首次
|
||||||
worldtube 测试覆盖(含跨 motion-segment 与 history-exhausted failure
|
crossing,并在段边界重新采样;任意加速运动在没有可信区间界时必须报告
|
||||||
semantics),但尚无生产 backend 使用该路径。该 driver 只检查离散端点的
|
`UNSUPPORTED`,不得把离散采样没有发现根解释为正常 miss。扩展加速运动能力需要
|
||||||
$F$ 符号,尚不能保证捕获一个步长内的窄进入;任意加速 backend 落地前需加入
|
同时提供可信的段内界或专用首次 crossing 解法。
|
||||||
段内速度/加速度界或自适应子区间搜索。
|
- `end_id` 贯通 endpoint、`LensVertex`、`terminal_mismatch` 与
|
||||||
- 多渐近远端路由尚未实现:`end_id` 已进入 endpoint、`LensVertex`、
|
`discrete_jacobian`,避免跨 end 插值;lens-map 保存
|
||||||
`terminal_mismatch` 与 `discrete_jacobian`,避免跨 end 插值;但
|
`end_id`。不同物理 region 的 reachable-end 路由及 catalog 绑定仍需独立定义,
|
||||||
`asymptotic_route_camera` 目前对多个 end 只处理第一个,lens-map 文件格式也
|
不能把能够保存 end 标识解释为已支持完整解析延拓。
|
||||||
未序列化 `end_id`。虫洞/最大延拓接入前需要补这些。
|
|
||||||
- 生命周期为三态:`NO_ENDS`(才允许 legacy)、`DIRECTED_READY`、
|
- 生命周期为三态:`NO_ENDS`(才允许 legacy)、`DIRECTED_READY`、
|
||||||
`PROTOCOL_ERROR`(descriptor 读取失败或不支持的 exterior,显式
|
`PROTOCOL_ERROR`(descriptor 读取失败或不支持的 exterior,显式
|
||||||
`INVALID/UNSUPPORTED`,绝不退回 legacy)。pre-route 也先校验所有 descriptor
|
`INVALID/UNSUPPORTED`,绝不退回 legacy)。pre-route 也先校验所有 descriptor
|
||||||
与 exterior kind,再判定 worldtube 内外,因此“声明了不受支持 exterior 而相机
|
与 exterior kind,再判定 worldtube 内外,因此“声明了不受支持 exterior 而相机
|
||||||
恰在球内”不会被静默接受。
|
恰在球内”不会被静默接受。
|
||||||
- 内区积分时若 worldtube sample 变为 `valid == 0`(历史耗尽),作为一等
|
- 内区积分时若 worldtube sample 变为 `valid == 0`(历史耗尽),作为一等
|
||||||
terminal reason 返回 `RAY_ENDPOINT_TIME_RANGE_EXHAUSTED`、保留 `end_id`,并由
|
terminal reason 返回 `INCOMPLETE/TIME_RANGE_EXHAUSTED`、保留 `end_id`,并由
|
||||||
`RayPool` 记为 `RAY_POOL_TERMINATED`,与 pre-route 的耗尽语义一致。generic
|
`RayPool` 记为 `RAY_POOL_TERMINATED`,与 pre-route 的耗尽语义一致。内区 crossing
|
||||||
accelerated driver 与内区 crossing localizer 的二分过程中任何 sample 失败都
|
localizer 定位过程中任何 sample 失败都直接传播具体状态,不返回一个正常 entry。
|
||||||
直接传播该具体状态,不返回一个正常 entry 或普通 integration failure。
|
|
||||||
- Minkowski entry quadratic 用稳定根公式($q=-\tfrac12(b+\mathrm{copysign}
|
- Minkowski entry quadratic 用稳定根公式($q=-\tfrac12(b+\mathrm{copysign}
|
||||||
(\sqrt\Delta,b))$,取最小正根);$c=0$(相机在边界)时按 $b=\mathrm dF/
|
(\sqrt\Delta,b))$,取最小正根);$c=0$(相机在边界)时按 $b=\mathrm dF/
|
||||||
\mathrm ds$ 分类。worldtube sample 必须有限且 $R>0$,否则 `INVALID`。
|
\mathrm ds$ 分类。worldtube sample 必须有限且 $R>0$,否则 `INVALID`。
|
||||||
@@ -1076,6 +1075,104 @@ residual、Chebyshev 表或解析主项;运行期不得建表。
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
# 18B. 自适应测地线积分
|
||||||
|
|
||||||
|
积分器负责轨迹误差控制、拒步与数值失败诊断,不承担物理终态分类。步长、计算配额与
|
||||||
|
回溯时间是独立配置;改变步长或容差不得隐式改变可追踪的时间范围。
|
||||||
|
|
||||||
|
- 生产默认采用 DP54;固定 RK4 保留为显式数值对照。CLI 默认相对容差与 `Pi/L`
|
||||||
|
绝对容差为 `1e-9`,位置绝对容差为 `1e-9` 倍 backend 长度单位(解析
|
||||||
|
Schwarzschild 为 `M`,Alcubierre 为 bubble 半径,Minkowski 为坐标单位长度)。
|
||||||
|
初始步长、最大步长及时间配额按 backend 的长度/时间单位配置,所有参数均可显式
|
||||||
|
覆盖并写入 provenance。容差控制的是局部 ODE 误差,不承诺临界光线最终方向的
|
||||||
|
全局误差界;生产精度应以独立容差与几何尺度收敛确定。
|
||||||
|
- CLI 步长下限为 `max(1e-12,16*DBL_EPSILON)` 倍 backend 长度单位(`c=1`),
|
||||||
|
是不绑定正常轨迹的数值保护,不是已测得的物理最小时间尺度。上限在解析
|
||||||
|
Schwarzschild 为 `8M`,Minkowski 为 `16` 个坐标时间单位,Alcubierre 为
|
||||||
|
初始默认步长的八倍。上限用于限制 trial 区间,不替代误差与首次事件控制;
|
||||||
|
near-critical 光线应独立收紧容差,不能只靠减小上限保证分类与方向收敛。
|
||||||
|
参数扫描与复现输入见 `benchmarks/adaptive_step_bounds_2026-10-05/`;解析 backend
|
||||||
|
的测量不外推为 NR/DG 数据的默认步长标定。
|
||||||
|
- `GeodesicTraceConfig.stepper` 区分固定 RK4 与 Dormand–Prince 5(4)。DP54 的
|
||||||
|
`atol_x/atol_Pi/atol_L/rtol`、`min_step/max_step`、
|
||||||
|
`consecutive_rejection_limit`、`max_lookback_time` 全部显式;缺省、非正、非有限或
|
||||||
|
`min_step > max_step` 直接返回 protocol error,不偷偷填默认值。初始 trial step
|
||||||
|
复用 `coordinate_time_step`。
|
||||||
|
- DP54 采用标准 Dormand–Prince 5(4)7M tableau,接受 5 阶解,误差用
|
||||||
|
`h*sum((B5-B4)*k)` 直接计算;位置误差尺度
|
||||||
|
`atol_x + rtol*max(|dx|,|h*k1.x|)`,`Pi` 用 `atol_Pi + rtol*max(|Pi_before|,|Pi_candidate|)`,
|
||||||
|
`L` 用 `atol_L + rtol*max(1,|dL|)`;控制器 safety `0.9`、factor clamp `[0.2,5]`、
|
||||||
|
exponent `1/5`,无 FSAL(每次 trial 7 次 RHS),拒步不提交状态。
|
||||||
|
- 自适应控制状态属于各条 ray:保存 `integration_start_time`(activation/entry 时间,
|
||||||
|
非相机能量参考 `L0`)、`next_step`、累计 rejected/RHS 计数与 `previous_rejected`;
|
||||||
|
`steps` 表示 accepted 步数。状态须跨 slab 与预算重试保留;endpoint 保存最后可信
|
||||||
|
轨迹及控制/成本状态,使续追无需从相机重放,也不重置 `L0`。
|
||||||
|
- 控制/成本状态在 scheduler 各层按值传递:batch 路径的 `RayPool` SoA 保存同一组
|
||||||
|
per-ray 字段,slab activation 只重置新 ray 的 accepted 步数,绝不重置 adaptive
|
||||||
|
control state;frame/movie 的续追请求以完整 resume state 重建(frame 与 movie
|
||||||
|
共用同一 helper,禁止逐字段手抄或漏字段)。endpoint 记录本次实际授予的 time
|
||||||
|
budget,供 retry 层独立累计。off-mesh witness 原地提升必须整体复制该状态,
|
||||||
|
重试回填保留连续状态与成本计数。
|
||||||
|
- 计算配额与回溯时间是两条独立、各自饱和的 retry 预算:step 增量与 time 增量互不
|
||||||
|
替代,只有"实际耗尽且仍可增长"的 quota 才允许发起 retry;任一 blocking quota 已
|
||||||
|
达硬上限时不得仅凭另一 quota 产生无效重试,直接按 budget-incomplete 处理。两个
|
||||||
|
quota 的实际配置总 grant 必须与已 spent 数量分开记录,retry 采样取实际 grant,
|
||||||
|
不得由已花费步数反推授权。"可增长"指新 quota 必须打开严格更大的可表示区间:整数
|
||||||
|
步长严格增加,time 左边界 `start - quota` 严格前移;因大 time origin 或增量过小
|
||||||
|
而 round 到同一区间的增量不算有效增长,不得发起永远无法推进的 retry。两者都到上限
|
||||||
|
后 UUU 仍为 budget-incomplete,UUD/UDD 在几何停止尺度可按 finite-resolution 近似
|
||||||
|
标黑。自动补齐的 time 重试增量由 `max_lookback_time` 指定,总上限为其四倍
|
||||||
|
(对有限数值范围饱和);这是可覆盖的 resource quota policy,不是物理终态条件。
|
||||||
|
- 每步对 slab 左边界与显式回溯预算左边界截断;DP54 不以
|
||||||
|
`coordinate_time_step * max_steps` 定义时间范围。回溯预算耗尽而轨迹仍可信
|
||||||
|
返回 `UNRESOLVED/BUDGET_EXHAUSTED`;真实的 slab data time failure 仍是
|
||||||
|
`INCOMPLETE/TIME_RANGE_EXHAUSTED`。`max_steps` 仍作为 accepted 步数额度。
|
||||||
|
各 trial 先确定可表示的目标时间,再用实际 `target-before.t` 推进状态、构造
|
||||||
|
dense interpolant 与提交时间;不得以舍入前的步长推进空间、舍入后的步长记时间。
|
||||||
|
worldtube 采样的坐标时间同样使用实际差值回推运动,不假设半步总是可表示。
|
||||||
|
Alcubierre 的默认时间范围由 `1.25*4*R_escape/(1-|v_s|)` 给出;固定步的步数
|
||||||
|
估算不能截短自适应路径的历史,也不能替代其独立资源上限。
|
||||||
|
- 初始 accepted 状态的 RHS/metric 失败直接报告具体 point reason,不缩步;后续 stage
|
||||||
|
的 `OUT_OF_DOMAIN/INVALID_METRIC` 可有界缩步重试;`TIME_UNAVAILABLE/INTERNAL_ERROR`
|
||||||
|
不靠无限缩步;最小步长或时间不可进导致失败时报告 `INCOMPLETE/INTEGRATION_ERROR`。
|
||||||
|
拒步上限耗尽时保留具体 stage 原因,或报告积分误差不可控。失败路径保证调用者
|
||||||
|
state 与 endpoint 的最后可信状态一致。
|
||||||
|
- directed inside→outside 事件的 DP 子积分定位使用同一 DP 误差控制(不混用 RK4),
|
||||||
|
成本计入 endpoint 但不伪造 accepted 主步。定位的 time bracket
|
||||||
|
停止容差取局部步长量级与真实 `nextafter` ULP 的组合(不随远端 `|t|` 放大),任何
|
||||||
|
可表示的非零 target−before 区间都实际积分,只有 target==before 才允许直接取状态;
|
||||||
|
`t+h==t` 明确失败或返回已接受可信状态,不伪造轨迹。子积分失败经独立 RayReason 透传
|
||||||
|
(`TIME_UNAVAILABLE→TIME_RANGE_EXHAUSTED`、`INVALID_METRIC`、`OUT_OF_DOMAIN`、
|
||||||
|
`INTEGRATION_ERROR`),与 worldtube descriptor 自身的 protocol/history 失败区分。
|
||||||
|
- 嵌入误差估计不保证找到全部几何事件;窄进出、first-crossing 与同一步内多个事件的
|
||||||
|
顺序必须独立验证,不能只凭步端点符号或误差通过认定事件完整。积分精度还须通过
|
||||||
|
逃逸方向、频移、null 残差及适用 backend 的独立守恒量验证;不靠反复归一化掩盖误差。
|
||||||
|
- DP54 accepted 区间的四次 dense interpolant 用于枚举事件候选。对分段匀速球形
|
||||||
|
worldtube,代入 `F=|x-center|²-radius²` 得到至多八次多项式;通过导数根划分
|
||||||
|
单调区间并隔离根,不能仅查看主步两端符号。根按过去传播方向排序,区分真正的
|
||||||
|
inside→outside crossing 与切触;motion 段边界截断主步并重新建立候选。
|
||||||
|
相机相对能量阈值的候选从同一 accepted 区间的 `L-L0` 获得。候选必须经误差受控
|
||||||
|
子积分验证,escape 与暗阈值按可信轨迹顺序处理;数值不可分辨的同时事件采用明确、
|
||||||
|
一致的优先规则,不能由 end descriptor 的排列决定终态。
|
||||||
|
`L-L0` 在动态时空中不假定单调:即使主步两端均低于阈值,也要处理步内的首次
|
||||||
|
upcrossing。阈值根按导数根分段,在局部 bracket 内确认并定位;不能用整个区间的
|
||||||
|
二分取代首次 crossing。所有候选的可信时间须在子积分后重新比较;当前不可分辨的
|
||||||
|
同时事件取 escape 优先。阈值是 `>=` 的闭事件,真正的步末 crossing 不能因根
|
||||||
|
合并到端点而丢失。无法确认事件时有界缩步,耗尽后报告积分失败,不回退为假成功。
|
||||||
|
`LOG_P0` 辅助监测策略保留 accepted-state 检查,不提供这一多项式事件定位能力;
|
||||||
|
生产 CLI 使用相机相对 `L-L0` 策略。
|
||||||
|
- lens-map 的积分 provenance 必须保存稳定的 stepper wire code、分组绝对/相对
|
||||||
|
容差、初始步长及上下限、拒步上限、初始计算/回溯配额与重试政策。render-only
|
||||||
|
replay 消费文件策略,不能由当前 CLI 默认值覆盖历史配置,也不从缺失字段推断
|
||||||
|
自适应积分来源。未知 stepper code 或无效配置须拒绝;只含固定 RK4 来源的旧文件
|
||||||
|
可按明确的固定步语义导入,但不能补成 DP54 结果。
|
||||||
|
- accepted、rejected 与实际 RHS 成本按持久 sample 身份统计;续追保存累计值,回填
|
||||||
|
替换而不是再次累加。off-mesh witness 与原地提升后的顶点是同一样本,不能重复
|
||||||
|
计费;事件子积分和失败 stage 的 RHS 也计入真实成本。渲染地图保存这些诊断值,
|
||||||
|
replay 的来源与成本统计应与原始 trace 一致。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# 19. 恒星 catalog 的内部表示
|
# 19. 恒星 catalog 的内部表示
|
||||||
|
|
||||||
不要预存 RGB。
|
不要预存 RGB。
|
||||||
|
|||||||
+7
-108
@@ -257,106 +257,6 @@ static int solve_entry_quadratic(const double d[3], const double q[3],
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double worldtube_F_frame(const double c_frame[3], double radius,
|
|
||||||
const double x_frame[3]) {
|
|
||||||
const double d[3] = {x_frame[0] - c_frame[0], x_frame[1] - c_frame[1],
|
|
||||||
x_frame[2] - c_frame[2]};
|
|
||||||
return dot3(d, d) - radius * radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Bracketed first-entry search for a worldtube whose motion is not constant.
|
|
||||||
* This is the future interface for accelerated worldtubes; the current
|
|
||||||
* backends always take the closed quadratic path above. */
|
|
||||||
static AsymptoticStatus minkowski_generic_first_entry(
|
|
||||||
const SpacetimeSource *source, const SpacetimeAsymptoticEnd *end,
|
|
||||||
double t0, const double x_frame[3], const double w_frame[3],
|
|
||||||
double *s_out) {
|
|
||||||
double s = 0.0;
|
|
||||||
SpacetimeEscapeWorldtubeSample sample;
|
|
||||||
AsymptoticStatus status = worldtube_sample(source, end, t0, &sample);
|
|
||||||
if (status != ASYMPTOTIC_OK)
|
|
||||||
return status;
|
|
||||||
double c_frame[3];
|
|
||||||
backend_position_to_frame(end, sample.center, c_frame);
|
|
||||||
const double f_start = worldtube_F_frame(c_frame, sample.radius, x_frame);
|
|
||||||
if (f_start < 0.0) {
|
|
||||||
*s_out = 0.0;
|
|
||||||
return ASYMPTOTIC_OK;
|
|
||||||
}
|
|
||||||
if (f_start == 0.0) {
|
|
||||||
/* On the boundary only an inward slope is an entry; outward and tangent
|
|
||||||
* rays keep searching. */
|
|
||||||
double v_frame[3], d0[3], q0[3];
|
|
||||||
backend_vector_to_frame(end, sample.velocity, v_frame);
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
|
||||||
d0[i] = x_frame[i] - c_frame[i];
|
|
||||||
q0[i] = w_frame[i] + v_frame[i];
|
|
||||||
}
|
|
||||||
const double slope0 =
|
|
||||||
2.0 * dot3(d0, q0) + 2.0 * sample.radius * sample.radius_rate;
|
|
||||||
if (slope0 < 0.0) {
|
|
||||||
*s_out = 0.0;
|
|
||||||
return ASYMPTOTIC_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const double speed = fabs(sample.velocity[0]) + fabs(sample.velocity[1]) +
|
|
||||||
fabs(sample.velocity[2]) + fabs(sample.radius_rate) + 1.0;
|
|
||||||
const double base_step = 0.5 * fmax(sample.radius, 1.0) / speed;
|
|
||||||
for (int iteration = 0; iteration < 1000000; ++iteration) {
|
|
||||||
double step = base_step;
|
|
||||||
const double boundary = spacetime_escape_worldtube_next_segment(
|
|
||||||
source, end->end_id, t0 - s);
|
|
||||||
if (isfinite(boundary)) {
|
|
||||||
/* The backward-integration distance to a past segment boundary. */
|
|
||||||
const double to_boundary = (t0 - boundary) - s;
|
|
||||||
if (to_boundary > 0.0)
|
|
||||||
step = fmin(step, to_boundary);
|
|
||||||
}
|
|
||||||
const double s_next = s + step;
|
|
||||||
const double t_next = t0 - s_next;
|
|
||||||
SpacetimeEscapeWorldtubeSample next;
|
|
||||||
status = worldtube_sample(source, end, t_next, &next);
|
|
||||||
if (status != ASYMPTOTIC_OK)
|
|
||||||
return status;
|
|
||||||
double c_next[3], ray_next[3];
|
|
||||||
backend_position_to_frame(end, next.center, c_next);
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
ray_next[i] = x_frame[i] + w_frame[i] * s_next;
|
|
||||||
const double f_next = worldtube_F_frame(c_next, next.radius, ray_next);
|
|
||||||
/* Only a strictly negative sample is an entry; a single touch at F == 0
|
|
||||||
* (tangent) is not. */
|
|
||||||
if (f_next < 0.0) {
|
|
||||||
double lo = s, hi = s_next;
|
|
||||||
AsymptoticStatus bisect_status = ASYMPTOTIC_OK;
|
|
||||||
for (int bisect = 0; bisect < 80; ++bisect) {
|
|
||||||
const double mid = 0.5 * (lo + hi);
|
|
||||||
SpacetimeEscapeWorldtubeSample mid_sample;
|
|
||||||
bisect_status = worldtube_sample(source, end, t0 - mid, &mid_sample);
|
|
||||||
if (bisect_status != ASYMPTOTIC_OK)
|
|
||||||
break;
|
|
||||||
double c_mid[3], ray_mid[3];
|
|
||||||
backend_position_to_frame(end, mid_sample.center, c_mid);
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
ray_mid[i] = x_frame[i] + w_frame[i] * mid;
|
|
||||||
const double f_mid =
|
|
||||||
worldtube_F_frame(c_mid, mid_sample.radius, ray_mid);
|
|
||||||
if (f_mid <= 0.0)
|
|
||||||
hi = mid;
|
|
||||||
else
|
|
||||||
lo = mid;
|
|
||||||
}
|
|
||||||
/* A sample failure inside the bracket must not be disguised as a
|
|
||||||
* normal entry. */
|
|
||||||
if (bisect_status != ASYMPTOTIC_OK)
|
|
||||||
return bisect_status;
|
|
||||||
*s_out = hi;
|
|
||||||
return ASYMPTOTIC_OK;
|
|
||||||
}
|
|
||||||
s = s_next;
|
|
||||||
}
|
|
||||||
return ASYMPTOTIC_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void minkowski_route_escaped(const SpacetimeAsymptoticEnd *end,
|
static void minkowski_route_escaped(const SpacetimeAsymptoticEnd *end,
|
||||||
const double w_frame[3],
|
const double w_frame[3],
|
||||||
SpacetimeEndId end_id,
|
SpacetimeEndId end_id,
|
||||||
@@ -405,14 +305,13 @@ static AsymptoticStatus minkowski_preroute(
|
|||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
x_cur[i] = x_frame[i] + w_frame[i] * s;
|
x_cur[i] = x_frame[i] + w_frame[i] * s;
|
||||||
if (!sample.velocity_constant) {
|
if (!sample.velocity_constant) {
|
||||||
double s_rel;
|
/* An arbitrary accelerated worldtube has no strict interval bound on
|
||||||
status = minkowski_generic_first_entry(source, end, t, x_cur, w_frame,
|
* its relative motion, so a bracketed sign search can silently miss a
|
||||||
&s_rel);
|
* narrow first entry. Until such bounds exist, report it explicitly
|
||||||
if (status != ASYMPTOTIC_OK)
|
* instead of fabricating a route; piecewise-constant motion (the
|
||||||
return status;
|
* production backends) stays supported through the closed quadratic
|
||||||
minkowski_route_entry(end, t0, x_frame, w_frame, s + s_rel, end_id,
|
* path below. */
|
||||||
route);
|
return ASYMPTOTIC_UNSUPPORTED;
|
||||||
return ASYMPTOTIC_OK;
|
|
||||||
}
|
}
|
||||||
double c_frame[3], v_frame[3], d[3], q[3];
|
double c_frame[3], v_frame[3], d[3], q[3];
|
||||||
backend_position_to_frame(end, sample.center, c_frame);
|
backend_position_to_frame(end, sample.center, c_frame);
|
||||||
|
|||||||
+215
-29
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "optics.h"
|
#include "optics.h"
|
||||||
|
|
||||||
|
#include <float.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
@@ -102,6 +103,17 @@ int frame_lens_mesh_build_coarse(FrameLensMesh *mesh, int width, int height,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clamp an `unsigned long` cost counter into the persistent uint64_t field.
|
||||||
|
* On every platform this project builds for the two widths are equal, so the
|
||||||
|
* branch compiles away; it keeps a wider `unsigned long` from silently wrapping. */
|
||||||
|
static uint64_t cost_counter_u64(unsigned long value) {
|
||||||
|
#if ULONG_MAX > UINT64_MAX
|
||||||
|
return value > (unsigned long)UINT64_MAX ? UINT64_MAX : (uint64_t)value;
|
||||||
|
#else
|
||||||
|
return (uint64_t)value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Store an endpoint into a lens vertex. For an UNRESOLVED result the last
|
/* Store an endpoint into a lens vertex. For an UNRESOLVED result the last
|
||||||
* accepted continuous state is kept so the ray can be resumed; `granted_limit`
|
* accepted continuous state is kept so the ray can be resumed; `granted_limit`
|
||||||
* is the total accepted-step budget that produced this result (0 when it is
|
* is the total accepted-step budget that produced this result (0 when it is
|
||||||
@@ -112,6 +124,14 @@ static void store_endpoint(LensVertex *vertex, const RayEndpoint *endpoint,
|
|||||||
vertex->reason = endpoint->reason;
|
vertex->reason = endpoint->reason;
|
||||||
vertex->end_id = endpoint->end_id;
|
vertex->end_id = endpoint->end_id;
|
||||||
vertex->traced = 1;
|
vertex->traced = 1;
|
||||||
|
/* Real integration cost for every outcome. The endpoint already reports the
|
||||||
|
* cumulative accepted/rejected/RHS totals of a resumed trace, so this is an
|
||||||
|
* overwrite, never an accumulation. A fresh (analytically pre-routed) escape
|
||||||
|
* legitimately reports zero. */
|
||||||
|
vertex->trace_accepted_steps = (uint64_t)endpoint->accepted_steps;
|
||||||
|
vertex->trace_rejected_steps = (uint64_t)endpoint->rejected_steps;
|
||||||
|
vertex->trace_rhs_evaluations = cost_counter_u64(endpoint->rhs_evaluations);
|
||||||
|
vertex->trace_cost_saturated = 0;
|
||||||
if (endpoint->outcome == RAY_OUTCOME_ESCAPED) {
|
if (endpoint->outcome == RAY_OUTCOME_ESCAPED) {
|
||||||
for (int axis = 0; axis < 3; ++axis)
|
for (int axis = 0; axis < 3; ++axis)
|
||||||
vertex->n_infinity[axis] = endpoint->n_infinity[axis];
|
vertex->n_infinity[axis] = endpoint->n_infinity[axis];
|
||||||
@@ -127,13 +147,60 @@ static void store_endpoint(LensVertex *vertex, const RayEndpoint *endpoint,
|
|||||||
vertex->continuation_log_alpha_p0 = endpoint->final_log_alpha_p0;
|
vertex->continuation_log_alpha_p0 = endpoint->final_log_alpha_p0;
|
||||||
vertex->continuation_log_alpha_p0_0 = endpoint->final_log_alpha_p0_0;
|
vertex->continuation_log_alpha_p0_0 = endpoint->final_log_alpha_p0_0;
|
||||||
vertex->continuation_steps = endpoint->accepted_steps;
|
vertex->continuation_steps = endpoint->accepted_steps;
|
||||||
|
vertex->continuation_integration_start_time =
|
||||||
|
endpoint->integration_start_time;
|
||||||
|
vertex->continuation_next_step = endpoint->next_step;
|
||||||
|
vertex->continuation_rejected_steps = endpoint->rejected_steps;
|
||||||
|
vertex->continuation_rhs_evaluations = endpoint->rhs_evaluations;
|
||||||
|
vertex->continuation_previous_rejected = endpoint->previous_rejected;
|
||||||
|
/* Prefer the explicit grant of this request, then the trace's actual
|
||||||
|
* configured step budget. Only legacy/synthetic endpoints whose
|
||||||
|
* accepted_step_limit is zero fall back to the spent accepted count; real
|
||||||
|
* production must never infer a grant from steps already spent. */
|
||||||
const unsigned int used =
|
const unsigned int used =
|
||||||
granted_limit != 0 ? granted_limit : endpoint->accepted_steps;
|
granted_limit != 0 ? granted_limit
|
||||||
|
: endpoint->accepted_step_limit != 0 ? endpoint->accepted_step_limit
|
||||||
|
: endpoint->accepted_steps;
|
||||||
if (used > vertex->continuation_limit)
|
if (used > vertex->continuation_limit)
|
||||||
vertex->continuation_limit = used;
|
vertex->continuation_limit = used;
|
||||||
|
/* The granted time quota is monotonic like the step quota: a resume must
|
||||||
|
* never silently shrink a budget that a previous generation granted. */
|
||||||
|
if (endpoint->lookback_limit > vertex->continuation_lookback_limit)
|
||||||
|
vertex->continuation_lookback_limit = endpoint->lookback_limit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int frame_vertex_continuation_state(const LensVertex *vertex,
|
||||||
|
GeodesicRayState *state) {
|
||||||
|
if (vertex == NULL || state == NULL ||
|
||||||
|
vertex->outcome != RAY_OUTCOME_UNRESOLVED ||
|
||||||
|
!isfinite(vertex->continuation_t) ||
|
||||||
|
!isfinite(vertex->continuation_log_alpha_p0) ||
|
||||||
|
!isfinite(vertex->continuation_log_alpha_p0_0) ||
|
||||||
|
!isfinite(vertex->continuation_integration_start_time) ||
|
||||||
|
!isfinite(vertex->continuation_next_step))
|
||||||
|
return -1;
|
||||||
|
for (int axis = 0; axis < 3; ++axis)
|
||||||
|
if (!isfinite(vertex->continuation_x[axis]) ||
|
||||||
|
!isfinite(vertex->continuation_Pi[axis]))
|
||||||
|
return -1;
|
||||||
|
*state = (GeodesicRayState){
|
||||||
|
.coordinate_time = vertex->continuation_t,
|
||||||
|
.x = {vertex->continuation_x[0], vertex->continuation_x[1],
|
||||||
|
vertex->continuation_x[2]},
|
||||||
|
.Pi = {vertex->continuation_Pi[0], vertex->continuation_Pi[1],
|
||||||
|
vertex->continuation_Pi[2]},
|
||||||
|
.log_alpha_p0 = vertex->continuation_log_alpha_p0,
|
||||||
|
.log_alpha_p0_0 = vertex->continuation_log_alpha_p0_0,
|
||||||
|
.steps = vertex->continuation_steps,
|
||||||
|
.integration_start_time = vertex->continuation_integration_start_time,
|
||||||
|
.next_step = vertex->continuation_next_step,
|
||||||
|
.rejected_steps = vertex->continuation_rejected_steps,
|
||||||
|
.rhs_evaluations = vertex->continuation_rhs_evaluations,
|
||||||
|
.previous_rejected = vertex->continuation_previous_rejected};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int frame_lens_mesh_trace(FrameLensMesh *mesh, const SpacetimeSource *spacetime,
|
int frame_lens_mesh_trace(FrameLensMesh *mesh, const SpacetimeSource *spacetime,
|
||||||
const ObserverState *observer,
|
const ObserverState *observer,
|
||||||
const GeodesicTraceConfig *trace) {
|
const GeodesicTraceConfig *trace) {
|
||||||
@@ -643,14 +710,77 @@ static size_t witness_find(const FrameLensMesh *mesh, size_t a, size_t b) {
|
|||||||
return SIZE_MAX;
|
return SIZE_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int retry_limit(unsigned int current,
|
static unsigned int retry_step_limit(unsigned int current,
|
||||||
const RefinementConfig *config) {
|
const RefinementConfig *config) {
|
||||||
const unsigned int remaining = config->max_total_steps - current;
|
const unsigned int remaining = config->max_total_steps - current;
|
||||||
return current + (config->retry_step_increment < remaining
|
return current + (config->retry_step_increment < remaining
|
||||||
? config->retry_step_increment
|
? config->retry_step_increment
|
||||||
: remaining);
|
: remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double retry_time_limit(double current,
|
||||||
|
const RefinementConfig *config) {
|
||||||
|
const double remaining = config->max_total_lookback_time - current;
|
||||||
|
return current + (config->retry_lookback_increment < remaining
|
||||||
|
? config->retry_lookback_increment
|
||||||
|
: remaining);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* One local coordinate-time ULP measured with nextafter. It bounds the
|
||||||
|
* rounding of the boundary-limited final step that produced a lookback stop. */
|
||||||
|
static double retry_time_ulp(double t) {
|
||||||
|
const double up = nextafter(t, INFINITY);
|
||||||
|
const double down = nextafter(t, -INFINITY);
|
||||||
|
return fmax(fabs(up - t), fabs(t - down));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decide whether an UNRESOLVED vertex should be retried and, if so, fill the
|
||||||
|
* independently saturated step/time budgets. A quota counts as blocking only
|
||||||
|
* when the ray actually reached it; a retry is refused when any blocking quota
|
||||||
|
* cannot open a strictly larger representable region, because growing a
|
||||||
|
* different quota cannot make progress. Returns nonzero when a retry request
|
||||||
|
* should be emitted. */
|
||||||
|
static int retry_budgets(const LensVertex *vertex,
|
||||||
|
const RefinementConfig *config,
|
||||||
|
unsigned int *step_limit, double *lookback_limit) {
|
||||||
|
const unsigned int step_current = vertex->continuation_limit;
|
||||||
|
const double time_current = vertex->continuation_lookback_limit;
|
||||||
|
const double start = vertex->continuation_integration_start_time;
|
||||||
|
/* Use the same quantity and direction as the integrator's stop test: the
|
||||||
|
* ray is time-blocked when its stop time reached the lookback left boundary
|
||||||
|
* t <= start - quota. The DP loop exits on exactly that comparison, so a
|
||||||
|
* single time ULP is allowed only for the boundary-limited final step. */
|
||||||
|
const double time_left = start - time_current;
|
||||||
|
const int time_blocked =
|
||||||
|
time_current > 0.0 &&
|
||||||
|
vertex->continuation_t <= time_left + retry_time_ulp(time_left);
|
||||||
|
const int step_blocked = vertex->continuation_steps >= step_current;
|
||||||
|
const int step_can_grow =
|
||||||
|
config->retry_step_increment > 0 && step_current < config->max_total_steps;
|
||||||
|
const int time_can_grow =
|
||||||
|
config->retry_lookback_increment > 0.0 &&
|
||||||
|
time_current < config->max_total_lookback_time;
|
||||||
|
const unsigned int step_candidate =
|
||||||
|
step_can_grow ? retry_step_limit(step_current, config) : step_current;
|
||||||
|
const double time_candidate =
|
||||||
|
time_can_grow ? retry_time_limit(time_current, config) : time_current;
|
||||||
|
/* A candidate only counts when it opens a representable region: integer
|
||||||
|
* steps must strictly increase, and the time left boundary must strictly
|
||||||
|
* move. A larger quota that rounds to the same boundary (or is unchanged at
|
||||||
|
* a large time origin) is not effective growth and must not launch a retry
|
||||||
|
* that can never progress. */
|
||||||
|
const int step_effective = step_candidate > step_current;
|
||||||
|
const int time_effective = time_candidate > time_current &&
|
||||||
|
(start - time_candidate) < (start - time_current);
|
||||||
|
if (!(step_blocked || time_blocked))
|
||||||
|
return 0;
|
||||||
|
if ((step_blocked && !step_effective) || (time_blocked && !time_effective))
|
||||||
|
return 0;
|
||||||
|
*step_limit = step_effective ? step_candidate : step_current;
|
||||||
|
*lookback_limit = time_effective ? time_candidate : time_current;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int triangle_allows_children(const FrameLensMesh *mesh,
|
static int triangle_allows_children(const FrameLensMesh *mesh,
|
||||||
const LensTriangle *triangle,
|
const LensTriangle *triangle,
|
||||||
const RefinementConfig *config);
|
const RefinementConfig *config);
|
||||||
@@ -677,7 +807,9 @@ int frame_lens_mesh_prepare_generation(FrameLensMesh *mesh,
|
|||||||
* as is an off-mesh unresolved witness. A witness retry carries its edge so
|
* as is an off-mesh unresolved witness. A witness retry carries its edge so
|
||||||
* the refinement decision sees the updated state; both passes share
|
* the refinement decision sees the updated state; both passes share
|
||||||
* retry_seen so a promoted witness is never requested twice. */
|
* retry_seen so a promoted witness is never requested twice. */
|
||||||
if (config->retry_step_increment > 0 && mesh->vertex_count > 0) {
|
if ((config->retry_step_increment > 0 ||
|
||||||
|
config->retry_lookback_increment > 0.0) &&
|
||||||
|
mesh->vertex_count > 0) {
|
||||||
unsigned char *retry_seen = calloc(mesh->vertex_count, 1);
|
unsigned char *retry_seen = calloc(mesh->vertex_count, 1);
|
||||||
if (retry_seen == NULL)
|
if (retry_seen == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
@@ -694,14 +826,14 @@ int frame_lens_mesh_prepare_generation(FrameLensMesh *mesh,
|
|||||||
if (vertex->outcome != RAY_OUTCOME_UNRESOLVED || retry_seen[v])
|
if (vertex->outcome != RAY_OUTCOME_UNRESOLVED || retry_seen[v])
|
||||||
continue;
|
continue;
|
||||||
retry_seen[v] = 1;
|
retry_seen[v] = 1;
|
||||||
if (vertex->continuation_limit >= config->max_total_steps)
|
unsigned int step_limit;
|
||||||
continue; /* capped: reported as budget-incomplete, not retried */
|
double time_limit;
|
||||||
const unsigned int limit = retry_limit(vertex->continuation_limit, config);
|
if (!retry_budgets(vertex, config, &step_limit, &time_limit))
|
||||||
if (limit <= vertex->continuation_limit)
|
continue; /* blocked quota at cap: reported as budget-incomplete */
|
||||||
continue;
|
|
||||||
FrameSample retry = {.kind = FRAME_SAMPLE_RETRY,
|
FrameSample retry = {.kind = FRAME_SAMPLE_RETRY,
|
||||||
.vertex_id = v,
|
.vertex_id = v,
|
||||||
.step_limit = limit,
|
.step_limit = step_limit,
|
||||||
|
.lookback_limit = time_limit,
|
||||||
.vertex = *vertex};
|
.vertex = *vertex};
|
||||||
if (add_sample(mesh, &retry)) {
|
if (add_sample(mesh, &retry)) {
|
||||||
free(retry_seen);
|
free(retry_seen);
|
||||||
@@ -716,15 +848,16 @@ int frame_lens_mesh_prepare_generation(FrameLensMesh *mesh,
|
|||||||
if (retry_seen[v] || vertex->outcome != RAY_OUTCOME_UNRESOLVED)
|
if (retry_seen[v] || vertex->outcome != RAY_OUTCOME_UNRESOLVED)
|
||||||
continue;
|
continue;
|
||||||
retry_seen[v] = 1;
|
retry_seen[v] = 1;
|
||||||
if (vertex->continuation_limit >= config->max_total_steps)
|
unsigned int step_limit;
|
||||||
continue;
|
double time_limit;
|
||||||
const unsigned int limit = retry_limit(vertex->continuation_limit, config);
|
if (!retry_budgets(vertex, config, &step_limit, &time_limit))
|
||||||
if (limit <= vertex->continuation_limit)
|
|
||||||
continue;
|
continue;
|
||||||
FrameSample retry = {.kind = FRAME_SAMPLE_RETRY, .vertex_id = v,
|
FrameSample retry = {.kind = FRAME_SAMPLE_RETRY, .vertex_id = v,
|
||||||
.edge_vertex = {vertex->probe_edge[0],
|
.edge_vertex = {vertex->probe_edge[0],
|
||||||
vertex->probe_edge[1]},
|
vertex->probe_edge[1]},
|
||||||
.step_limit = limit, .vertex = *vertex};
|
.step_limit = step_limit,
|
||||||
|
.lookback_limit = time_limit,
|
||||||
|
.vertex = *vertex};
|
||||||
if (add_sample(mesh, &retry)) {
|
if (add_sample(mesh, &retry)) {
|
||||||
free(retry_seen);
|
free(retry_seen);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -994,6 +1127,43 @@ void frame_lens_mesh_boundary_stats(FrameLensMesh *mesh,
|
|||||||
stats->retry_requests = mesh->retry_requests;
|
stats->retry_requests = mesh->retry_requests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t sat_add_u64(uint64_t total, uint64_t value, int *saturated) {
|
||||||
|
if (UINT64_MAX - total < value) {
|
||||||
|
*saturated = 1;
|
||||||
|
return UINT64_MAX;
|
||||||
|
}
|
||||||
|
return total + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void frame_lens_mesh_trace_stats(const FrameLensMesh *mesh,
|
||||||
|
FrameTraceStats *stats) {
|
||||||
|
if (stats == NULL)
|
||||||
|
return;
|
||||||
|
*stats = (FrameTraceStats){0};
|
||||||
|
if (mesh == NULL)
|
||||||
|
return;
|
||||||
|
int saturated = 0;
|
||||||
|
for (size_t i = 0; i < mesh->vertex_count; ++i) {
|
||||||
|
const LensVertex *vertex = &mesh->vertices[i];
|
||||||
|
if (!vertex->traced)
|
||||||
|
continue;
|
||||||
|
stats->accepted_steps =
|
||||||
|
sat_add_u64(stats->accepted_steps, vertex->trace_accepted_steps,
|
||||||
|
&saturated);
|
||||||
|
stats->rejected_steps =
|
||||||
|
sat_add_u64(stats->rejected_steps, vertex->trace_rejected_steps,
|
||||||
|
&saturated);
|
||||||
|
stats->rhs_evaluations =
|
||||||
|
sat_add_u64(stats->rhs_evaluations, vertex->trace_rhs_evaluations,
|
||||||
|
&saturated);
|
||||||
|
++stats->vertices;
|
||||||
|
if (vertex->trace_cost_saturated)
|
||||||
|
++stats->saturated_vertices;
|
||||||
|
}
|
||||||
|
if (saturated && stats->saturated_vertices == 0)
|
||||||
|
stats->saturated_vertices = 1;
|
||||||
|
}
|
||||||
|
|
||||||
static LensVertex midpoint_vertex(const LensVertex *a, const LensVertex *b) {
|
static LensVertex midpoint_vertex(const LensVertex *a, const LensVertex *b) {
|
||||||
LensVertex result = {.image_x = 0.5 * (a->image_x + b->image_x),
|
LensVertex result = {.image_x = 0.5 * (a->image_x + b->image_x),
|
||||||
.image_y = 0.5 * (a->image_y + b->image_y)};
|
.image_y = 0.5 * (a->image_y + b->image_y)};
|
||||||
@@ -1438,6 +1608,18 @@ void frame_retry_config_defaults(RefinementConfig *config,
|
|||||||
trace->max_steps > (UINT_MAX / 4u) ? trace->max_steps
|
trace->max_steps > (UINT_MAX / 4u) ? trace->max_steps
|
||||||
: trace->max_steps * 4u;
|
: trace->max_steps * 4u;
|
||||||
}
|
}
|
||||||
|
/* The coordinate-time retry budget is a resource quota owned by the
|
||||||
|
* adaptive stepper; it has no meaning for the fixed-step RK4 path, so an
|
||||||
|
* RK4 config keeps its zero time fields. */
|
||||||
|
if (trace->stepper == GEODESIC_STEPPER_DP54 &&
|
||||||
|
config->retry_lookback_increment == 0.0 &&
|
||||||
|
config->max_total_lookback_time == 0.0) {
|
||||||
|
config->retry_lookback_increment = trace->max_lookback_time;
|
||||||
|
config->max_total_lookback_time =
|
||||||
|
trace->max_lookback_time > DBL_MAX / 4.0
|
||||||
|
? DBL_MAX
|
||||||
|
: trace->max_lookback_time * 4.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int frame_lens_mesh_refine(FrameLensMesh *mesh,
|
int frame_lens_mesh_refine(FrameLensMesh *mesh,
|
||||||
@@ -1472,20 +1654,24 @@ int frame_lens_mesh_refine_with_progress(
|
|||||||
if (sample->cached) continue;
|
if (sample->cached) continue;
|
||||||
RayEndpoint endpoint;
|
RayEndpoint endpoint;
|
||||||
if (sample->kind == FRAME_SAMPLE_RETRY) {
|
if (sample->kind == FRAME_SAMPLE_RETRY) {
|
||||||
const LensVertex *v = &sample->vertex;
|
GeodesicRayState state;
|
||||||
GeodesicRayState state = {
|
if (frame_vertex_continuation_state(&sample->vertex, &state)) {
|
||||||
.coordinate_time = v->continuation_t,
|
/* An UNRESOLVED request without a valid resume payload is a
|
||||||
.x = {v->continuation_x[0], v->continuation_x[1],
|
* protocol error, never a silent discard. */
|
||||||
v->continuation_x[2]},
|
endpoint = (RayEndpoint){.magnification = 1.0,
|
||||||
.Pi = {v->continuation_Pi[0], v->continuation_Pi[1],
|
.end_id = SPACETIME_END_NONE,
|
||||||
v->continuation_Pi[2]},
|
.outcome = RAY_OUTCOME_INCOMPLETE,
|
||||||
.log_alpha_p0 = v->continuation_log_alpha_p0,
|
.reason = RAY_REASON_PROTOCOL_ERROR,
|
||||||
.log_alpha_p0_0 = v->continuation_log_alpha_p0_0,
|
.stop_coordinate_time = NAN,
|
||||||
.steps = v->continuation_steps};
|
.threshold_value = NAN};
|
||||||
GeodesicTraceConfig retry_config = *trace;
|
} else {
|
||||||
retry_config.max_steps = sample->step_limit;
|
GeodesicTraceConfig retry_config = *trace;
|
||||||
endpoint = geodesic_trace_past_from_state(spacetime, &state,
|
retry_config.max_steps = sample->step_limit;
|
||||||
&retry_config);
|
if (sample->lookback_limit > 0.0)
|
||||||
|
retry_config.max_lookback_time = sample->lookback_limit;
|
||||||
|
endpoint = geodesic_trace_past_from_state(spacetime, &state,
|
||||||
|
&retry_config);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
endpoint = geodesic_trace_past(spacetime, observer,
|
endpoint = geodesic_trace_past(spacetime, observer,
|
||||||
sample->vertex.camera_direction, trace);
|
sample->vertex.camera_direction, trace);
|
||||||
|
|||||||
+55
@@ -8,6 +8,7 @@
|
|||||||
#include "spacetime.h"
|
#include "spacetime.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double image_x, image_y;
|
double image_x, image_y;
|
||||||
@@ -29,10 +30,31 @@ typedef struct {
|
|||||||
double continuation_log_alpha_p0_0;
|
double continuation_log_alpha_p0_0;
|
||||||
unsigned int continuation_steps;
|
unsigned int continuation_steps;
|
||||||
unsigned int continuation_limit;
|
unsigned int continuation_limit;
|
||||||
|
/* Adaptive (DP54) resume control/cost state, valid with the fields above when
|
||||||
|
* outcome == RAY_OUTCOME_UNRESOLVED. An integration start time of zero is a
|
||||||
|
* legal coordinate time; the legacy RK4 path leaves these zero. */
|
||||||
|
double continuation_integration_start_time;
|
||||||
|
double continuation_next_step;
|
||||||
|
unsigned int continuation_rejected_steps;
|
||||||
|
unsigned long continuation_rhs_evaluations;
|
||||||
|
unsigned int continuation_previous_rejected;
|
||||||
|
/* Granted total coordinate-time lookback budget accumulated for this
|
||||||
|
* continuation. Zero when the legacy RK4 path supplies no time quota. */
|
||||||
|
double continuation_lookback_limit;
|
||||||
/* Persistent off-mesh probe witness; also participates in completion checks.
|
/* Persistent off-mesh probe witness; also participates in completion checks.
|
||||||
* When set, probe_edge holds the sorted edge (a,b) this witness samples. */
|
* When set, probe_edge holds the sorted edge (a,b) this witness samples. */
|
||||||
int diagnostic_probe;
|
int diagnostic_probe;
|
||||||
size_t probe_edge[2];
|
size_t probe_edge[2];
|
||||||
|
/* Actual integration cost for this persistent vertex, copied from the
|
||||||
|
* endpoint for every outcome (not only UNRESOLVED). The endpoint already
|
||||||
|
* carries cumulative accepted/rejected/RHS counts for a resumed trace, so
|
||||||
|
* each install overwrites rather than accumulates and a witness promoted in
|
||||||
|
* place keeps one physical sample counted exactly once. `uint64_t` with the
|
||||||
|
* saturated flag records a counter that had to be capped instead of wrapping. */
|
||||||
|
uint64_t trace_accepted_steps;
|
||||||
|
uint64_t trace_rejected_steps;
|
||||||
|
uint64_t trace_rhs_evaluations;
|
||||||
|
int trace_cost_saturated;
|
||||||
} LensVertex;
|
} LensVertex;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -77,6 +99,13 @@ typedef struct {
|
|||||||
* budget-incomplete instead of silently blackened. */
|
* budget-incomplete instead of silently blackened. */
|
||||||
unsigned int retry_step_increment;
|
unsigned int retry_step_increment;
|
||||||
unsigned int max_total_steps;
|
unsigned int max_total_steps;
|
||||||
|
/* Independent coordinate-time retry budget. The step and time quotas are
|
||||||
|
* saturated separately and a retry is requested only while a quota that
|
||||||
|
* actually blocked the ray can still grow. Both zero on a DP trace derive
|
||||||
|
* from trace->max_lookback_time; a zero increment with a positive cap keeps
|
||||||
|
* the time budget fixed. Ignored by the legacy RK4 path. */
|
||||||
|
double retry_lookback_increment;
|
||||||
|
double max_total_lookback_time;
|
||||||
} RefinementConfig;
|
} RefinementConfig;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -91,6 +120,9 @@ typedef struct {
|
|||||||
size_t edge_vertex[2];
|
size_t edge_vertex[2];
|
||||||
/* For FRAME_SAMPLE_RETRY: the new total accepted-step budget. */
|
/* For FRAME_SAMPLE_RETRY: the new total accepted-step budget. */
|
||||||
unsigned int step_limit;
|
unsigned int step_limit;
|
||||||
|
/* For FRAME_SAMPLE_RETRY: the new total coordinate-time lookback budget;
|
||||||
|
* zero keeps the trace config budget. */
|
||||||
|
double lookback_limit;
|
||||||
int cached;
|
int cached;
|
||||||
LensVertex vertex;
|
LensVertex vertex;
|
||||||
} FrameSample;
|
} FrameSample;
|
||||||
@@ -116,6 +148,19 @@ typedef struct {
|
|||||||
size_t budget_incomplete_triangles;
|
size_t budget_incomplete_triangles;
|
||||||
} FrameBoundaryStats;
|
} FrameBoundaryStats;
|
||||||
|
|
||||||
|
/* Truthful integration cost aggregated over a finalized mesh. Every
|
||||||
|
* persistent vertex (including promoted probe witnesses) is counted exactly
|
||||||
|
* once, so summing after refinement does not double-count retries. Counters
|
||||||
|
* saturate at UINT64_MAX and increment `saturated_vertices` instead of
|
||||||
|
* wrapping. `vertices` is the number of traced vertices the cost covers. */
|
||||||
|
typedef struct {
|
||||||
|
uint64_t accepted_steps;
|
||||||
|
uint64_t rejected_steps;
|
||||||
|
uint64_t rhs_evaluations;
|
||||||
|
size_t vertices;
|
||||||
|
size_t saturated_vertices;
|
||||||
|
} FrameTraceStats;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
LensVertex *vertices;
|
LensVertex *vertices;
|
||||||
LensTriangle *triangles;
|
LensTriangle *triangles;
|
||||||
@@ -188,6 +233,12 @@ const FrameSample *frame_lens_mesh_samples(const FrameLensMesh *mesh,
|
|||||||
size_t *count);
|
size_t *count);
|
||||||
int frame_lens_mesh_install_sample(FrameLensMesh *mesh, size_t sample_id,
|
int frame_lens_mesh_install_sample(FrameLensMesh *mesh, size_t sample_id,
|
||||||
const RayEndpoint *endpoint);
|
const RayEndpoint *endpoint);
|
||||||
|
/* Rebuild the full adaptive resume state recorded in a vertex's continuation
|
||||||
|
* fields into `state`. Returns 0 on success and -1 when the vertex has no
|
||||||
|
* valid resume payload. The frame refinement loop and the movie scheduler
|
||||||
|
* both use this so neither can silently drop a control field. */
|
||||||
|
int frame_vertex_continuation_state(const LensVertex *vertex,
|
||||||
|
GeodesicRayState *state);
|
||||||
/* Applies a nonempty completed generation; callers skip frames for which
|
/* Applies a nonempty completed generation; callers skip frames for which
|
||||||
* prepare_generation returned zero. Returns the number of newly added
|
* prepare_generation returned zero. Returns the number of newly added
|
||||||
* vertices, zero when no topology change was made, or -1 on failure. */
|
* vertices, zero when no topology change was made, or -1 on failure. */
|
||||||
@@ -209,6 +260,10 @@ int frame_lens_mesh_refine_with_progress(
|
|||||||
void frame_lens_mesh_boundary_stats(FrameLensMesh *mesh,
|
void frame_lens_mesh_boundary_stats(FrameLensMesh *mesh,
|
||||||
const RefinementConfig *config,
|
const RefinementConfig *config,
|
||||||
FrameBoundaryStats *stats);
|
FrameBoundaryStats *stats);
|
||||||
|
/* Aggregate the per-vertex integration cost of a finalized mesh. Unlike
|
||||||
|
* boundary_stats this does not modify the mesh and needs no config. */
|
||||||
|
void frame_lens_mesh_trace_stats(const FrameLensMesh *mesh,
|
||||||
|
FrameTraceStats *stats);
|
||||||
/* Fill retry defaults (derived from the trace step budget) when the caller
|
/* Fill retry defaults (derived from the trace step budget) when the caller
|
||||||
* did not configure them explicitly. A zero max_total_steps disables retry
|
* did not configure them explicitly. A zero max_total_steps disables retry
|
||||||
* only if retry_step_increment is also zero. */
|
* only if retry_step_increment is also zero. */
|
||||||
|
|||||||
+1601
-68
File diff suppressed because it is too large.
Load diff
+79
-2
@@ -56,7 +56,13 @@ typedef struct {
|
|||||||
/* Last trusted state at termination. For an ESCAPED endpoint this is the
|
/* Last trusted state at termination. For an ESCAPED endpoint this is the
|
||||||
* (finite) numerical truncation position, not the true parameter end. */
|
* (finite) numerical truncation position, not the true parameter end. */
|
||||||
double stop_coordinate_time;
|
double stop_coordinate_time;
|
||||||
unsigned int accepted_steps;
|
unsigned int accepted_steps; /* accepted (spent) steps */
|
||||||
|
/* Actual total accepted-step budget the trace was configured with, kept
|
||||||
|
* distinct from the spent `accepted_steps`. Production endpoints always
|
||||||
|
* carry it so a retry layer never has to infer a grant from the spent count;
|
||||||
|
* zero only on legacy/synthetic endpoints. For a resumed trace this is the
|
||||||
|
* new total grant, not the additional steps. */
|
||||||
|
unsigned int accepted_step_limit;
|
||||||
/* Last trusted continuous state, used to resume an UNRESOLVED ray from its
|
/* Last trusted continuous state, used to resume an UNRESOLVED ray from its
|
||||||
* last accepted step instead of replaying it from the camera. */
|
* last accepted step instead of replaying it from the camera. */
|
||||||
double final_x[3];
|
double final_x[3];
|
||||||
@@ -65,14 +71,73 @@ typedef struct {
|
|||||||
double final_log_alpha_p0_0; /* original reference L0 for retries */
|
double final_log_alpha_p0_0; /* original reference L0 for retries */
|
||||||
/* Monitored threshold value at termination, NAN when not applicable. */
|
/* Monitored threshold value at termination, NAN when not applicable. */
|
||||||
double threshold_value;
|
double threshold_value;
|
||||||
|
/* Adaptive (DP54) controller state and cumulative cost at termination,
|
||||||
|
* copied from the last trusted ray state so a retry resumes without
|
||||||
|
* replaying. The controller fields below (integration window, suggested
|
||||||
|
* step, previous-rejection flag, rejected-step count) are not applicable to
|
||||||
|
* RK4 and stay zero there. `rhs_evaluations` is different: it is the real
|
||||||
|
* cumulative metric-evaluation cost for every stepper, RK4 included. */
|
||||||
|
double integration_start_time; /* adaptive window start (entry/activation) */
|
||||||
|
double next_step; /* positive trial-step magnitude, 0 if unset */
|
||||||
|
unsigned int rejected_steps; /* cumulative rejected trials (DP54 only) */
|
||||||
|
unsigned long rhs_evaluations; /* cumulative actual RHS evaluations */
|
||||||
|
unsigned int previous_rejected;/* 1 when the last trial was rejected */
|
||||||
|
/* Coordinate-time lookback budget actually granted to this trace, recorded
|
||||||
|
* so the frame/movie retry layer can accumulate the per-sample total
|
||||||
|
* independently of the accepted-step budget. Zero for the legacy RK4 path
|
||||||
|
* and for endpoints that never reached a trusted adaptive state. This is a
|
||||||
|
* resource quota, not part of the continuous resume state. */
|
||||||
|
double lookback_limit;
|
||||||
} RayEndpoint;
|
} RayEndpoint;
|
||||||
|
|
||||||
|
/* ODE stepper selection for the past-directed geodesic integrator. RK4 is
|
||||||
|
* the legacy fixed-step path and is value 0 so that zero-initialized configs
|
||||||
|
* keep their historical behavior. DP54 is the explicit adaptive
|
||||||
|
* Dormand-Prince 5(4) stepper; both paths share the same termination,
|
||||||
|
* lookback-budget and retry-control interfaces. */
|
||||||
|
typedef enum {
|
||||||
|
GEODESIC_STEPPER_RK4 = 0,
|
||||||
|
GEODESIC_STEPPER_DP54 = 1
|
||||||
|
} GeodesicStepper;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
double coordinate_time_step;
|
double coordinate_time_step;
|
||||||
unsigned int max_steps;
|
unsigned int max_steps;
|
||||||
/* Normal dark terminal for every backend. No backend may substitute a
|
/* Normal dark terminal for every backend. No backend may substitute a
|
||||||
* position/horizon cutoff for physical capture. */
|
* position/horizon cutoff for physical capture. */
|
||||||
ThresholdPolicy threshold;
|
ThresholdPolicy threshold;
|
||||||
|
|
||||||
|
/* Stepper selection (see GeodesicStepper). */
|
||||||
|
GeodesicStepper stepper;
|
||||||
|
|
||||||
|
/* DP54 tolerances. When stepper == GEODESIC_STEPPER_DP54 all four must be
|
||||||
|
* finite and strictly positive; they are never silently defaulted. Error
|
||||||
|
* scales: position uses atol_x + rtol*max(|dx|, |h*dxdt|) so a distant
|
||||||
|
* coordinate origin cannot relax the local length scale; Pi uses
|
||||||
|
* atol_Pi + rtol*max(|Pi_before|, |Pi_candidate|); L uses
|
||||||
|
* atol_L + rtol*max(1, |dL|). */
|
||||||
|
double atol_x;
|
||||||
|
double atol_Pi;
|
||||||
|
double atol_L;
|
||||||
|
double rtol;
|
||||||
|
|
||||||
|
/* DP54 trial-step magnitude bounds in coordinate time. Both finite and
|
||||||
|
* 0 < min_step <= max_step. The initial trial step and the driver
|
||||||
|
* suggestion reuse coordinate_time_step. */
|
||||||
|
double min_step;
|
||||||
|
double max_step;
|
||||||
|
|
||||||
|
/* DP54 maximum number of consecutive rejected trials before reporting an
|
||||||
|
* integration error. Must be nonzero. */
|
||||||
|
unsigned int consecutive_rejection_limit;
|
||||||
|
|
||||||
|
/* DP54 explicit coordinate-time lookback budget (length, finite and
|
||||||
|
* strictly positive). DP54 never derives its history from the legacy
|
||||||
|
* coordinate_time_step * max_steps product: reaching
|
||||||
|
* integration_start_time - max_lookback_time while the trajectory is still
|
||||||
|
* trustworthy is UNRESOLVED/BUDGET_EXHAUSTED, distinct from a source slab
|
||||||
|
* data time failure (TIME_RANGE_EXHAUSTED). */
|
||||||
|
double max_lookback_time;
|
||||||
} GeodesicTraceConfig;
|
} GeodesicTraceConfig;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -83,7 +148,19 @@ typedef struct {
|
|||||||
/* Reference L at the start of this ray's integration, carried unchanged
|
/* Reference L at the start of this ray's integration, carried unchanged
|
||||||
* through retries so THRESHOLD_LOG_ENERGY_GROWTH stays camera-relative. */
|
* through retries so THRESHOLD_LOG_ENERGY_GROWTH stays camera-relative. */
|
||||||
double log_alpha_p0_0;
|
double log_alpha_p0_0;
|
||||||
unsigned int steps;
|
unsigned int steps; /* accepted steps (all steppers) */
|
||||||
|
/* Adaptive DP54 controller state; the controller fields default to zero and
|
||||||
|
* are ignored by the RK4 path. `integration_start_time` is the inner
|
||||||
|
* activation/entry time (not the L0 camera energy); `next_step` is a
|
||||||
|
* positive trial-step magnitude and is initialized from
|
||||||
|
* config->coordinate_time_step on the first adaptive advance.
|
||||||
|
* `rhs_evaluations` is the real cumulative RHS cost for every stepper;
|
||||||
|
* `rejected_steps`/`previous_rejected` remain DP54-only. */
|
||||||
|
double integration_start_time;
|
||||||
|
double next_step;
|
||||||
|
unsigned int rejected_steps; /* cumulative rejected trials (DP54 only) */
|
||||||
|
unsigned long rhs_evaluations; /* cumulative actual RHS evaluations */
|
||||||
|
unsigned int previous_rejected;/* 1 when the last trial was rejected */
|
||||||
} GeodesicRayState;
|
} GeodesicRayState;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
+119
-17
@@ -11,9 +11,15 @@
|
|||||||
* because their padding and size_t width are ABI-dependent. */
|
* because their padding and size_t width are ABI-dependent. */
|
||||||
static const unsigned char lens_map_magic[8] = {'G', 'R', 'L', 'E', 'N', 'S', 1, 0};
|
static const unsigned char lens_map_magic[8] = {'G', 'R', 'L', 'E', 'N', 'S', 1, 0};
|
||||||
/* Version 2 stores the two-level RayOutcome instead of the removed
|
/* Version 2 stores the two-level RayOutcome instead of the removed
|
||||||
* RayEndpointStatus. Version 1 files are rejected: their old captured bit
|
* RayEndpointStatus. Version 3 appends the adaptive DP54 policy and the
|
||||||
* cannot be upgraded into the new dark/unresolved/error provenance. */
|
* per-vertex integration cost; it still supports v2 import as a legacy
|
||||||
enum { LENS_MAP_VERSION = 2, LENS_MAP_ENDIAN = 0x01020304u };
|
* fixed-step RK4 map. Version 1 is rejected: its old captured bit cannot be
|
||||||
|
* upgraded into the new dark/unresolved/error provenance. */
|
||||||
|
enum {
|
||||||
|
LENS_MAP_VERSION = 3,
|
||||||
|
LENS_MAP_VERSION_LEGACY = 2,
|
||||||
|
LENS_MAP_ENDIAN = 0x01020304u
|
||||||
|
};
|
||||||
|
|
||||||
static uint32_t crc32_update(uint32_t crc, const void *data, size_t size) {
|
static uint32_t crc32_update(uint32_t crc, const void *data, size_t size) {
|
||||||
const unsigned char *bytes = data;
|
const unsigned char *bytes = data;
|
||||||
@@ -63,6 +69,55 @@ static int unit_vector(const double v[3]) {
|
|||||||
const double n2 = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
const double n2 = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
|
||||||
return isfinite(n2) && fabs(n2 - 1.0) <= 1e-9;
|
return isfinite(n2) && fabs(n2 - 1.0) <= 1e-9;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Explicit switch over the stable wire codes; unknown codes are rejected
|
||||||
|
* instead of being reinterpreted as a C enum value. */
|
||||||
|
static int integrator_code_known(uint32_t code) {
|
||||||
|
switch ((GeodesicStepper)code) {
|
||||||
|
case GEODESIC_STEPPER_RK4:
|
||||||
|
case GEODESIC_STEPPER_DP54:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shared read/write schema. It deliberately does not validate mesh contents
|
||||||
|
* (valid_mesh does that per frame): it only proves the provenance is a
|
||||||
|
* complete, self-consistent policy. RK4 maps must state that no adaptive
|
||||||
|
* configuration applies; DP54 maps must carry it in full. */
|
||||||
|
static int provenance_valid(const LensMapProvenance *p) {
|
||||||
|
if (p == NULL || !isfinite(p->threshold_value) ||
|
||||||
|
p->threshold_kind > THRESHOLD_LOG_ENERGY_GROWTH ||
|
||||||
|
!isfinite(p->min_edge_pixels) || p->min_edge_pixels < 0.0 ||
|
||||||
|
!isfinite(p->min_area_pixels2) || p->min_area_pixels2 < 0.0 ||
|
||||||
|
!isfinite(p->coordinate_time_step) || p->coordinate_time_step <= 0.0 ||
|
||||||
|
!integrator_code_known(p->integrator))
|
||||||
|
return 0;
|
||||||
|
if (p->integrator == (uint32_t)GEODESIC_STEPPER_RK4) {
|
||||||
|
return p->atol_x == 0.0 && p->atol_Pi == 0.0 && p->atol_L == 0.0 &&
|
||||||
|
p->rtol == 0.0 && p->min_step == 0.0 && p->max_step == 0.0 &&
|
||||||
|
p->max_lookback_time == 0.0 && p->retry_lookback_increment == 0.0 &&
|
||||||
|
p->max_total_lookback_time == 0.0 &&
|
||||||
|
p->max_consecutive_rejections == 0;
|
||||||
|
}
|
||||||
|
/* DP54. */
|
||||||
|
return p->initial_max_steps != 0 && isfinite(p->atol_x) && p->atol_x > 0.0 &&
|
||||||
|
isfinite(p->atol_Pi) && p->atol_Pi > 0.0 &&
|
||||||
|
isfinite(p->atol_L) && p->atol_L > 0.0 && isfinite(p->rtol) &&
|
||||||
|
p->rtol > 0.0 && isfinite(p->min_step) && p->min_step > 0.0 &&
|
||||||
|
isfinite(p->max_step) && p->max_step > 0.0 &&
|
||||||
|
p->min_step <= p->max_step &&
|
||||||
|
p->coordinate_time_step >= p->min_step &&
|
||||||
|
p->coordinate_time_step <= p->max_step &&
|
||||||
|
isfinite(p->max_lookback_time) && p->max_lookback_time > 0.0 &&
|
||||||
|
p->max_consecutive_rejections != 0 &&
|
||||||
|
isfinite(p->retry_lookback_increment) &&
|
||||||
|
p->retry_lookback_increment >= 0.0 &&
|
||||||
|
isfinite(p->max_total_lookback_time) &&
|
||||||
|
p->max_total_lookback_time >= p->max_lookback_time;
|
||||||
|
}
|
||||||
|
|
||||||
static int valid_mesh(const FrameLensMesh *m) {
|
static int valid_mesh(const FrameLensMesh *m) {
|
||||||
if (m == NULL || m->vertex_count == 0 || m->triangle_count == 0) return 0;
|
if (m == NULL || m->vertex_count == 0 || m->triangle_count == 0) return 0;
|
||||||
for (size_t i = 0; i < m->vertex_count; ++i) {
|
for (size_t i = 0; i < m->vertex_count; ++i) {
|
||||||
@@ -87,7 +142,8 @@ int lens_map_write(const char *path, int width, int height, double fov,
|
|||||||
const LensMapFrame *frames, size_t frame_count) {
|
const LensMapFrame *frames, size_t frame_count) {
|
||||||
if (path == NULL || provenance == NULL || frames == NULL || width <= 0 ||
|
if (path == NULL || provenance == NULL || frames == NULL || width <= 0 ||
|
||||||
height <= 0 || !isfinite(fov) || fov <= 0.0 || fov >= 179.0 ||
|
height <= 0 || !isfinite(fov) || fov <= 0.0 || fov >= 179.0 ||
|
||||||
frame_count == 0 || frame_count > UINT64_MAX)
|
frame_count == 0 || frame_count > UINT64_MAX ||
|
||||||
|
!provenance_valid(provenance))
|
||||||
return -1;
|
return -1;
|
||||||
for (size_t i = 0; i < frame_count; ++i) if (!valid_mesh(&frames[i].mesh)) return -1;
|
for (size_t i = 0; i < frame_count; ++i) if (!valid_mesh(&frames[i].mesh)) return -1;
|
||||||
FILE *file = fopen(path, "wb"); if (file == NULL) return -1;
|
FILE *file = fopen(path, "wb"); if (file == NULL) return -1;
|
||||||
@@ -105,7 +161,17 @@ int lens_map_write(const char *path, int width, int height, double fov,
|
|||||||
write_double(file, provenance->min_edge_pixels, NULL) ||
|
write_double(file, provenance->min_edge_pixels, NULL) ||
|
||||||
write_double(file, provenance->min_area_pixels2, NULL) ||
|
write_double(file, provenance->min_area_pixels2, NULL) ||
|
||||||
write_double(file, provenance->coordinate_time_step, NULL) ||
|
write_double(file, provenance->coordinate_time_step, NULL) ||
|
||||||
write_u32(file, provenance->initial_max_steps, NULL);
|
write_u32(file, provenance->initial_max_steps, NULL) ||
|
||||||
|
write_double(file, provenance->atol_x, NULL) ||
|
||||||
|
write_double(file, provenance->atol_Pi, NULL) ||
|
||||||
|
write_double(file, provenance->atol_L, NULL) ||
|
||||||
|
write_double(file, provenance->rtol, NULL) ||
|
||||||
|
write_double(file, provenance->min_step, NULL) ||
|
||||||
|
write_double(file, provenance->max_step, NULL) ||
|
||||||
|
write_double(file, provenance->max_lookback_time, NULL) ||
|
||||||
|
write_double(file, provenance->retry_lookback_increment, NULL) ||
|
||||||
|
write_double(file, provenance->max_total_lookback_time, NULL) ||
|
||||||
|
write_u32(file, provenance->max_consecutive_rejections, NULL);
|
||||||
for (size_t f = 0; !failed && f < frame_count; ++f) {
|
for (size_t f = 0; !failed && f < frame_count; ++f) {
|
||||||
const FrameLensMesh *m = &frames[f].mesh; uint32_t crc = UINT32_MAX;
|
const FrameLensMesh *m = &frames[f].mesh; uint32_t crc = UINT32_MAX;
|
||||||
failed = write_u64(file, frames[f].frame_id, NULL) ||
|
failed = write_u64(file, frames[f].frame_id, NULL) ||
|
||||||
@@ -122,7 +188,10 @@ int lens_map_write(const char *path, int width, int height, double fov,
|
|||||||
failed = failed || write_double(file, v->log_frequency_ratio, &crc) ||
|
failed = failed || write_double(file, v->log_frequency_ratio, &crc) ||
|
||||||
write_u32(file, (uint32_t)v->end_id, &crc) ||
|
write_u32(file, (uint32_t)v->end_id, &crc) ||
|
||||||
write_u32(file, (uint32_t)v->outcome, &crc) ||
|
write_u32(file, (uint32_t)v->outcome, &crc) ||
|
||||||
write_u32(file, (uint32_t)v->reason, &crc);
|
write_u32(file, (uint32_t)v->reason, &crc) ||
|
||||||
|
write_u64(file, v->trace_accepted_steps, &crc) ||
|
||||||
|
write_u64(file, v->trace_rejected_steps, &crc) ||
|
||||||
|
write_u64(file, v->trace_rhs_evaluations, &crc);
|
||||||
}
|
}
|
||||||
for (size_t i = 0; !failed && i < m->triangle_count; ++i) {
|
for (size_t i = 0; !failed && i < m->triangle_count; ++i) {
|
||||||
for (int j = 0; j < 3; ++j) failed = failed || write_u64(file, m->triangles[i].vertex[j], &crc);
|
for (int j = 0; j < 3; ++j) failed = failed || write_u64(file, m->triangles[i].vertex[j], &crc);
|
||||||
@@ -147,11 +216,20 @@ int lens_map_read(const char *path, LensMapProvenance *provenance,
|
|||||||
*map = (LensMap){0}; FILE *file = fopen(path, "rb"); if (file == NULL) return -1;
|
*map = (LensMap){0}; FILE *file = fopen(path, "rb"); if (file == NULL) return -1;
|
||||||
unsigned char magic[8]; uint32_t version, endian, width, height; uint64_t count;
|
unsigned char magic[8]; uint32_t version, endian, width, height; uint64_t count;
|
||||||
LensMapProvenance prov = {0};
|
LensMapProvenance prov = {0};
|
||||||
int failed = read_bytes(file, magic, sizeof magic, NULL) || memcmp(magic, lens_map_magic, sizeof magic) ||
|
int failed = read_bytes(file, magic, sizeof magic, NULL) ||
|
||||||
|
memcmp(magic, lens_map_magic, sizeof magic) ||
|
||||||
read_u32(file, &version, NULL) || read_u32(file, &endian, NULL) ||
|
read_u32(file, &version, NULL) || read_u32(file, &endian, NULL) ||
|
||||||
read_u32(file, &width, NULL) || read_u32(file, &height, NULL) ||
|
read_u32(file, &width, NULL) || read_u32(file, &height, NULL) ||
|
||||||
read_double(file, &map->horizontal_fov_deg, NULL) || read_u64(file, &count, NULL) ||
|
read_double(file, &map->horizontal_fov_deg, NULL) || read_u64(file, &count, NULL);
|
||||||
read_u32(file, &prov.threshold_kind, NULL) ||
|
/* Branch on the version before reading any version-specific header field, so
|
||||||
|
* a v2 file is never parsed with the v3 layout. */
|
||||||
|
if (failed)
|
||||||
|
goto done;
|
||||||
|
if (version != LENS_MAP_VERSION && version != LENS_MAP_VERSION_LEGACY) {
|
||||||
|
failed = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
failed = read_u32(file, &prov.threshold_kind, NULL) ||
|
||||||
read_u32(file, &prov.threshold_policy_version, NULL) ||
|
read_u32(file, &prov.threshold_policy_version, NULL) ||
|
||||||
read_double(file, &prov.threshold_value, NULL) ||
|
read_double(file, &prov.threshold_value, NULL) ||
|
||||||
read_u32(file, &prov.retry_step_increment, NULL) ||
|
read_u32(file, &prov.retry_step_increment, NULL) ||
|
||||||
@@ -161,16 +239,35 @@ int lens_map_read(const char *path, LensMapProvenance *provenance,
|
|||||||
read_double(file, &prov.min_edge_pixels, NULL) ||
|
read_double(file, &prov.min_edge_pixels, NULL) ||
|
||||||
read_double(file, &prov.min_area_pixels2, NULL) ||
|
read_double(file, &prov.min_area_pixels2, NULL) ||
|
||||||
read_double(file, &prov.coordinate_time_step, NULL) ||
|
read_double(file, &prov.coordinate_time_step, NULL) ||
|
||||||
read_u32(file, &prov.initial_max_steps, NULL) ||
|
read_u32(file, &prov.initial_max_steps, NULL);
|
||||||
version != LENS_MAP_VERSION || endian != LENS_MAP_ENDIAN || width == 0 || height == 0 ||
|
if (!failed && version == LENS_MAP_VERSION) {
|
||||||
width > INT32_MAX || height > INT32_MAX || !isfinite(map->horizontal_fov_deg) ||
|
failed = read_double(file, &prov.atol_x, NULL) ||
|
||||||
map->horizontal_fov_deg <= 0.0 || map->horizontal_fov_deg >= 179.0 || count == 0 ||
|
read_double(file, &prov.atol_Pi, NULL) ||
|
||||||
prov.threshold_kind > THRESHOLD_LOG_ENERGY_GROWTH ||
|
read_double(file, &prov.atol_L, NULL) ||
|
||||||
!isfinite(prov.threshold_value) ||
|
read_double(file, &prov.rtol, NULL) ||
|
||||||
prov.coordinate_time_step < 0.0 || !isfinite(prov.coordinate_time_step) ||
|
read_double(file, &prov.min_step, NULL) ||
|
||||||
count > SIZE_MAX / sizeof *map->frames;
|
read_double(file, &prov.max_step, NULL) ||
|
||||||
|
read_double(file, &prov.max_lookback_time, NULL) ||
|
||||||
|
read_double(file, &prov.retry_lookback_increment, NULL) ||
|
||||||
|
read_double(file, &prov.max_total_lookback_time, NULL) ||
|
||||||
|
read_u32(file, &prov.max_consecutive_rejections, NULL);
|
||||||
|
}
|
||||||
|
/* Legacy v2 carried no adaptive policy. Its missing fields stay zero, and
|
||||||
|
* its integrator must be RK4: a v2 DP54 claim is impossible and rejected. */
|
||||||
|
if (!failed && version == LENS_MAP_VERSION_LEGACY &&
|
||||||
|
prov.integrator != (uint32_t)GEODESIC_STEPPER_RK4)
|
||||||
|
failed = 1;
|
||||||
|
if (!failed &&
|
||||||
|
(endian != LENS_MAP_ENDIAN || width == 0 || height == 0 ||
|
||||||
|
width > INT32_MAX || height > INT32_MAX ||
|
||||||
|
!isfinite(map->horizontal_fov_deg) ||
|
||||||
|
map->horizontal_fov_deg <= 0.0 || map->horizontal_fov_deg >= 179.0 ||
|
||||||
|
count == 0 || count > SIZE_MAX / sizeof *map->frames ||
|
||||||
|
!provenance_valid(&prov)))
|
||||||
|
failed = 1;
|
||||||
if (failed) goto done;
|
if (failed) goto done;
|
||||||
map->provenance = prov;
|
map->provenance = prov;
|
||||||
|
map->file_version = version;
|
||||||
if (provenance != NULL)
|
if (provenance != NULL)
|
||||||
*provenance = prov;
|
*provenance = prov;
|
||||||
map->width = (int)width; map->height = (int)height; map->frame_count = (size_t)count;
|
map->width = (int)width; map->height = (int)height; map->frame_count = (size_t)count;
|
||||||
@@ -204,6 +301,11 @@ int lens_map_read(const char *path, LensMapProvenance *provenance,
|
|||||||
v->outcome = (RayOutcome)outcome;
|
v->outcome = (RayOutcome)outcome;
|
||||||
v->reason = (RayReason)reason;
|
v->reason = (RayReason)reason;
|
||||||
v->traced = 1;
|
v->traced = 1;
|
||||||
|
if (version == LENS_MAP_VERSION) {
|
||||||
|
failed = failed || read_u64(file, &v->trace_accepted_steps, &crc) ||
|
||||||
|
read_u64(file, &v->trace_rejected_steps, &crc) ||
|
||||||
|
read_u64(file, &v->trace_rhs_evaluations, &crc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; !failed && i < frame->mesh.triangle_count; ++i) {
|
for (size_t i = 0; !failed && i < frame->mesh.triangle_count; ++i) {
|
||||||
for (int j = 0; j < 3; ++j) {
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
|||||||
+28
-1
@@ -25,19 +25,46 @@ typedef struct {
|
|||||||
uint32_t retry_step_increment;
|
uint32_t retry_step_increment;
|
||||||
uint32_t max_total_steps;
|
uint32_t max_total_steps;
|
||||||
uint32_t max_level;
|
uint32_t max_level;
|
||||||
uint32_t integrator; /* 0 = fixed-step RK4 (transitional) */
|
/* Stable wire code: 0 = fixed-step RK4, 1 = adaptive Dormand-Prince 5(4).
|
||||||
|
* Never serialize the C enum directly; unknown codes are rejected. */
|
||||||
|
uint32_t integrator;
|
||||||
double min_edge_pixels;
|
double min_edge_pixels;
|
||||||
double min_area_pixels2;
|
double min_area_pixels2;
|
||||||
/* Integration source: the coordinate-time step and the initial per-ray
|
/* Integration source: the coordinate-time step and the initial per-ray
|
||||||
* accepted-step budget used for the first trace. */
|
* accepted-step budget used for the first trace. */
|
||||||
double coordinate_time_step;
|
double coordinate_time_step;
|
||||||
uint32_t initial_max_steps;
|
uint32_t initial_max_steps;
|
||||||
|
/* Adaptive DP54 configuration. For an RK4 map every field here is exactly
|
||||||
|
* zero, which makes "not applicable" explicit on the wire instead of
|
||||||
|
* implying a silently defaulted stepper. For a DP54 map the tolerances,
|
||||||
|
* step bounds and explicit lookback budget are finite and strictly positive,
|
||||||
|
* min_step <= coordinate_time_step <= max_step, and the consecutive
|
||||||
|
* rejection limit is nonzero. */
|
||||||
|
double atol_x;
|
||||||
|
double atol_Pi;
|
||||||
|
double atol_L;
|
||||||
|
double rtol;
|
||||||
|
double min_step;
|
||||||
|
double max_step;
|
||||||
|
double max_lookback_time;
|
||||||
|
/* Retry resource policy: coordinate-time increment per retry and the total
|
||||||
|
* lookback cap. `retry_lookback_increment` may be zero (fixed time budget);
|
||||||
|
* a production DP54 map requires max_total_lookback_time >=
|
||||||
|
* max_lookback_time (the initial grant). Both zero on an RK4 map. */
|
||||||
|
double retry_lookback_increment;
|
||||||
|
double max_total_lookback_time;
|
||||||
|
uint32_t max_consecutive_rejections;
|
||||||
} LensMapProvenance;
|
} LensMapProvenance;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int width, height;
|
int width, height;
|
||||||
double horizontal_fov_deg;
|
double horizontal_fov_deg;
|
||||||
LensMapProvenance provenance;
|
LensMapProvenance provenance;
|
||||||
|
/* On-disk format version actually read (2 for legacy RK4, 3 for the current
|
||||||
|
* adaptive-aware format). 0 when the struct was not produced by a read.
|
||||||
|
* A v2 map carries no per-vertex integration cost, so those replay as zero;
|
||||||
|
* the unknown cost is explicit through this version rather than implied. */
|
||||||
|
uint32_t file_version;
|
||||||
LensMapFrame *frames;
|
LensMapFrame *frames;
|
||||||
size_t frame_count;
|
size_t frame_count;
|
||||||
} LensMap;
|
} LensMap;
|
||||||
|
|||||||
+478
-63
@@ -10,6 +10,8 @@
|
|||||||
#include "spacetime.h"
|
#include "spacetime.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
@@ -67,6 +69,24 @@ typedef struct {
|
|||||||
const char *fast_fftw_wisdom_path;
|
const char *fast_fftw_wisdom_path;
|
||||||
const char *blackbody_table_path;
|
const char *blackbody_table_path;
|
||||||
RefinementConfig refinement;
|
RefinementConfig refinement;
|
||||||
|
/* Integrator selection and its explicit-override flags. A flag records that
|
||||||
|
* a value was named on the command line so an explicit zero is never confused
|
||||||
|
* with "not specified, use the derived default". */
|
||||||
|
GeodesicStepper stepper;
|
||||||
|
int integrator_specified;
|
||||||
|
double ode_rtol, ode_atol_x, ode_atol_pi, ode_atol_l;
|
||||||
|
double ode_initial_step, ode_min_step, ode_max_step;
|
||||||
|
unsigned int ode_max_rejections;
|
||||||
|
unsigned int trace_max_steps;
|
||||||
|
double trace_lookback_time;
|
||||||
|
double retry_lookback_increment;
|
||||||
|
double max_total_lookback_time;
|
||||||
|
int ode_rtol_specified, ode_atol_x_specified, ode_atol_pi_specified;
|
||||||
|
int ode_atol_l_specified, ode_initial_step_specified, ode_min_step_specified;
|
||||||
|
int ode_max_step_specified, ode_max_rejections_specified;
|
||||||
|
int trace_max_steps_specified, trace_lookback_time_specified;
|
||||||
|
int retry_step_increment_specified, max_total_steps_specified;
|
||||||
|
int retry_lookback_increment_specified, max_total_lookback_time_specified;
|
||||||
ToneMapSettings tone_map;
|
ToneMapSettings tone_map;
|
||||||
PngWriteSettings png;
|
PngWriteSettings png;
|
||||||
int sensor_bloom_enabled;
|
int sensor_bloom_enabled;
|
||||||
@@ -76,6 +96,15 @@ typedef struct {
|
|||||||
double sensor_bloom_transfer;
|
double sensor_bloom_transfer;
|
||||||
} Settings;
|
} Settings;
|
||||||
|
|
||||||
|
/* Keep the production default independent of backend-specific units and
|
||||||
|
* resource allowances, which are populated by trace_config(). */
|
||||||
|
static GeodesicStepper default_stepper(void) { return GEODESIC_STEPPER_DP54; }
|
||||||
|
|
||||||
|
static GeodesicTraceConfig trace_config(const Settings *s);
|
||||||
|
static RefinementConfig effective_refinement(const Settings *s,
|
||||||
|
const GeodesicTraceConfig *trace);
|
||||||
|
static int validate_settings(const Settings *s);
|
||||||
|
|
||||||
static int parse_int(const char *text, int *value) {
|
static int parse_int(const char *text, int *value) {
|
||||||
char *end;
|
char *end;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@@ -162,6 +191,27 @@ static int parse_finite_positive(const char *text, double *value) {
|
|||||||
return errno || end == text || *end || !isfinite(*value) || *value <= 0.0 ? -1 : 0;
|
return errno || end == text || *end || !isfinite(*value) || *value <= 0.0 ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Unsigned integer with the full 32-bit range, zero allowed. Used by retry
|
||||||
|
* quotas where an explicit zero is meaningful. */
|
||||||
|
static int parse_uint_nonnegative(const char *text, unsigned int *value) {
|
||||||
|
char *end;
|
||||||
|
errno = 0;
|
||||||
|
const unsigned long parsed = strtoul(text, &end, 10);
|
||||||
|
if (errno || end == text || *end || parsed > UINT_MAX)
|
||||||
|
return -1;
|
||||||
|
*value = (unsigned int)parsed;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unsigned integer that must be at least one. */
|
||||||
|
static int parse_uint_positive(const char *text, unsigned int *value) {
|
||||||
|
unsigned int parsed;
|
||||||
|
if (parse_uint_nonnegative(text, &parsed) || parsed == 0)
|
||||||
|
return -1;
|
||||||
|
*value = parsed;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Sensor-bloom transfer coefficient: finite and in [0, 1). */
|
/* Sensor-bloom transfer coefficient: finite and in [0, 1). */
|
||||||
static int parse_sensor_bloom_transfer(const char *text, double *value) {
|
static int parse_sensor_bloom_transfer(const char *text, double *value) {
|
||||||
char *end;
|
char *end;
|
||||||
@@ -406,6 +456,7 @@ static int parse_args(int argc, char **argv, Settings *s,
|
|||||||
.catalog_load_workers = 4,
|
.catalog_load_workers = 4,
|
||||||
.movie_output_workers = 0,
|
.movie_output_workers = 0,
|
||||||
.fast_fftw_plan_mode = FAST_PSF_FFTW_PLAN_ESTIMATE,
|
.fast_fftw_plan_mode = FAST_PSF_FFTW_PLAN_ESTIMATE,
|
||||||
|
.stepper = default_stepper(),
|
||||||
.refinement = {.angle_absolute_rad =
|
.refinement = {.angle_absolute_rad =
|
||||||
1e-3 * 3.14159265358979323846 / 180.0,
|
1e-3 * 3.14159265358979323846 / 180.0,
|
||||||
.angle_relative = 0.1,
|
.angle_relative = 0.1,
|
||||||
@@ -474,6 +525,60 @@ 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], "--dark-threshold") && i + 1 < argc &&
|
} else if (!strcmp(argv[i], "--dark-threshold") && i + 1 < argc &&
|
||||||
!parse_positive(argv[++i], &s->dark_threshold)) {
|
!parse_positive(argv[++i], &s->dark_threshold)) {
|
||||||
|
} else if (!strcmp(argv[i], "--integrator") && i + 1 < argc) {
|
||||||
|
const char *mode = argv[++i];
|
||||||
|
if (!strcmp(mode, "rk4")) {
|
||||||
|
s->stepper = GEODESIC_STEPPER_RK4;
|
||||||
|
} else if (!strcmp(mode, "dp54")) {
|
||||||
|
s->stepper = GEODESIC_STEPPER_DP54;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "--integrator expects rk4 or dp54.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
s->integrator_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--ode-rtol") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->ode_rtol)) {
|
||||||
|
s->ode_rtol_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--ode-atol-x") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->ode_atol_x)) {
|
||||||
|
s->ode_atol_x_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--ode-atol-pi") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->ode_atol_pi)) {
|
||||||
|
s->ode_atol_pi_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--ode-atol-l") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->ode_atol_l)) {
|
||||||
|
s->ode_atol_l_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--ode-initial-step") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->ode_initial_step)) {
|
||||||
|
s->ode_initial_step_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--ode-min-step") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->ode_min_step)) {
|
||||||
|
s->ode_min_step_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--ode-max-step") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->ode_max_step)) {
|
||||||
|
s->ode_max_step_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--ode-max-rejections") && i + 1 < argc &&
|
||||||
|
!parse_uint_positive(argv[++i], &s->ode_max_rejections)) {
|
||||||
|
s->ode_max_rejections_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--trace-max-steps") && i + 1 < argc &&
|
||||||
|
!parse_uint_positive(argv[++i], &s->trace_max_steps)) {
|
||||||
|
s->trace_max_steps_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--trace-lookback-time") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->trace_lookback_time)) {
|
||||||
|
s->trace_lookback_time_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--retry-step-increment") && i + 1 < argc &&
|
||||||
|
!parse_uint_nonnegative(argv[++i],
|
||||||
|
&s->refinement.retry_step_increment)) {
|
||||||
|
s->retry_step_increment_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--max-total-steps") && i + 1 < argc &&
|
||||||
|
!parse_uint_positive(argv[++i], &s->refinement.max_total_steps)) {
|
||||||
|
s->max_total_steps_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--retry-lookback-increment") && i + 1 < argc &&
|
||||||
|
!parse_nonnegative(argv[++i], &s->retry_lookback_increment)) {
|
||||||
|
s->retry_lookback_increment_specified = 1;
|
||||||
|
} else if (!strcmp(argv[i], "--max-total-lookback-time") && i + 1 < argc &&
|
||||||
|
!parse_finite_positive(argv[++i], &s->max_total_lookback_time)) {
|
||||||
|
s->max_total_lookback_time_specified = 1;
|
||||||
} else if (!strcmp(argv[i], "--tone-map") && i + 1 < argc) {
|
} else if (!strcmp(argv[i], "--tone-map") && i + 1 < argc) {
|
||||||
const char *mode = argv[++i];
|
const char *mode = argv[++i];
|
||||||
if (!strcmp(mode, "softclip"))
|
if (!strcmp(mode, "softclip"))
|
||||||
@@ -615,7 +720,7 @@ static int parse_args(int argc, char **argv, Settings *s,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
s->sensor_bloom_enabled = s->sensor_bloom_limit_specified;
|
s->sensor_bloom_enabled = s->sensor_bloom_limit_specified;
|
||||||
return 0;
|
return validate_settings(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_help(const char *program) {
|
static void print_help(const char *program) {
|
||||||
@@ -719,6 +824,26 @@ static void print_help(const char *program) {
|
|||||||
#endif
|
#endif
|
||||||
fputs(" --allow-incomplete Publish even when unresolved/error rays remain (diagnostic; output is marked incomplete)\n",
|
fputs(" --allow-incomplete Publish even when unresolved/error rays remain (diagnostic; output is marked incomplete)\n",
|
||||||
stdout);
|
stdout);
|
||||||
|
fputs(
|
||||||
|
"\nIntegrator (adaptive DP5(4); fixed RK4 for comparison):\n"
|
||||||
|
" --integrator rk4|dp54 Past-ray stepper (default: dp54)\n"
|
||||||
|
" --ode-rtol R DP54 relative tolerance (default: 1e-9)\n"
|
||||||
|
" --ode-atol-x A DP54 position absolute tolerance (default: 1e-9 * backend length)\n"
|
||||||
|
" --ode-atol-pi A DP54 Pi absolute tolerance (default: 1e-9)\n"
|
||||||
|
" --ode-atol-l A DP54 log-energy absolute tolerance (default: 1e-9)\n"
|
||||||
|
" --ode-initial-step H Initial trial step in coordinate time (default: backend step)\n"
|
||||||
|
" --ode-min-step H DP54 minimum step (default: max(1e-12, 16 eps) * backend unit)\n"
|
||||||
|
" --ode-max-step H DP54 maximum step (default: backend dependent)\n"
|
||||||
|
" --ode-max-rejections N Consecutive rejected trials before failure (default: 32)\n"
|
||||||
|
" --trace-max-steps N Initial accepted-step budget (default: backend budget)\n"
|
||||||
|
" --trace-lookback-time T Explicit DP54 coordinate-time lookback budget\n"
|
||||||
|
" --retry-step-increment N Accepted steps added per retry (0 disables step retries)\n"
|
||||||
|
" --max-total-steps N Hard per-ray accepted-step cap across retries\n"
|
||||||
|
" --retry-lookback-increment T Coordinate-time budget added per retry (0 keeps it fixed)\n"
|
||||||
|
" --max-total-lookback-time T Hard per-ray coordinate-time cap across retries\n"
|
||||||
|
" DP54-only options are rejected under --integrator rk4;\n"
|
||||||
|
" all tracing options are rejected with --lens-map-input.\n",
|
||||||
|
stdout);
|
||||||
#ifdef SPACETIME_ALCUBIERRE
|
#ifdef SPACETIME_ALCUBIERRE
|
||||||
fputs(
|
fputs(
|
||||||
"\nAlcubierre warp bubble (moving x_s(t)=v_s*t; no capture):\n"
|
"\nAlcubierre warp bubble (moving x_s(t)=v_s*t; no capture):\n"
|
||||||
@@ -851,9 +976,10 @@ static void report_frame_refinement(void *context, size_t generation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SPACETIME_ALCUBIERRE
|
#ifdef SPACETIME_ALCUBIERRE
|
||||||
/* Upper bound on the per-ray step budget. Legal parameters whose worst-case
|
/* Resource cap on the accepted-step estimate for the legacy fixed-step
|
||||||
* near-comoving ray could need more than this are rejected at startup rather
|
* Alcubierre domain guard. It bounds a resource allowance only; the adaptive
|
||||||
* than silently terminating as UNRESOLVED/BUDGET_EXHAUSTED. */
|
* coordinate-time budget, not an accepted-step count, defines the trusted
|
||||||
|
* traced history and is never derived from this cap. */
|
||||||
#define ALCUBIERRE_MAX_TRACE_STEPS (1u << 24)
|
#define ALCUBIERRE_MAX_TRACE_STEPS (1u << 24)
|
||||||
|
|
||||||
/* Safety margin over the straight-line worst case: wall-region deflection can
|
/* Safety margin over the straight-line worst case: wall-region deflection can
|
||||||
@@ -865,25 +991,33 @@ static double alcubierre_time_step(const Settings *s) {
|
|||||||
return fmin(0.1, 0.05 / s->alcubierre_sigma);
|
return fmin(0.1, 0.05 / s->alcubierre_sigma);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Worst-case per-ray step budget, including ALCUBIERRE_BUDGET_MARGIN. A ray
|
/* Coordinate-time coverage a past-directed Alcubierre ray must be granted.
|
||||||
* that is nearly comoving with the bubble separates from its center in the
|
* A ray that is nearly comoving with the bubble separates from its center in
|
||||||
* propagation direction at only ~1 - |v_s|, so crossing the ~4*escape domain
|
* the propagation direction at only ~1 - |v_s|, so crossing the ~4*escape
|
||||||
* can take ~4*escape/(1-|v_s|) in coordinate time. trace_config() and the
|
* domain takes up to ~4*escape/(1 - |v_s|), scaled by ALCUBIERRE_BUDGET_MARGIN
|
||||||
* startup rejection share this single value so the configured limit always
|
* for lingering in the wall. This is a physical budget derived from the bubble
|
||||||
* carries the full margin when it is accepted. */
|
* geometry and the asymptotic separation rate; it is independent of the chosen
|
||||||
static double alcubierre_step_budget(const Settings *s) {
|
* step size and of the accepted-step count. */
|
||||||
|
static double alcubierre_trace_time_budget(const Settings *s) {
|
||||||
const double escape =
|
const double escape =
|
||||||
spacetime_alcubierre_escape_radius(s->alcubierre_radius,
|
spacetime_alcubierre_escape_radius(s->alcubierre_radius,
|
||||||
s->alcubierre_sigma);
|
s->alcubierre_sigma);
|
||||||
const double separation = 1.0 - fabs(s->alcubierre_vs);
|
const double separation = 1.0 - fabs(s->alcubierre_vs);
|
||||||
return ALCUBIERRE_BUDGET_MARGIN * 4.0 * escape /
|
return ALCUBIERRE_BUDGET_MARGIN * 4.0 * escape / separation;
|
||||||
(separation * alcubierre_time_step(s));
|
}
|
||||||
|
|
||||||
|
/* Legacy accepted-step estimate for the same coverage, used only by the
|
||||||
|
* fixed-step RK4 comparison path and to seed the initial accepted-step resource
|
||||||
|
* allowance. The adaptive path uses alcubierre_trace_time_budget() directly
|
||||||
|
* and never derives its history from a step count. */
|
||||||
|
static double alcubierre_step_budget(const Settings *s) {
|
||||||
|
return alcubierre_trace_time_budget(s) / alcubierre_time_step(s);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Recompute approximate-black provenance and report E/D/U accounting. The
|
/* Recompute per-triangle approximate-black provenance and aggregate the E/D/U
|
||||||
* result is diagnostic for now; production failure gating is layered on top
|
* accounting across the given frames. The caller uses the returned totals both
|
||||||
* of the same counters. */
|
* for the verbose report and for boundary_allows_publish() production gating. */
|
||||||
static void report_boundary_stats(const Settings *s,
|
static void report_boundary_stats(const Settings *s,
|
||||||
FrameLensMesh *const *meshes,
|
FrameLensMesh *const *meshes,
|
||||||
size_t frame_count,
|
size_t frame_count,
|
||||||
@@ -927,10 +1061,50 @@ static void report_boundary_stats(const Settings *s,
|
|||||||
total.approx_black_level_stops);
|
total.approx_black_level_stops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint64_t add_cost_u64(uint64_t total, uint64_t value, int *saturated) {
|
||||||
|
if (UINT64_MAX - total < value) {
|
||||||
|
*saturated = 1;
|
||||||
|
return UINT64_MAX;
|
||||||
|
}
|
||||||
|
return total + value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sum a frame's persistent-vertex cost into a running total. Every vertex
|
||||||
|
* (including promoted probe witnesses) is counted once, so this is safe to
|
||||||
|
* call after refinement and across movie frames without double-counting a
|
||||||
|
* retried sample. */
|
||||||
|
static void accumulate_trace_stats(const FrameLensMesh *mesh,
|
||||||
|
FrameTraceStats *total) {
|
||||||
|
FrameTraceStats frame;
|
||||||
|
frame_lens_mesh_trace_stats(mesh, &frame);
|
||||||
|
int saturated = 0;
|
||||||
|
total->accepted_steps =
|
||||||
|
add_cost_u64(total->accepted_steps, frame.accepted_steps, &saturated);
|
||||||
|
total->rejected_steps =
|
||||||
|
add_cost_u64(total->rejected_steps, frame.rejected_steps, &saturated);
|
||||||
|
total->rhs_evaluations =
|
||||||
|
add_cost_u64(total->rhs_evaluations, frame.rhs_evaluations, &saturated);
|
||||||
|
total->vertices += frame.vertices;
|
||||||
|
total->saturated_vertices += frame.saturated_vertices + (saturated ? 1u : 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void report_trace_stats(const Settings *s, const FrameTraceStats *stats,
|
||||||
|
const char *label) {
|
||||||
|
if (!s->verbose)
|
||||||
|
return;
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s trace cost: accepted=%" PRIu64 " rejected=%" PRIu64
|
||||||
|
" rhs=%" PRIu64 " over %zu vertices (saturated=%zu).\n",
|
||||||
|
label, stats->accepted_steps, stats->rejected_steps,
|
||||||
|
stats->rhs_evaluations, stats->vertices, stats->saturated_vertices);
|
||||||
|
}
|
||||||
|
|
||||||
static LensMapProvenance lens_map_provenance(const Settings *s,
|
static LensMapProvenance lens_map_provenance(const Settings *s,
|
||||||
const GeodesicTraceConfig *trace) {
|
const GeodesicTraceConfig *trace) {
|
||||||
RefinementConfig rc = s->refinement;
|
const RefinementConfig rc = effective_refinement(s, trace);
|
||||||
frame_retry_config_defaults(&rc, trace);
|
/* An RK4 map advertises "no adaptive configuration" as explicit zeros; the
|
||||||
|
* DP54 adaptive policy is only stored when the DP54 stepper actually ran. */
|
||||||
|
const int dp = trace->stepper == GEODESIC_STEPPER_DP54;
|
||||||
return (LensMapProvenance){.threshold_kind = (uint32_t)trace->threshold.kind,
|
return (LensMapProvenance){.threshold_kind = (uint32_t)trace->threshold.kind,
|
||||||
.threshold_policy_version =
|
.threshold_policy_version =
|
||||||
trace->threshold.policy_version,
|
trace->threshold.policy_version,
|
||||||
@@ -938,11 +1112,24 @@ static LensMapProvenance lens_map_provenance(const Settings *s,
|
|||||||
.retry_step_increment = rc.retry_step_increment,
|
.retry_step_increment = rc.retry_step_increment,
|
||||||
.max_total_steps = rc.max_total_steps,
|
.max_total_steps = rc.max_total_steps,
|
||||||
.max_level = rc.max_level,
|
.max_level = rc.max_level,
|
||||||
.integrator = 0,
|
.integrator = (uint32_t)trace->stepper,
|
||||||
.min_edge_pixels = rc.min_edge_pixels,
|
.min_edge_pixels = rc.min_edge_pixels,
|
||||||
.min_area_pixels2 = rc.min_area_pixels2,
|
.min_area_pixels2 = rc.min_area_pixels2,
|
||||||
.coordinate_time_step = trace->coordinate_time_step,
|
.coordinate_time_step = trace->coordinate_time_step,
|
||||||
.initial_max_steps = trace->max_steps};
|
.initial_max_steps = trace->max_steps,
|
||||||
|
.atol_x = dp ? trace->atol_x : 0.0,
|
||||||
|
.atol_Pi = dp ? trace->atol_Pi : 0.0,
|
||||||
|
.atol_L = dp ? trace->atol_L : 0.0,
|
||||||
|
.rtol = dp ? trace->rtol : 0.0,
|
||||||
|
.min_step = dp ? trace->min_step : 0.0,
|
||||||
|
.max_step = dp ? trace->max_step : 0.0,
|
||||||
|
.max_lookback_time = dp ? trace->max_lookback_time : 0.0,
|
||||||
|
.retry_lookback_increment =
|
||||||
|
dp ? rc.retry_lookback_increment : 0.0,
|
||||||
|
.max_total_lookback_time =
|
||||||
|
dp ? rc.max_total_lookback_time : 0.0,
|
||||||
|
.max_consecutive_rejections =
|
||||||
|
dp ? trace->consecutive_rejection_limit : 0u};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Refuse to publish silently on true errors or on unresolved triangles that
|
/* Refuse to publish silently on true errors or on unresolved triangles that
|
||||||
@@ -976,30 +1163,207 @@ static GeodesicTraceConfig trace_config(const Settings *s) {
|
|||||||
const ThresholdPolicy threshold = {.kind = THRESHOLD_LOG_ENERGY_GROWTH,
|
const ThresholdPolicy threshold = {.kind = THRESHOLD_LOG_ENERGY_GROWTH,
|
||||||
.value = s->dark_threshold,
|
.value = s->dark_threshold,
|
||||||
.policy_version = 3};
|
.policy_version = 3};
|
||||||
#ifdef SPACETIME_SCHWARZSCHILD
|
/* Per-backend integration policy. `default_step` is the initial DP54 trial
|
||||||
/* The directed worldtube crossing makes an escaping ray traverse the
|
* step (and RK4's fixed step on the legacy comparison path), `default_budget`
|
||||||
* interior as a round trip from the entry sphere (in, turn, back out),
|
* is the initial accepted-step resource allowance, `length_unit` scales the
|
||||||
* rather than the old one-way stop at the first outside sample. The step
|
* position tolerance and minimum step, and `default_max_step` bounds the DP54
|
||||||
* budget must cover roughly twice the escape sphere plus margin. */
|
* trial step. `default_lookback` is the trusted coordinate-time coverage: it
|
||||||
return (GeodesicTraceConfig){.coordinate_time_step = 0.1,
|
* is an explicit constant or a geometry-derived physical time, never the
|
||||||
.max_steps = 65536,
|
* product of the chosen step and the chosen step count. The directed
|
||||||
.threshold = threshold};
|
* worldtube crossing in Schwarzschild makes an escaping ray traverse the
|
||||||
|
* interior as a round trip, so its resource budget covers roughly twice the
|
||||||
|
* escape sphere plus margin. */
|
||||||
|
double default_step;
|
||||||
|
unsigned int default_budget;
|
||||||
|
double length_unit;
|
||||||
|
double default_max_step;
|
||||||
|
double default_lookback;
|
||||||
|
#if defined(SPACETIME_SCHWARZSCHILD)
|
||||||
|
default_step = 0.1;
|
||||||
|
default_budget = 65536;
|
||||||
|
length_unit = 1.0;
|
||||||
|
/* The far-field cap should not force small steps after the adaptive error
|
||||||
|
* controller has resolved the strong-field segment. */
|
||||||
|
default_max_step = 8.0;
|
||||||
|
/* Fixed-step physical coverage: 0.1 * 65536. */
|
||||||
|
default_lookback = 6553.6;
|
||||||
#elif defined(SPACETIME_ALCUBIERRE)
|
#elif defined(SPACETIME_ALCUBIERRE)
|
||||||
const double step = alcubierre_time_step(s);
|
default_step = alcubierre_time_step(s);
|
||||||
const double budget = alcubierre_step_budget(s);
|
{
|
||||||
unsigned max_steps = ALCUBIERRE_MAX_TRACE_STEPS;
|
/* Accepted-step resource estimate along the legacy fixed-step policy. It
|
||||||
if (budget < (double)max_steps && isfinite(budget))
|
* may be capped at ALCUBIERRE_MAX_TRACE_STEPS; the coordinate-time coverage
|
||||||
max_steps = (unsigned)ceil(budget);
|
* below is what guarantees the physical budget, so a capped count never
|
||||||
if (max_steps < 1024u)
|
* shortens the trusted history. */
|
||||||
max_steps = 1024u;
|
const double estimated_steps = alcubierre_step_budget(s);
|
||||||
return (GeodesicTraceConfig){.coordinate_time_step = step,
|
unsigned int budget = ALCUBIERRE_MAX_TRACE_STEPS;
|
||||||
.max_steps = max_steps,
|
if (isfinite(estimated_steps) && estimated_steps < (double)budget)
|
||||||
.threshold = threshold};
|
budget = (unsigned int)ceil(estimated_steps);
|
||||||
|
if (budget < 1024u)
|
||||||
|
budget = 1024u;
|
||||||
|
default_budget = budget;
|
||||||
|
}
|
||||||
|
length_unit = s->alcubierre_radius;
|
||||||
|
default_max_step = default_step * 8.0;
|
||||||
|
/* Physical coordinate-time coverage from the bubble geometry and the
|
||||||
|
* asymptotic separation rate, independent of the chosen step or step count. */
|
||||||
|
default_lookback = alcubierre_trace_time_budget(s);
|
||||||
#else
|
#else
|
||||||
return (GeodesicTraceConfig){.coordinate_time_step = 1.0,
|
default_step = 1.0;
|
||||||
.max_steps = 2048,
|
default_budget = 2048;
|
||||||
.threshold = threshold};
|
length_unit = 1.0;
|
||||||
|
default_max_step = 16.0;
|
||||||
|
/* Fixed-step physical coverage: 1.0 * 2048. */
|
||||||
|
default_lookback = 2048.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
double step = default_step;
|
||||||
|
unsigned int budget = default_budget;
|
||||||
|
if (s->ode_initial_step_specified)
|
||||||
|
step = s->ode_initial_step;
|
||||||
|
if (s->trace_max_steps_specified)
|
||||||
|
budget = s->trace_max_steps;
|
||||||
|
|
||||||
|
const double default_min_step =
|
||||||
|
fmax(1e-12 * length_unit, 16.0 * DBL_EPSILON * length_unit);
|
||||||
|
const double default_atol_x = 1e-9 * length_unit;
|
||||||
|
return (GeodesicTraceConfig){
|
||||||
|
.coordinate_time_step = step,
|
||||||
|
.max_steps = budget,
|
||||||
|
.threshold = threshold,
|
||||||
|
.stepper = s->stepper,
|
||||||
|
.atol_x = s->ode_atol_x_specified ? s->ode_atol_x : default_atol_x,
|
||||||
|
.atol_Pi = s->ode_atol_pi_specified ? s->ode_atol_pi : 1e-9,
|
||||||
|
.atol_L = s->ode_atol_l_specified ? s->ode_atol_l : 1e-9,
|
||||||
|
.rtol = s->ode_rtol_specified ? s->ode_rtol : 1e-9,
|
||||||
|
.min_step = s->ode_min_step_specified ? s->ode_min_step : default_min_step,
|
||||||
|
.max_step = s->ode_max_step_specified ? s->ode_max_step : default_max_step,
|
||||||
|
.consecutive_rejection_limit =
|
||||||
|
s->ode_max_rejections_specified ? s->ode_max_rejections : 32u,
|
||||||
|
.max_lookback_time = s->trace_lookback_time_specified
|
||||||
|
? s->trace_lookback_time
|
||||||
|
: default_lookback};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve the retry resource policy. The flag-aware defaults keep an explicit
|
||||||
|
* zero (e.g. --retry-step-increment 0 to disable step retries) distinct from a
|
||||||
|
* value left unset, which the existing frame-level helper could not. */
|
||||||
|
static RefinementConfig effective_refinement(const Settings *s,
|
||||||
|
const GeodesicTraceConfig *trace) {
|
||||||
|
RefinementConfig rc = s->refinement;
|
||||||
|
if (rc.retry_step_increment == 0 && !s->retry_step_increment_specified)
|
||||||
|
rc.retry_step_increment = trace->max_steps;
|
||||||
|
if (rc.max_total_steps == 0 && !s->max_total_steps_specified)
|
||||||
|
rc.max_total_steps = trace->max_steps > (UINT_MAX / 4u)
|
||||||
|
? trace->max_steps
|
||||||
|
: trace->max_steps * 4u;
|
||||||
|
if (trace->stepper == GEODESIC_STEPPER_DP54) {
|
||||||
|
if (s->retry_lookback_increment_specified) {
|
||||||
|
rc.retry_lookback_increment = s->retry_lookback_increment;
|
||||||
|
} else if (rc.retry_lookback_increment == 0.0) {
|
||||||
|
rc.retry_lookback_increment = trace->max_lookback_time;
|
||||||
|
}
|
||||||
|
if (s->max_total_lookback_time_specified) {
|
||||||
|
rc.max_total_lookback_time = s->max_total_lookback_time;
|
||||||
|
} else if (rc.max_total_lookback_time == 0.0) {
|
||||||
|
rc.max_total_lookback_time = trace->max_lookback_time > DBL_MAX / 4.0
|
||||||
|
? DBL_MAX
|
||||||
|
: trace->max_lookback_time * 4.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the first explicitly specified option that replay cannot honor; a
|
||||||
|
* render-only import must consume the stored policy instead of overriding it. */
|
||||||
|
static const char *replay_tracing_option(const Settings *s) {
|
||||||
|
if (s->integrator_specified) return "--integrator";
|
||||||
|
if (s->ode_rtol_specified) return "--ode-rtol";
|
||||||
|
if (s->ode_atol_x_specified) return "--ode-atol-x";
|
||||||
|
if (s->ode_atol_pi_specified) return "--ode-atol-pi";
|
||||||
|
if (s->ode_atol_l_specified) return "--ode-atol-l";
|
||||||
|
if (s->ode_initial_step_specified) return "--ode-initial-step";
|
||||||
|
if (s->ode_min_step_specified) return "--ode-min-step";
|
||||||
|
if (s->ode_max_step_specified) return "--ode-max-step";
|
||||||
|
if (s->ode_max_rejections_specified) return "--ode-max-rejections";
|
||||||
|
if (s->trace_max_steps_specified) return "--trace-max-steps";
|
||||||
|
if (s->trace_lookback_time_specified) return "--trace-lookback-time";
|
||||||
|
if (s->retry_step_increment_specified) return "--retry-step-increment";
|
||||||
|
if (s->max_total_steps_specified) return "--max-total-steps";
|
||||||
|
if (s->retry_lookback_increment_specified) return "--retry-lookback-increment";
|
||||||
|
if (s->max_total_lookback_time_specified) return "--max-total-lookback-time";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cross-option checks that need the resolved per-backend trace policy. */
|
||||||
|
static int validate_settings(const Settings *s) {
|
||||||
|
const GeodesicTraceConfig trace = trace_config(s);
|
||||||
|
if (trace.stepper == GEODESIC_STEPPER_RK4) {
|
||||||
|
const char *bad = NULL;
|
||||||
|
if (s->ode_rtol_specified) bad = "--ode-rtol";
|
||||||
|
else if (s->ode_atol_x_specified) bad = "--ode-atol-x";
|
||||||
|
else if (s->ode_atol_pi_specified) bad = "--ode-atol-pi";
|
||||||
|
else if (s->ode_atol_l_specified) bad = "--ode-atol-l";
|
||||||
|
else if (s->ode_min_step_specified) bad = "--ode-min-step";
|
||||||
|
else if (s->ode_max_step_specified) bad = "--ode-max-step";
|
||||||
|
else if (s->ode_max_rejections_specified) bad = "--ode-max-rejections";
|
||||||
|
else if (s->trace_lookback_time_specified) bad = "--trace-lookback-time";
|
||||||
|
else if (s->retry_lookback_increment_specified)
|
||||||
|
bad = "--retry-lookback-increment";
|
||||||
|
else if (s->max_total_lookback_time_specified)
|
||||||
|
bad = "--max-total-lookback-time";
|
||||||
|
if (bad != NULL) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s applies only to --integrator dp54; the fixed-step RK4 path "
|
||||||
|
"has no adaptive tolerance or lookback policy.\n",
|
||||||
|
bad);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!(trace.min_step <= trace.coordinate_time_step &&
|
||||||
|
trace.coordinate_time_step <= trace.max_step)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Adaptive step bounds must satisfy min <= initial <= max "
|
||||||
|
"(min=%.17g, initial=%.17g, max=%.17g).\n",
|
||||||
|
trace.min_step, trace.coordinate_time_step, trace.max_step);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (s->max_total_steps_specified && s->refinement.max_total_steps != 0 &&
|
||||||
|
s->refinement.max_total_steps < trace.max_steps) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"--max-total-steps (%u) must be >= the initial step budget (%u).\n",
|
||||||
|
s->refinement.max_total_steps, trace.max_steps);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (s->max_total_lookback_time_specified &&
|
||||||
|
s->max_total_lookback_time < trace.max_lookback_time) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"--max-total-lookback-time (%.17g) must be >= the initial lookback "
|
||||||
|
"budget (%.17g).\n",
|
||||||
|
s->max_total_lookback_time, trace.max_lookback_time);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *stepper_name(GeodesicStepper stepper) {
|
||||||
|
return stepper == GEODESIC_STEPPER_DP54 ? "dp54" : "rk4";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void report_trace_config(const Settings *s,
|
||||||
|
const GeodesicTraceConfig *trace,
|
||||||
|
const char *label) {
|
||||||
|
if (!s->verbose)
|
||||||
|
return;
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s: integrator=%s step=%.8g max_steps=%u threshold=%.8g "
|
||||||
|
"atol=(x %.8g, Pi %.8g, L %.8g) rtol=%.8g bounds=[%.8g, %.8g] "
|
||||||
|
"max_rejections=%u lookback=%.8g\n",
|
||||||
|
label, stepper_name(trace->stepper), trace->coordinate_time_step,
|
||||||
|
trace->max_steps, trace->threshold.value, trace->atol_x,
|
||||||
|
trace->atol_Pi, trace->atol_L, trace->rtol, trace->min_step,
|
||||||
|
trace->max_step, trace->consecutive_rejection_limit,
|
||||||
|
trace->max_lookback_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int resolve_camera(Settings *s) {
|
static int resolve_camera(Settings *s) {
|
||||||
@@ -1098,6 +1462,8 @@ static int render_observer_frame(const Settings *s, StarCatalog *catalog,
|
|||||||
const ObserverState *observer,
|
const ObserverState *observer,
|
||||||
const char *output_path) {
|
const char *output_path) {
|
||||||
const GeodesicTraceConfig trace = trace_config(s);
|
const GeodesicTraceConfig trace = trace_config(s);
|
||||||
|
const RefinementConfig refinement_config = effective_refinement(s, &trace);
|
||||||
|
report_trace_config(s, &trace, "Frame 0");
|
||||||
FrameLensMesh mesh = {0};
|
FrameLensMesh mesh = {0};
|
||||||
double *hdr = calloc((size_t)s->width * s->height * 3, sizeof *hdr);
|
double *hdr = calloc((size_t)s->width * s->height * 3, sizeof *hdr);
|
||||||
if (hdr == NULL || frame_lens_mesh_build_coarse(&mesh, s->width, s->height,
|
if (hdr == NULL || frame_lens_mesh_build_coarse(&mesh, s->width, s->height,
|
||||||
@@ -1124,7 +1490,7 @@ static int render_observer_frame(const Settings *s, StarCatalog *catalog,
|
|||||||
s->refinement.max_level);
|
s->refinement.max_level);
|
||||||
const double refinement_start = omp_get_wtime();
|
const double refinement_start = omp_get_wtime();
|
||||||
if (frame_lens_mesh_refine_with_progress(
|
if (frame_lens_mesh_refine_with_progress(
|
||||||
&mesh, spacetime, observer, &trace, &s->refinement,
|
&mesh, spacetime, observer, &trace, &refinement_config,
|
||||||
s->verbose ? report_frame_refinement : NULL, (void *)s)) {
|
s->verbose ? report_frame_refinement : NULL, (void *)s)) {
|
||||||
frame_lens_mesh_destroy(&mesh);
|
frame_lens_mesh_destroy(&mesh);
|
||||||
free(hdr);
|
free(hdr);
|
||||||
@@ -1137,11 +1503,13 @@ static int render_observer_frame(const Settings *s, StarCatalog *catalog,
|
|||||||
omp_get_wtime() - refinement_start, mesh.vertex_count,
|
omp_get_wtime() - refinement_start, mesh.vertex_count,
|
||||||
mesh.triangle_count);
|
mesh.triangle_count);
|
||||||
FrameBoundaryStats boundary_totals;
|
FrameBoundaryStats boundary_totals;
|
||||||
|
FrameLensMesh *frame_meshes[1] = {&mesh};
|
||||||
|
report_boundary_stats(s, frame_meshes, 1, &refinement_config,
|
||||||
|
&boundary_totals);
|
||||||
{
|
{
|
||||||
RefinementConfig boundary_config = s->refinement;
|
FrameTraceStats trace_stats;
|
||||||
frame_retry_config_defaults(&boundary_config, &trace);
|
frame_lens_mesh_trace_stats(&mesh, &trace_stats);
|
||||||
FrameLensMesh *meshes[1] = {&mesh};
|
report_trace_stats(s, &trace_stats, "Frame 0");
|
||||||
report_boundary_stats(s, meshes, 1, &boundary_config, &boundary_totals);
|
|
||||||
}
|
}
|
||||||
if (!boundary_allows_publish(s, &boundary_totals)) {
|
if (!boundary_allows_publish(s, &boundary_totals)) {
|
||||||
frame_lens_mesh_destroy(&mesh);
|
frame_lens_mesh_destroy(&mesh);
|
||||||
@@ -1230,8 +1598,7 @@ static int trace_movie_generation(Movie *movie, const Settings *s,
|
|||||||
RayPool rays = {0};
|
RayPool rays = {0};
|
||||||
size_t ray_count = 0;
|
size_t ray_count = 0;
|
||||||
size_t total_added = 0;
|
size_t total_added = 0;
|
||||||
RefinementConfig effective = s->refinement;
|
RefinementConfig effective = effective_refinement(s, trace);
|
||||||
frame_retry_config_defaults(&effective, trace);
|
|
||||||
for (size_t f = 0; f < movie->frame_count; ++f) {
|
for (size_t f = 0; f < movie->frame_count; ++f) {
|
||||||
const int prepared = frame_lens_mesh_prepare_generation(
|
const int prepared = frame_lens_mesh_prepare_generation(
|
||||||
&movie->frames[f].mesh, &effective);
|
&movie->frames[f].mesh, &effective);
|
||||||
@@ -1252,12 +1619,14 @@ static int trace_movie_generation(Movie *movie, const Settings *s,
|
|||||||
if (fs->cached) continue;
|
if (fs->cached) continue;
|
||||||
int rc;
|
int rc;
|
||||||
if (fs->kind == FRAME_SAMPLE_RETRY) {
|
if (fs->kind == FRAME_SAMPLE_RETRY) {
|
||||||
const LensVertex *v = &fs->vertex;
|
GeodesicRayState state;
|
||||||
rc = ray_pool_append_continuation(
|
if (frame_vertex_continuation_state(&fs->vertex, &state)) {
|
||||||
&rays, f, sample, v->continuation_t, v->continuation_x,
|
ray_pool_destroy(&rays);
|
||||||
v->continuation_Pi, v->continuation_log_alpha_p0,
|
return -1;
|
||||||
v->continuation_log_alpha_p0_0, v->continuation_steps,
|
}
|
||||||
fs->step_limit);
|
rc = ray_pool_append_continuation_state(&rays, f, sample, &state,
|
||||||
|
fs->step_limit,
|
||||||
|
fs->lookback_limit);
|
||||||
} else {
|
} else {
|
||||||
rc = ray_pool_append(&rays, &movie->frames[f].observer,
|
rc = ray_pool_append(&rays, &movie->frames[f].observer,
|
||||||
fs->vertex.camera_direction, f, sample);
|
fs->vertex.camera_direction, f, sample);
|
||||||
@@ -1454,6 +1823,7 @@ static int render_movie(const Settings *s, StarCatalog *catalog,
|
|||||||
ObserverTrack track = {0};
|
ObserverTrack track = {0};
|
||||||
Movie movie = {0};
|
Movie movie = {0};
|
||||||
const GeodesicTraceConfig trace = trace_config(s);
|
const GeodesicTraceConfig trace = trace_config(s);
|
||||||
|
report_trace_config(s, &trace, "Movie");
|
||||||
MovieOutputQueue output_queue;
|
MovieOutputQueue output_queue;
|
||||||
int output_queue_ready = 0;
|
int output_queue_ready = 0;
|
||||||
int result = -1;
|
int result = -1;
|
||||||
@@ -1478,8 +1848,7 @@ static int render_movie(const Settings *s, StarCatalog *catalog,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
RefinementConfig boundary_config = s->refinement;
|
const RefinementConfig boundary_config = effective_refinement(s, &trace);
|
||||||
frame_retry_config_defaults(&boundary_config, &trace);
|
|
||||||
FrameLensMesh **meshes = malloc(movie.frame_count * sizeof *meshes);
|
FrameLensMesh **meshes = malloc(movie.frame_count * sizeof *meshes);
|
||||||
if (meshes == NULL)
|
if (meshes == NULL)
|
||||||
goto done;
|
goto done;
|
||||||
@@ -1488,6 +1857,10 @@ static int render_movie(const Settings *s, StarCatalog *catalog,
|
|||||||
FrameBoundaryStats boundary_totals;
|
FrameBoundaryStats boundary_totals;
|
||||||
report_boundary_stats(s, meshes, movie.frame_count, &boundary_config,
|
report_boundary_stats(s, meshes, movie.frame_count, &boundary_config,
|
||||||
&boundary_totals);
|
&boundary_totals);
|
||||||
|
FrameTraceStats trace_totals = {0};
|
||||||
|
for (size_t i = 0; i < movie.frame_count; ++i)
|
||||||
|
accumulate_trace_stats(&movie.frames[i].mesh, &trace_totals);
|
||||||
|
report_trace_stats(s, &trace_totals, "Movie");
|
||||||
free(meshes);
|
free(meshes);
|
||||||
if (!boundary_allows_publish(s, &boundary_totals))
|
if (!boundary_allows_publish(s, &boundary_totals))
|
||||||
goto done;
|
goto done;
|
||||||
@@ -1623,17 +1996,40 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int render_lens_map(const Settings *s, StarCatalog *catalog) {
|
static int render_lens_map(const Settings *s, StarCatalog *catalog) {
|
||||||
|
const char *replay_conflict = replay_tracing_option(s);
|
||||||
|
if (replay_conflict != NULL) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"%s cannot be combined with --lens-map-input; a render-only replay "
|
||||||
|
"consumes the integration and retry policy stored in the map.\n",
|
||||||
|
replay_conflict);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
LensMap map = {0};
|
LensMap map = {0};
|
||||||
if (lens_map_read(s->lens_map_input_path, NULL, &map)) {
|
if (lens_map_read(s->lens_map_input_path, NULL, &map)) {
|
||||||
fprintf(stderr, "Failed to read or validate lens map: %s\n", s->lens_map_input_path);
|
fprintf(stderr, "Failed to read or validate lens map: %s\n", s->lens_map_input_path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (s->verbose)
|
||||||
|
fprintf(stderr,
|
||||||
|
"Imported lens map v%u: integrator=%s step=%.8g max_steps=%u "
|
||||||
|
"lookback=%.8g retry_lookback=%.8g max_total_lookback=%.8g\n",
|
||||||
|
map.file_version,
|
||||||
|
stepper_name((GeodesicStepper)map.provenance.integrator),
|
||||||
|
map.provenance.coordinate_time_step, map.provenance.initial_max_steps,
|
||||||
|
map.provenance.max_lookback_time,
|
||||||
|
map.provenance.retry_lookback_increment,
|
||||||
|
map.provenance.max_total_lookback_time);
|
||||||
|
/* Render-only replay never retries, but the full source policy (including
|
||||||
|
* the coordinate-time retry quotas) is restored rather than replaced by the
|
||||||
|
* process's CLI defaults. */
|
||||||
RefinementConfig replay_config = {
|
RefinementConfig replay_config = {
|
||||||
.max_level = map.provenance.max_level,
|
.max_level = map.provenance.max_level,
|
||||||
.min_edge_pixels = map.provenance.min_edge_pixels,
|
.min_edge_pixels = map.provenance.min_edge_pixels,
|
||||||
.min_area_pixels2 = map.provenance.min_area_pixels2,
|
.min_area_pixels2 = map.provenance.min_area_pixels2,
|
||||||
.retry_step_increment = map.provenance.retry_step_increment,
|
.retry_step_increment = map.provenance.retry_step_increment,
|
||||||
.max_total_steps = map.provenance.max_total_steps};
|
.max_total_steps = map.provenance.max_total_steps,
|
||||||
|
.retry_lookback_increment = map.provenance.retry_lookback_increment,
|
||||||
|
.max_total_lookback_time = map.provenance.max_total_lookback_time};
|
||||||
int replay_incomplete = 0;
|
int replay_incomplete = 0;
|
||||||
/* Replay consumes stored decisions, not current CLI refinement defaults. */
|
/* Replay consumes stored decisions, not current CLI refinement defaults. */
|
||||||
for (size_t f = 0; f < map.frame_count; ++f) {
|
for (size_t f = 0; f < map.frame_count; ++f) {
|
||||||
@@ -1644,6 +2040,12 @@ static int render_lens_map(const Settings *s, StarCatalog *catalog) {
|
|||||||
lens_map_destroy(&map); return -1;
|
lens_map_destroy(&map); return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
FrameTraceStats trace_totals = {0};
|
||||||
|
for (size_t f = 0; f < map.frame_count; ++f)
|
||||||
|
accumulate_trace_stats(&map.frames[f].mesh, &trace_totals);
|
||||||
|
report_trace_stats(s, &trace_totals, "Imported map");
|
||||||
|
}
|
||||||
if ((s->width_specified && s->width != map.width) ||
|
if ((s->width_specified && s->width != map.width) ||
|
||||||
(s->height_specified && s->height != map.height) ||
|
(s->height_specified && s->height != map.height) ||
|
||||||
(s->fov_specified && fabs(s->horizontal_fov_deg - map.horizontal_fov_deg) > 1e-12)) {
|
(s->fov_specified && fabs(s->horizontal_fov_deg - map.horizontal_fov_deg) > 1e-12)) {
|
||||||
@@ -1878,6 +2280,12 @@ int main(int argc, char **argv) {
|
|||||||
"--refine-jacobian-min J "
|
"--refine-jacobian-min J "
|
||||||
"--refine-min-edge-pixels P --refine-min-area-pixels2 A] "
|
"--refine-min-edge-pixels P --refine-min-area-pixels2 A] "
|
||||||
"[--draw-mesh] [--write-catalog PATH] "
|
"[--draw-mesh] [--write-catalog PATH] "
|
||||||
|
"[--integrator rk4|dp54 --ode-rtol R --ode-atol-x A "
|
||||||
|
"--ode-atol-pi A --ode-atol-l A --ode-initial-step H "
|
||||||
|
"--ode-min-step H --ode-max-step H --ode-max-rejections N "
|
||||||
|
"--trace-max-steps N --trace-lookback-time T "
|
||||||
|
"--retry-step-increment N --max-total-steps N "
|
||||||
|
"--retry-lookback-increment T --max-total-lookback-time T] "
|
||||||
"[--catalog-load-workers N] "
|
"[--catalog-load-workers N] "
|
||||||
"[--observer-track PATH --frames-dir DIR --frames-prefix NAME "
|
"[--observer-track PATH --frames-dir DIR --frames-prefix NAME "
|
||||||
"--start-time T --duration T --fps N | --movie-track-samples] "
|
"--start-time T --duration T --fps N | --movie-track-samples] "
|
||||||
@@ -1989,9 +2397,16 @@ int main(int argc, char **argv) {
|
|||||||
"R > 0, sigma > 0.\n", stderr);
|
"R > 0, sigma > 0.\n", stderr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (alcubierre_step_budget(&settings) >
|
/* The fixed-step RK4 comparison path sizes its history from
|
||||||
(double)ALCUBIERRE_MAX_TRACE_STEPS) {
|
* step * accepted-step count, so its domain guard still rejects an
|
||||||
/* The budget has a V-shaped minimum at sigma = 0.5, where the step
|
* estimate that exceeds the cap. The adaptive path uses an independent
|
||||||
|
* coordinate-time budget and must not be rejected here: trustworthy quota
|
||||||
|
* exhaustion is reported as UNRESOLVED and handled by the publication
|
||||||
|
* gate, and explicit lookback/step overrides remain independent. */
|
||||||
|
if (settings.stepper == GEODESIC_STEPPER_RK4 &&
|
||||||
|
alcubierre_step_budget(&settings) >
|
||||||
|
(double)ALCUBIERRE_MAX_TRACE_STEPS) {
|
||||||
|
/* The estimate has a V-shaped minimum at sigma = 0.5, where the step
|
||||||
* stops being capped: below it the 20/sigma term dominates (increase
|
* stops being capped: below it the 20/sigma term dominates (increase
|
||||||
* sigma helps), above it the step scales as 1/sigma (decrease sigma
|
* sigma helps), above it the step scales as 1/sigma (decrease sigma
|
||||||
* helps), and at exactly 0.5 neither direction improves anything. */
|
* helps), and at exactly 0.5 neither direction improves anything. */
|
||||||
@@ -2001,9 +2416,9 @@ int main(int argc, char **argv) {
|
|||||||
else if (settings.alcubierre_sigma < 0.5)
|
else if (settings.alcubierre_sigma < 0.5)
|
||||||
sigma_advice = "increase --alcubierre-sigma, ";
|
sigma_advice = "increase --alcubierre-sigma, ";
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Alcubierre trace budget exceeds the %u-step cap; decrease "
|
"Fixed-step RK4 Alcubierre trace budget exceeds the %u-step "
|
||||||
"--alcubierre-radius, %sor move --alcubierre-vs away from "
|
"cap; decrease --alcubierre-radius, %sor move --alcubierre-vs "
|
||||||
"+/-1.\n",
|
"away from +/-1, or use the adaptive default.\n",
|
||||||
ALCUBIERRE_MAX_TRACE_STEPS, sigma_advice);
|
ALCUBIERRE_MAX_TRACE_STEPS, sigma_advice);
|
||||||
spacetime_destroy(&spacetime);
|
spacetime_destroy(&spacetime);
|
||||||
return 2;
|
return 2;
|
||||||
|
|||||||
@@ -16,7 +16,10 @@ int ray_pool_init(RayPool *p, size_t capacity) {
|
|||||||
RAY_ALLOC(direction0) && RAY_ALLOC(direction1) && RAY_ALLOC(direction2) &&
|
RAY_ALLOC(direction0) && RAY_ALLOC(direction1) && RAY_ALLOC(direction2) &&
|
||||||
RAY_ALLOC(log_alpha_p0) && RAY_ALLOC(log_alpha_p0_0) &&
|
RAY_ALLOC(log_alpha_p0) && RAY_ALLOC(log_alpha_p0_0) &&
|
||||||
RAY_ALLOC(activate_t) && RAY_ALLOC(steps) &&
|
RAY_ALLOC(activate_t) && RAY_ALLOC(steps) &&
|
||||||
RAY_ALLOC(step_limit) && RAY_ALLOC(continuation) &&
|
RAY_ALLOC(step_limit) && RAY_ALLOC(integration_start_time) &&
|
||||||
|
RAY_ALLOC(next_step) && RAY_ALLOC(rejected_steps) &&
|
||||||
|
RAY_ALLOC(rhs_evaluations) && RAY_ALLOC(previous_rejected) &&
|
||||||
|
RAY_ALLOC(lookback_limit) && RAY_ALLOC(continuation) &&
|
||||||
RAY_ALLOC(frame_id) && RAY_ALLOC(vertex_id) && RAY_ALLOC(status) &&
|
RAY_ALLOC(frame_id) && RAY_ALLOC(vertex_id) && RAY_ALLOC(status) &&
|
||||||
RAY_ALLOC(endpoint))) {
|
RAY_ALLOC(endpoint))) {
|
||||||
ray_pool_destroy(p);
|
ray_pool_destroy(p);
|
||||||
@@ -55,30 +58,45 @@ int ray_pool_append(RayPool *p, const ObserverState *observer,
|
|||||||
.final_log_alpha_p0_0 = NAN,
|
.final_log_alpha_p0_0 = NAN,
|
||||||
.threshold_value = NAN};
|
.threshold_value = NAN};
|
||||||
p->step_limit[i] = 0;
|
p->step_limit[i] = 0;
|
||||||
|
/* Adaptive control state starts unset; ray_pool_preroute() seeds the window
|
||||||
|
* start from the resolved activation time. Initializing here as well keeps
|
||||||
|
* a directly advanced pool slot well-defined. */
|
||||||
|
p->integration_start_time[i] = observer->coordinate_time;
|
||||||
|
p->next_step[i] = 0.0;
|
||||||
|
p->rejected_steps[i] = 0;
|
||||||
|
p->rhs_evaluations[i] = 0;
|
||||||
|
p->previous_rejected[i] = 0;
|
||||||
|
p->lookback_limit[i] = 0.0;
|
||||||
p->continuation[i] = 0;
|
p->continuation[i] = 0;
|
||||||
p->log_alpha_p0_0[i] = 0.0;
|
p->log_alpha_p0_0[i] = 0.0;
|
||||||
++p->count;
|
++p->count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ray_pool_append_continuation(RayPool *p, size_t frame_id,
|
int ray_pool_append_continuation_state(RayPool *p, size_t frame_id,
|
||||||
size_t vertex_id, double t, const double x[3],
|
size_t vertex_id,
|
||||||
const double Pi[3], double log_alpha_p0,
|
const GeodesicRayState *state,
|
||||||
double log_alpha_p0_0, unsigned int steps,
|
unsigned int accepted_limit,
|
||||||
unsigned int limit) {
|
double lookback_limit) {
|
||||||
if (p == NULL || p->count == p->capacity || x == NULL || Pi == NULL)
|
if (p == NULL || p->count == p->capacity || state == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
const size_t i = p->count;
|
const size_t i = p->count;
|
||||||
p->t[i] = t;
|
p->t[i] = state->coordinate_time;
|
||||||
p->activate_t[i] = t;
|
p->activate_t[i] = state->coordinate_time;
|
||||||
p->observer[i] = NULL;
|
p->observer[i] = NULL;
|
||||||
p->direction0[i] = p->direction1[i] = p->direction2[i] = 0.0;
|
p->direction0[i] = p->direction1[i] = p->direction2[i] = 0.0;
|
||||||
p->x0[i] = x[0]; p->x1[i] = x[1]; p->x2[i] = x[2];
|
p->x0[i] = state->x[0]; p->x1[i] = state->x[1]; p->x2[i] = state->x[2];
|
||||||
p->p0[i] = Pi[0]; p->p1[i] = Pi[1]; p->p2[i] = Pi[2];
|
p->p0[i] = state->Pi[0]; p->p1[i] = state->Pi[1]; p->p2[i] = state->Pi[2];
|
||||||
p->log_alpha_p0[i] = log_alpha_p0;
|
p->log_alpha_p0[i] = state->log_alpha_p0;
|
||||||
p->log_alpha_p0_0[i] = log_alpha_p0_0;
|
p->log_alpha_p0_0[i] = state->log_alpha_p0_0;
|
||||||
p->steps[i] = steps;
|
p->steps[i] = state->steps;
|
||||||
p->step_limit[i] = limit;
|
p->step_limit[i] = accepted_limit;
|
||||||
|
p->integration_start_time[i] = state->integration_start_time;
|
||||||
|
p->next_step[i] = state->next_step;
|
||||||
|
p->rejected_steps[i] = state->rejected_steps;
|
||||||
|
p->rhs_evaluations[i] = state->rhs_evaluations;
|
||||||
|
p->previous_rejected[i] = state->previous_rejected;
|
||||||
|
p->lookback_limit[i] = lookback_limit;
|
||||||
p->continuation[i] = 1;
|
p->continuation[i] = 1;
|
||||||
p->frame_id[i] = frame_id;
|
p->frame_id[i] = frame_id;
|
||||||
p->vertex_id[i] = vertex_id;
|
p->vertex_id[i] = vertex_id;
|
||||||
@@ -88,16 +106,34 @@ int ray_pool_append_continuation(RayPool *p, size_t frame_id,
|
|||||||
.outcome = RAY_OUTCOME_INCOMPLETE,
|
.outcome = RAY_OUTCOME_INCOMPLETE,
|
||||||
.reason = RAY_REASON_NONE,
|
.reason = RAY_REASON_NONE,
|
||||||
.stop_coordinate_time = NAN,
|
.stop_coordinate_time = NAN,
|
||||||
.accepted_steps = steps,
|
.accepted_steps = state->steps,
|
||||||
|
.accepted_step_limit = accepted_limit,
|
||||||
.final_x = {NAN, NAN, NAN},
|
.final_x = {NAN, NAN, NAN},
|
||||||
.final_Pi = {NAN, NAN, NAN},
|
.final_Pi = {NAN, NAN, NAN},
|
||||||
.final_log_alpha_p0 = NAN,
|
.final_log_alpha_p0 = NAN,
|
||||||
.final_log_alpha_p0_0 = log_alpha_p0_0,
|
.final_log_alpha_p0_0 = state->log_alpha_p0_0,
|
||||||
.threshold_value = NAN};
|
.threshold_value = NAN};
|
||||||
++p->count;
|
++p->count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ray_pool_append_continuation(RayPool *p, size_t frame_id,
|
||||||
|
size_t vertex_id, double t, const double x[3],
|
||||||
|
const double Pi[3], double log_alpha_p0,
|
||||||
|
double log_alpha_p0_0, unsigned int steps,
|
||||||
|
unsigned int limit) {
|
||||||
|
if (x == NULL || Pi == NULL)
|
||||||
|
return -1;
|
||||||
|
const GeodesicRayState state = {.coordinate_time = t,
|
||||||
|
.x = {x[0], x[1], x[2]},
|
||||||
|
.Pi = {Pi[0], Pi[1], Pi[2]},
|
||||||
|
.log_alpha_p0 = log_alpha_p0,
|
||||||
|
.log_alpha_p0_0 = log_alpha_p0_0,
|
||||||
|
.steps = steps};
|
||||||
|
return ray_pool_append_continuation_state(p, frame_id, vertex_id, &state,
|
||||||
|
limit, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
void ray_pool_preroute(RayPool *p, const SpacetimeSource *source) {
|
void ray_pool_preroute(RayPool *p, const SpacetimeSource *source) {
|
||||||
if (p == NULL || source == NULL)
|
if (p == NULL || source == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -151,6 +187,14 @@ void ray_pool_preroute(RayPool *p, const SpacetimeSource *source) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
p->activate_t[i] = route.activate_t;
|
p->activate_t[i] = route.activate_t;
|
||||||
|
/* The adaptive window starts at the resolved activation/entry state; the
|
||||||
|
* first trial step and all cost counters are freshly initialized. An
|
||||||
|
* integration start time of zero is a legal coordinate time. */
|
||||||
|
p->integration_start_time[i] = route.activate_t;
|
||||||
|
p->next_step[i] = 0.0;
|
||||||
|
p->rejected_steps[i] = 0;
|
||||||
|
p->rhs_evaluations[i] = 0;
|
||||||
|
p->previous_rejected[i] = 0;
|
||||||
p->x0[i] = route.x[0];
|
p->x0[i] = route.x[0];
|
||||||
p->x1[i] = route.x[1];
|
p->x1[i] = route.x[1];
|
||||||
p->x2[i] = route.x[2];
|
p->x2[i] = route.x[2];
|
||||||
@@ -169,7 +213,10 @@ void ray_pool_activate_in_time_range(RayPool *p, const MetricSlab *slab) {
|
|||||||
p->activate_t[i] <= slab->t_lo)
|
p->activate_t[i] <= slab->t_lo)
|
||||||
continue;
|
continue;
|
||||||
p->t[i] = p->activate_t[i];
|
p->t[i] = p->activate_t[i];
|
||||||
/* Continuation rays keep the accepted-step count they already consumed. */
|
/* Continuation rays keep the accepted-step count they already consumed.
|
||||||
|
* Activation never resets adaptive control state; for a new ray it was
|
||||||
|
* already seeded by preroute, for a continuation it comes from the
|
||||||
|
* installed resume state. */
|
||||||
if (!p->continuation[i])
|
if (!p->continuation[i])
|
||||||
p->steps[i] = 0;
|
p->steps[i] = 0;
|
||||||
p->status[i] = RAY_POOL_ACTIVE;
|
p->status[i] = RAY_POOL_ACTIVE;
|
||||||
@@ -191,10 +238,17 @@ void ray_pool_advance_active(RayPool *p, const MetricSlab *slab,
|
|||||||
.Pi = {p->p0[i], p->p1[i], p->p2[i]},
|
.Pi = {p->p0[i], p->p1[i], p->p2[i]},
|
||||||
.log_alpha_p0 = p->log_alpha_p0[i],
|
.log_alpha_p0 = p->log_alpha_p0[i],
|
||||||
.log_alpha_p0_0 = p->log_alpha_p0_0[i],
|
.log_alpha_p0_0 = p->log_alpha_p0_0[i],
|
||||||
.steps = p->steps[i]};
|
.steps = p->steps[i],
|
||||||
|
.integration_start_time = p->integration_start_time[i],
|
||||||
|
.next_step = p->next_step[i],
|
||||||
|
.rejected_steps = p->rejected_steps[i],
|
||||||
|
.rhs_evaluations = p->rhs_evaluations[i],
|
||||||
|
.previous_rejected = p->previous_rejected[i]};
|
||||||
GeodesicTraceConfig per_ray = *config;
|
GeodesicTraceConfig per_ray = *config;
|
||||||
if (p->step_limit[i] != 0)
|
if (p->step_limit[i] != 0)
|
||||||
per_ray.max_steps = p->step_limit[i];
|
per_ray.max_steps = p->step_limit[i];
|
||||||
|
if (p->lookback_limit[i] != 0.0)
|
||||||
|
per_ray.max_lookback_time = p->lookback_limit[i];
|
||||||
const GeodesicAdvanceResult result =
|
const GeodesicAdvanceResult result =
|
||||||
geodesic_advance_past_ray(slab, &s, slab->t_lo, &per_ray, &p->endpoint[i]);
|
geodesic_advance_past_ray(slab, &s, slab->t_lo, &per_ray, &p->endpoint[i]);
|
||||||
p->t[i] = s.coordinate_time;
|
p->t[i] = s.coordinate_time;
|
||||||
@@ -202,6 +256,11 @@ void ray_pool_advance_active(RayPool *p, const MetricSlab *slab,
|
|||||||
p->p0[i] = s.Pi[0]; p->p1[i] = s.Pi[1]; p->p2[i] = s.Pi[2];
|
p->p0[i] = s.Pi[0]; p->p1[i] = s.Pi[1]; p->p2[i] = s.Pi[2];
|
||||||
p->log_alpha_p0[i] = s.log_alpha_p0;
|
p->log_alpha_p0[i] = s.log_alpha_p0;
|
||||||
p->steps[i] = s.steps;
|
p->steps[i] = s.steps;
|
||||||
|
p->integration_start_time[i] = s.integration_start_time;
|
||||||
|
p->next_step[i] = s.next_step;
|
||||||
|
p->rejected_steps[i] = s.rejected_steps;
|
||||||
|
p->rhs_evaluations[i] = s.rhs_evaluations;
|
||||||
|
p->previous_rejected[i] = s.previous_rejected;
|
||||||
if (result == GEODESIC_ADVANCE_TERMINATED)
|
if (result == GEODESIC_ADVANCE_TERMINATED)
|
||||||
p->status[i] = p->endpoint[i].outcome == RAY_OUTCOME_UNRESOLVED
|
p->status[i] = p->endpoint[i].outcome == RAY_OUTCOME_UNRESOLVED
|
||||||
? RAY_POOL_UNRESOLVED
|
? RAY_POOL_UNRESOLVED
|
||||||
@@ -228,6 +287,9 @@ void ray_pool_destroy(RayPool *p) {
|
|||||||
free(p->p0); free(p->p1); free(p->p2); free(p->log_alpha_p0);
|
free(p->p0); free(p->p1); free(p->p2); free(p->log_alpha_p0);
|
||||||
free(p->log_alpha_p0_0);
|
free(p->log_alpha_p0_0);
|
||||||
free(p->activate_t); free(p->steps); free(p->step_limit);
|
free(p->activate_t); free(p->steps); free(p->step_limit);
|
||||||
|
free(p->integration_start_time); free(p->next_step);
|
||||||
|
free(p->rejected_steps); free(p->rhs_evaluations);
|
||||||
|
free(p->previous_rejected); free(p->lookback_limit);
|
||||||
free(p->continuation); free(p->frame_id); free(p->vertex_id);
|
free(p->continuation); free(p->frame_id); free(p->vertex_id);
|
||||||
free(p->status);
|
free(p->status);
|
||||||
free(p->endpoint);
|
free(p->endpoint);
|
||||||
|
|||||||
@@ -25,6 +25,20 @@ typedef struct {
|
|||||||
unsigned int *steps;
|
unsigned int *steps;
|
||||||
/* Per-ray total accepted-step limit; zero means use the trace config. */
|
/* Per-ray total accepted-step limit; zero means use the trace config. */
|
||||||
unsigned int *step_limit;
|
unsigned int *step_limit;
|
||||||
|
/* Adaptive (DP54) per-ray control state, copied verbatim from the resume
|
||||||
|
* state and never reset by activation. All fields are ignored by the legacy
|
||||||
|
* RK4 path. `integration_start_time` is the activation/entry time of the
|
||||||
|
* adaptive window (not the camera energy reference), `next_step` is a
|
||||||
|
* positive trial-step magnitude (zero means "derive from the config"),
|
||||||
|
* `rejected_steps`/`rhs_evaluations` are cumulative cost and
|
||||||
|
* `previous_rejected` flags a rejected last trial. */
|
||||||
|
double *integration_start_time;
|
||||||
|
double *next_step;
|
||||||
|
unsigned int *rejected_steps;
|
||||||
|
unsigned long *rhs_evaluations;
|
||||||
|
unsigned int *previous_rejected;
|
||||||
|
/* Per-ray total lookback time budget; zero means use the trace config. */
|
||||||
|
double *lookback_limit;
|
||||||
/* Nonzero for a retry that resumes from a saved state instead of from the
|
/* Nonzero for a retry that resumes from a saved state instead of from the
|
||||||
* camera; such rays are not pre-routed. */
|
* camera; such rays are not pre-routed. */
|
||||||
uint8_t *continuation;
|
uint8_t *continuation;
|
||||||
@@ -39,7 +53,19 @@ int ray_pool_append(RayPool *pool, const ObserverState *observer,
|
|||||||
const double direction[3],
|
const double direction[3],
|
||||||
size_t frame_id, size_t vertex_id);
|
size_t frame_id, size_t vertex_id);
|
||||||
/* Append a retry that resumes an UNRESOLVED ray from its last accepted state.
|
/* Append a retry that resumes an UNRESOLVED ray from its last accepted state.
|
||||||
* `limit` is the new total accepted-step budget for this ray. */
|
* Every continuous and adaptive control field of `state` is copied so the
|
||||||
|
* resumed ray never replays from the camera, resets L0, or forgets its
|
||||||
|
* accumulated rejection/RHS counters. `accepted_limit` is the new total
|
||||||
|
* accepted-step budget; `lookback_limit` is the new total coordinate-time
|
||||||
|
* lookback budget (zero means use the trace config). Neither quota is part of
|
||||||
|
* the continuous state. */
|
||||||
|
int ray_pool_append_continuation_state(RayPool *pool, size_t frame_id,
|
||||||
|
size_t vertex_id,
|
||||||
|
const GeodesicRayState *state,
|
||||||
|
unsigned int accepted_limit,
|
||||||
|
double lookback_limit);
|
||||||
|
/* Legacy scattered-field wrapper around the state interface above. It builds
|
||||||
|
* an RK4-compatible state (zero adaptive control) and a zero lookback quota. */
|
||||||
int ray_pool_append_continuation(RayPool *pool, size_t frame_id,
|
int ray_pool_append_continuation(RayPool *pool, size_t frame_id,
|
||||||
size_t vertex_id, double t, const double x[3],
|
size_t vertex_id, double t, const double x[3],
|
||||||
const double Pi[3], double log_alpha_p0,
|
const double Pi[3], double log_alpha_p0,
|
||||||
|
|||||||
@@ -0,0 +1,545 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Exercise the production DP54 default, v3 lens-map provenance/replay and the
|
||||||
|
adaptive retry/budget policy from the CLI.
|
||||||
|
|
||||||
|
The production default is now adaptive Dormand-Prince 5(4). These checks
|
||||||
|
require that a run without --integrator exports wire code 1 and is physically
|
||||||
|
and bit-for-bit equal to an explicit --integrator dp54 run, so `make test`
|
||||||
|
truly covers the production default rather than only the explicit path.
|
||||||
|
--integrator rk4 stays available for the legacy wire code and for a
|
||||||
|
fixed-step reference convergence check. Small CPU 16x8/32x16 scenes keep the
|
||||||
|
runtime short; physical comparisons use stored lens-map endpoints, not only the
|
||||||
|
rendered PNG.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import struct
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import zlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Keep scratch data inside the pre-approved OpenCode scratch directory instead
|
||||||
|
# of creating directories directly under the system temporary root.
|
||||||
|
TMP_ROOT = Path('/tmp/opencode')
|
||||||
|
TMP_ROOT.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
BUILD = Path(sys.argv[1] if len(sys.argv) > 1 else 'build/Release').resolve()
|
||||||
|
TESTDIR = Path(sys.argv[2]).resolve() if len(sys.argv) > 2 else BUILD
|
||||||
|
ENV = dict(os.environ, OMP_NUM_THREADS='4')
|
||||||
|
|
||||||
|
# v3 wire offsets (see src/lens_map.c). The header is deliberately not part of
|
||||||
|
# the payload CRC.
|
||||||
|
VERSION_OFFSET = 8
|
||||||
|
FRAME_COUNT_OFFSET = 32
|
||||||
|
PROVENANCE_OFFSET = 40
|
||||||
|
PROVENANCE_V3_OFFSET = 100
|
||||||
|
VERTEX_COUNT_OFFSET = 200
|
||||||
|
TRIANGLE_COUNT_OFFSET = 208
|
||||||
|
VERTEX_START = 224
|
||||||
|
VERTEX_SIZE = 108
|
||||||
|
TRIANGLE_SIZE = 32
|
||||||
|
|
||||||
|
ATOL_FIELDS = ('atol_x', 'atol_Pi', 'atol_L', 'rtol', 'min_step', 'max_step',
|
||||||
|
'max_lookback_time', 'retry_lookback_increment',
|
||||||
|
'max_total_lookback_time')
|
||||||
|
# Machine-roundoff floor for comparing two adaptive integrations; below this a
|
||||||
|
# difference carries no convergence information.
|
||||||
|
ROUNDOFF_FLOOR = 1e-12
|
||||||
|
ENDPOINT_ASSERT = 1e-6
|
||||||
|
|
||||||
|
|
||||||
|
def run(binary, *args, ok=True, env=ENV):
|
||||||
|
result = subprocess.run([str(binary), *map(str, args)], env=env,
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if (result.returncode == 0) != ok:
|
||||||
|
raise AssertionError(
|
||||||
|
f'{binary.name} {args}: rc={result.returncode}\n{result.stderr}')
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def image_payload(path):
|
||||||
|
data = path.read_bytes()
|
||||||
|
assert data[:8] == b'\x89PNG\r\n\x1a\n', f'not a PNG: {path}'
|
||||||
|
offset, compressed = 8, bytearray()
|
||||||
|
while offset < len(data):
|
||||||
|
count, kind = struct.unpack_from('>I4s', data, offset)
|
||||||
|
payload = data[offset + 8:offset + 8 + count]
|
||||||
|
if kind == b'IDAT':
|
||||||
|
compressed.extend(payload)
|
||||||
|
offset += count + 12
|
||||||
|
return bytes(zlib.decompress(compressed))
|
||||||
|
|
||||||
|
|
||||||
|
def map_provenance(path):
|
||||||
|
data = path.read_bytes()
|
||||||
|
assert data[:8] == b'GRLENS\x01\x00'
|
||||||
|
version = struct.unpack_from('<I', data, VERSION_OFFSET)[0]
|
||||||
|
frame_count = struct.unpack_from('<Q', data, FRAME_COUNT_OFFSET)[0]
|
||||||
|
base = PROVENANCE_OFFSET
|
||||||
|
prov = {}
|
||||||
|
prov['threshold_kind'], prov['threshold_policy_version'] = struct.unpack_from(
|
||||||
|
'<II', data, base)
|
||||||
|
prov['threshold_value'] = struct.unpack_from('<d', data, base + 8)[0]
|
||||||
|
(prov['retry_step_increment'], prov['max_total_steps'], prov['max_level'],
|
||||||
|
prov['integrator']) = struct.unpack_from('<IIII', data, base + 16)
|
||||||
|
prov['min_edge_pixels'] = struct.unpack_from('<d', data, base + 32)[0]
|
||||||
|
prov['min_area_pixels2'] = struct.unpack_from('<d', data, base + 40)[0]
|
||||||
|
prov['coordinate_time_step'] = struct.unpack_from('<d', data, base + 48)[0]
|
||||||
|
prov['initial_max_steps'] = struct.unpack_from('<I', data, base + 56)[0]
|
||||||
|
if version == 3:
|
||||||
|
off = PROVENANCE_V3_OFFSET
|
||||||
|
for name in ATOL_FIELDS:
|
||||||
|
prov[name] = struct.unpack_from('<d', data, off)[0]
|
||||||
|
off += 8
|
||||||
|
prov['max_consecutive_rejections'] = struct.unpack_from('<I', data, off)[0]
|
||||||
|
return version, frame_count, prov
|
||||||
|
|
||||||
|
|
||||||
|
def map_vertices(path):
|
||||||
|
data = path.read_bytes()
|
||||||
|
version = struct.unpack_from('<I', data, VERSION_OFFSET)[0]
|
||||||
|
assert version == 3, f'expected a v3 map, got v{version}'
|
||||||
|
vertices = struct.unpack_from('<Q', data, VERTEX_COUNT_OFFSET)[0]
|
||||||
|
triangles = struct.unpack_from('<Q', data, TRIANGLE_COUNT_OFFSET)[0]
|
||||||
|
offset = VERTEX_START
|
||||||
|
values = []
|
||||||
|
for _ in range(vertices):
|
||||||
|
values.append(struct.unpack_from('<9dIIIQQQ', data, offset))
|
||||||
|
offset += VERTEX_SIZE
|
||||||
|
return values, data[offset:offset + triangles * TRIANGLE_SIZE]
|
||||||
|
|
||||||
|
|
||||||
|
def endpoint_deviation(a, b):
|
||||||
|
"""(mismatched provenance count, max direction/log-g deviation).
|
||||||
|
|
||||||
|
Vertices whose end_id/outcome/reason differ are counted as mismatches and
|
||||||
|
excluded from the numeric deviation; the caller requires zero mismatches.
|
||||||
|
"""
|
||||||
|
mismatches = 0
|
||||||
|
worst = 0.0
|
||||||
|
assert len(a) == len(b)
|
||||||
|
for x, y in zip(a, b):
|
||||||
|
if x[9:12] != y[9:12]:
|
||||||
|
mismatches += 1
|
||||||
|
continue
|
||||||
|
for k in (3, 4, 5, 6, 7, 8):
|
||||||
|
worst = max(worst, abs(x[k] - y[k]))
|
||||||
|
return mismatches, worst
|
||||||
|
|
||||||
|
|
||||||
|
def trace_cost(stderr, label):
|
||||||
|
match = re.search(label + r' trace cost: accepted=(\d+) rejected=(\d+) '
|
||||||
|
r'rhs=(\d+)', stderr)
|
||||||
|
return None if match is None else match.groups()
|
||||||
|
|
||||||
|
|
||||||
|
def sum_rhs(vertices):
|
||||||
|
return sum(v[14] for v in vertices)
|
||||||
|
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory(prefix='gr-adaptive-cli-',
|
||||||
|
dir=str(TMP_ROOT)) as directory:
|
||||||
|
tmp = Path(directory)
|
||||||
|
for backend in ('minkowski', 'schwarzschild'):
|
||||||
|
binary = BUILD / f'{backend}_sky'
|
||||||
|
if not binary.exists():
|
||||||
|
print(f'{backend}: binary absent, skipping', flush=True)
|
||||||
|
continue
|
||||||
|
help_text = run(binary, '--help').stdout
|
||||||
|
for option in ('--integrator', '--ode-rtol', '--ode-atol-x',
|
||||||
|
'--ode-atol-pi', '--ode-atol-l', '--ode-initial-step',
|
||||||
|
'--ode-min-step', '--ode-max-step',
|
||||||
|
'--ode-max-rejections', '--trace-max-steps',
|
||||||
|
'--trace-lookback-time', '--retry-step-increment',
|
||||||
|
'--max-total-steps', '--retry-lookback-increment',
|
||||||
|
'--max-total-lookback-time'):
|
||||||
|
assert option in help_text, (backend, option)
|
||||||
|
ext = 'png' if '.png' in help_text else 'ppm'
|
||||||
|
hdr_available = '--hdr-output' in help_text
|
||||||
|
hdr_args = ['--hdr-output'] if hdr_available else []
|
||||||
|
common = ['--catalog', 'assets/sky_grid_5deg.csv', '--width', 32,
|
||||||
|
'--height', 16, '--fov-deg', 80, '--exposure', 1e-3,
|
||||||
|
'--coarse-cell-pixels', 8, '--refine-max-level', 0,
|
||||||
|
'--psf-relative-tail', 1e-4]
|
||||||
|
|
||||||
|
def single(name, *options, ok=True, env=ENV, use_common=common):
|
||||||
|
out = tmp / f'{backend}_{name}.{ext}'
|
||||||
|
result = run(binary, *use_common, '--output', out, *options,
|
||||||
|
ok=ok, env=env)
|
||||||
|
return out, result
|
||||||
|
|
||||||
|
# 1) The production default (no --integrator) must be DP54 and must
|
||||||
|
# match an explicit --integrator dp54 run physically and in its
|
||||||
|
# PNG/HDR output.
|
||||||
|
dflt_map = tmp / f'{backend}_dflt.grlens'
|
||||||
|
dflt_out, dflt_run = single('dflt', *hdr_args, '--verbose',
|
||||||
|
'--lens-map-output', dflt_map)
|
||||||
|
version, frame_count, dflt_prov = map_provenance(dflt_map)
|
||||||
|
assert version == 3 and frame_count == 1
|
||||||
|
assert dflt_prov['integrator'] == 1, dflt_prov
|
||||||
|
assert dflt_prov['min_step'] == 1e-12, dflt_prov
|
||||||
|
assert dflt_prov['max_step'] == {'minkowski': 16.0,
|
||||||
|
'schwarzschild': 8.0}[backend], dflt_prov
|
||||||
|
assert dflt_prov['min_step'] <= dflt_prov['coordinate_time_step'] \
|
||||||
|
<= dflt_prov['max_step']
|
||||||
|
assert dflt_prov['atol_x'] > 0 and dflt_prov['rtol'] > 0
|
||||||
|
assert dflt_prov['max_lookback_time'] > 0
|
||||||
|
assert dflt_prov['max_consecutive_rejections'] > 0
|
||||||
|
expl_map = tmp / f'{backend}_expl.grlens'
|
||||||
|
expl_out, _ = single('expl', *hdr_args, '--integrator', 'dp54',
|
||||||
|
'--lens-map-output', expl_map)
|
||||||
|
assert dflt_map.read_bytes() == expl_map.read_bytes(), \
|
||||||
|
'default map differs from explicit dp54'
|
||||||
|
assert image_payload(dflt_out) == image_payload(expl_out)
|
||||||
|
if hdr_available:
|
||||||
|
dflt_hdr = dflt_out.with_name(dflt_out.stem + '_HDR.fits')
|
||||||
|
expl_hdr = expl_out.with_name(expl_out.stem + '_HDR.fits')
|
||||||
|
assert dflt_hdr.read_bytes() == expl_hdr.read_bytes()
|
||||||
|
dflt_vertices, _ = map_vertices(dflt_map)
|
||||||
|
|
||||||
|
# 2) The legacy RK4 wire code must be 0 and its cost counters must be
|
||||||
|
# real (nonzero RHS evaluations), not legacy zeros.
|
||||||
|
rk4_map = tmp / f'{backend}_rk4.grlens'
|
||||||
|
single('rk4', '--integrator', 'rk4', '--lens-map-output', rk4_map)
|
||||||
|
_, _, rk4_prov = map_provenance(rk4_map)
|
||||||
|
assert rk4_prov['integrator'] == 0, rk4_prov
|
||||||
|
rk4_vertices, _ = map_vertices(rk4_map)
|
||||||
|
assert sum_rhs(rk4_vertices) > 0, 'RK4 RHS cost counters are not real'
|
||||||
|
|
||||||
|
# 3) Same-camera tolerance convergence with three levels. Outcome,
|
||||||
|
# reason and end must not change between levels, and the deviation
|
||||||
|
# from the tightest reference must shrink as the tolerance tightens.
|
||||||
|
# These are local ODE tolerances, not a global sky-error bound.
|
||||||
|
tol_maps = {}
|
||||||
|
for tol in ('1e-7', '1e-9', '1e-12'):
|
||||||
|
m = tmp / f'{backend}_tol_{tol}.grlens'
|
||||||
|
single(f'tol_{tol}', '--integrator', 'dp54', '--ode-rtol', tol,
|
||||||
|
'--ode-atol-x', tol, '--ode-atol-pi', tol,
|
||||||
|
'--ode-atol-l', tol, '--lens-map-output', m)
|
||||||
|
tol_maps[tol] = map_vertices(m)[0]
|
||||||
|
mism7, err7 = endpoint_deviation(tol_maps['1e-7'], tol_maps['1e-12'])
|
||||||
|
mism9, err9 = endpoint_deviation(tol_maps['1e-9'], tol_maps['1e-12'])
|
||||||
|
assert mism7 == 0 and mism9 == 0, \
|
||||||
|
f'{backend}: tolerance levels disagree on outcome/end'
|
||||||
|
assert err9 < ENDPOINT_ASSERT, (backend, 'default vs tight', err9)
|
||||||
|
assert err7 + ROUNDOFF_FLOOR >= err9, \
|
||||||
|
f'{backend}: tightening tolerance did not reduce error ' \
|
||||||
|
f'({err7} -> {err9})'
|
||||||
|
print(f'{backend}: default==dp54, tol errors 1e-7={err7:.3g} '
|
||||||
|
f'1e-9={err9:.3g}', flush=True)
|
||||||
|
|
||||||
|
# 4) Render-only replay of the default map must be bit-identical and
|
||||||
|
# its stored statistics must equal the live trace cost.
|
||||||
|
replay_out = tmp / f'{backend}_replay.{ext}'
|
||||||
|
replay_run = run(binary, *common, *hdr_args, '--lens-map-input',
|
||||||
|
dflt_map, '--verbose', '--output', replay_out)
|
||||||
|
assert image_payload(replay_out) == image_payload(dflt_out)
|
||||||
|
if hdr_available:
|
||||||
|
replay_hdr = replay_out.with_name(replay_out.stem + '_HDR.fits')
|
||||||
|
assert dflt_out.with_name(dflt_out.stem + '_HDR.fits').read_bytes() \
|
||||||
|
== replay_hdr.read_bytes()
|
||||||
|
live_cost = trace_cost(dflt_run.stderr, 'Frame 0')
|
||||||
|
replay_cost = trace_cost(replay_run.stderr, 'Imported map')
|
||||||
|
assert live_cost is not None and replay_cost is not None
|
||||||
|
assert live_cost == replay_cost, (live_cost, replay_cost)
|
||||||
|
|
||||||
|
# 5) Explicit zeros in the retry policy must survive, not be filled in
|
||||||
|
# by the derived defaults.
|
||||||
|
zero_step_map = tmp / f'{backend}_zero_step.grlens'
|
||||||
|
single('zero_step', '--integrator', 'dp54', '--retry-step-increment',
|
||||||
|
'0', '--lens-map-output', zero_step_map)
|
||||||
|
_, _, zero_step = map_provenance(zero_step_map)
|
||||||
|
assert zero_step['retry_step_increment'] == 0, zero_step
|
||||||
|
assert zero_step['max_total_steps'] > 0, zero_step
|
||||||
|
zero_time_map = tmp / f'{backend}_zero_time.grlens'
|
||||||
|
single('zero_time', '--integrator', 'dp54',
|
||||||
|
'--retry-lookback-increment', '0', '--lens-map-output',
|
||||||
|
zero_time_map)
|
||||||
|
_, _, zero_time = map_provenance(zero_time_map)
|
||||||
|
assert zero_time['retry_lookback_increment'] == 0, zero_time
|
||||||
|
assert zero_time['max_total_lookback_time'] >= \
|
||||||
|
zero_time['max_lookback_time'], zero_time
|
||||||
|
|
||||||
|
# 6) RK4 rejects every DP-only option rather than silently ignoring it.
|
||||||
|
rk4_errors = [
|
||||||
|
(['--integrator', 'rk4', '--ode-rtol', 1e-9], 'applies only'),
|
||||||
|
(['--integrator', 'rk4', '--ode-min-step', 1e-9], 'applies only'),
|
||||||
|
(['--integrator', 'rk4', '--ode-max-step', 1e-3], 'applies only'),
|
||||||
|
(['--integrator', 'rk4', '--ode-max-rejections', 4], 'applies only'),
|
||||||
|
(['--integrator', 'rk4', '--trace-lookback-time', 1], 'applies only'),
|
||||||
|
(['--integrator', 'rk4', '--retry-lookback-increment', 1], 'applies only'),
|
||||||
|
(['--integrator', 'rk4', '--max-total-lookback-time', 2], 'applies only'),
|
||||||
|
]
|
||||||
|
# DP cross-field validation and malformed values fail immediately.
|
||||||
|
invalid = [
|
||||||
|
(['--integrator', 'bogus'], None),
|
||||||
|
(['--integrator'], None),
|
||||||
|
(['--integrator', 'dp54', '--ode-rtol', 0], None),
|
||||||
|
(['--integrator', 'dp54', '--ode-rtol', -1], None),
|
||||||
|
(['--integrator', 'dp54', '--ode-atol-x', 'nan'], None),
|
||||||
|
(['--integrator', 'dp54', '--ode-max-rejections', 0], None),
|
||||||
|
(['--integrator', 'dp54', '--trace-max-steps', 0], None),
|
||||||
|
(['--integrator', 'dp54', '--ode-initial-step', 5,
|
||||||
|
'--ode-max-step', 1], 'min <= initial <= max'),
|
||||||
|
(['--integrator', 'dp54', '--ode-min-step', 4,
|
||||||
|
'--ode-initial-step', 2], 'min <= initial <= max'),
|
||||||
|
(['--integrator', 'dp54', '--trace-lookback-time', 0], None),
|
||||||
|
(['--integrator', 'dp54', '--retry-step-increment', -1], None),
|
||||||
|
]
|
||||||
|
for options, message in rk4_errors + invalid:
|
||||||
|
missing = tmp / 'adaptive_should_not_exist.csv'
|
||||||
|
result = run(binary, '--catalog', missing, *options, ok=False)
|
||||||
|
if message:
|
||||||
|
assert message in result.stderr, (options, result.stderr)
|
||||||
|
assert not missing.exists(), result.stderr
|
||||||
|
|
||||||
|
# 7) Replay must consume the stored policy: explicit tracing options
|
||||||
|
# cannot be layered on top of --lens-map-input.
|
||||||
|
conflict = run(binary, *common, '--lens-map-input', dflt_map,
|
||||||
|
'--integrator', 'rk4', '--output',
|
||||||
|
tmp / 'conflict.png', ok=False)
|
||||||
|
assert 'cannot be combined with --lens-map-input' in conflict.stderr, \
|
||||||
|
conflict.stderr
|
||||||
|
conflict2 = run(binary, *common, '--lens-map-input', dflt_map,
|
||||||
|
'--trace-max-steps', 100, '--output',
|
||||||
|
tmp / 'conflict2.png', ok=False)
|
||||||
|
assert 'cannot be combined with --lens-map-input' in conflict2.stderr, \
|
||||||
|
conflict2.stderr
|
||||||
|
conflict3 = run(binary, *common, '--lens-map-input', dflt_map,
|
||||||
|
'--integrator', 'dp54', '--ode-rtol', 1e-9,
|
||||||
|
'--output', tmp / 'conflict3.png', ok=False)
|
||||||
|
assert 'cannot be combined with --lens-map-input' in conflict3.stderr, \
|
||||||
|
conflict3.stderr
|
||||||
|
|
||||||
|
# 8) Single vs movie: the same physical observer event must agree, and
|
||||||
|
# threads/slabs must not change the stored adaptive endpoints.
|
||||||
|
track = tmp / f'{backend}.csv'
|
||||||
|
observer_test = TESTDIR / f'test_observer_{backend}'
|
||||||
|
if observer_test.exists():
|
||||||
|
run(observer_test, track)
|
||||||
|
moving_single = tmp / f'{backend}_moving.grlens'
|
||||||
|
single('moving', '--observer-position', 3, -4, 5,
|
||||||
|
'--observer-velocity', 0.2, -0.1, 0.3,
|
||||||
|
'--look-ra-deg', 37, '--look-dec-deg', -23,
|
||||||
|
'--camera-roll-deg', 19, '--lens-map-output', moving_single)
|
||||||
|
movie_map = tmp / f'{backend}_movie.grlens'
|
||||||
|
run(binary, *common, '--observer-track', track, '--frames-dir', tmp,
|
||||||
|
'--frames-prefix', f'{backend}_movie', '--duration', 0,
|
||||||
|
'--fps', 1, '--lens-map-output', movie_map)
|
||||||
|
single_v, _ = map_vertices(moving_single)
|
||||||
|
movie_v, _ = map_vertices(movie_map)
|
||||||
|
mism, dev = endpoint_deviation(single_v, movie_v)
|
||||||
|
assert mism == 0 and dev < ENDPOINT_ASSERT, (mism, dev)
|
||||||
|
|
||||||
|
thread_maps = []
|
||||||
|
for threads in (1, 2, 4):
|
||||||
|
m = tmp / f'{backend}_movie_{threads}thr.grlens'
|
||||||
|
run(binary, *common, '--observer-track', track, '--frames-dir',
|
||||||
|
tmp, '--frames-prefix', f'{backend}_m{threads}',
|
||||||
|
'--duration', 0, '--fps', 1, '--lens-map-output', m,
|
||||||
|
env=dict(ENV, OMP_NUM_THREADS=str(threads)))
|
||||||
|
thread_maps.append(m)
|
||||||
|
reference = thread_maps[0].read_bytes()
|
||||||
|
for m in thread_maps[1:]:
|
||||||
|
assert m.read_bytes() == reference, \
|
||||||
|
f'{backend}: DP movie map changed across threads'
|
||||||
|
|
||||||
|
slab_maps = []
|
||||||
|
for slab in (2, 8, 64):
|
||||||
|
m = tmp / f'{backend}_slab_{slab}.grlens'
|
||||||
|
run(binary, *common, '--observer-track', track, '--frames-dir',
|
||||||
|
tmp, '--frames-prefix', f'{backend}_s{slab}',
|
||||||
|
'--slab-duration', slab, '--duration', 0, '--fps', 1,
|
||||||
|
'--lens-map-output', m)
|
||||||
|
slab_maps.append(m)
|
||||||
|
base_v, _ = map_vertices(slab_maps[0])
|
||||||
|
for m in slab_maps[1:]:
|
||||||
|
other_v, _ = map_vertices(m)
|
||||||
|
mism, dev = endpoint_deviation(base_v, other_v)
|
||||||
|
assert mism == 0 and dev < ENDPOINT_ASSERT, (mism, dev)
|
||||||
|
print(f'{backend}: DP movie threads/slabs agree', flush=True)
|
||||||
|
|
||||||
|
# 9) Budget: a tiny initial coordinate-time budget leaves UNRESOLVED
|
||||||
|
# rays; with no room to grow the publication gate refuses the frame,
|
||||||
|
# while retry increments that can grow resolve it.
|
||||||
|
if backend == 'schwarzschild':
|
||||||
|
refused = tmp / f'{backend}_refused.{ext}'
|
||||||
|
small = ['--integrator', 'dp54', '--trace-lookback-time', 1e-6,
|
||||||
|
'--retry-lookback-increment', 0,
|
||||||
|
'--max-total-lookback-time', 1e-6]
|
||||||
|
result = run(binary, *common, '--output', refused, *small, ok=False)
|
||||||
|
assert 'Incomplete render refused' in result.stderr, result.stderr
|
||||||
|
assert not refused.exists()
|
||||||
|
allow = tmp / f'{backend}_allow.{ext}'
|
||||||
|
run(binary, *common, '--output', allow, '--allow-incomplete', *small)
|
||||||
|
assert allow.exists()
|
||||||
|
|
||||||
|
direct = tmp / f'{backend}_direct.{ext}'
|
||||||
|
direct_result = subprocess.run(
|
||||||
|
[str(binary), *map(str, common), '--output', str(direct),
|
||||||
|
'--integrator', 'dp54', '--trace-lookback-time', '4000'],
|
||||||
|
env=ENV, capture_output=True, text=True)
|
||||||
|
if direct_result.returncode == 0:
|
||||||
|
retried = tmp / f'{backend}_retried.{ext}'
|
||||||
|
run(binary, *common, '--output', retried, '--integrator', 'dp54',
|
||||||
|
'--trace-lookback-time', 1e-6,
|
||||||
|
'--retry-lookback-increment', 25,
|
||||||
|
'--max-total-lookback-time', 4000)
|
||||||
|
assert image_payload(retried)
|
||||||
|
print('schwarzschild: retry budget resolves previously '
|
||||||
|
'unresolved rays', flush=True)
|
||||||
|
else:
|
||||||
|
print('schwarzschild: direct budget scene still unresolved; '
|
||||||
|
'retry-resolution case skipped', flush=True)
|
||||||
|
|
||||||
|
# 10) Fixed-step reference convergence on a small scene. The
|
||||||
|
# accepted budget is explicit and large so the finer step does
|
||||||
|
# not silently shorten the traced history. Both fixed-step
|
||||||
|
# levels and the DP54 default must agree below ENDPOINT_ASSERT.
|
||||||
|
# If the reference itself does not converge this must FAIL and
|
||||||
|
# be reported, never loosened into a false zero.
|
||||||
|
ref_common = ['--catalog', 'assets/sky_grid_5deg.csv', '--width',
|
||||||
|
16, '--height', 8, '--fov-deg', 80, '--exposure',
|
||||||
|
1e-3, '--coarse-cell-pixels', 8, '--refine-max-level',
|
||||||
|
0, '--psf-relative-tail', 1e-4]
|
||||||
|
|
||||||
|
def ref_map(tag, *options):
|
||||||
|
m = tmp / f'{backend}_ref_{tag}.grlens'
|
||||||
|
run(binary, *ref_common, '--output',
|
||||||
|
tmp / f'{backend}_ref_{tag}.{ext}', '--lens-map-output', m,
|
||||||
|
*options)
|
||||||
|
return map_vertices(m)[0]
|
||||||
|
|
||||||
|
rk4_04 = ref_map('rk4_04', '--integrator', 'rk4',
|
||||||
|
'--ode-initial-step', 0.04, '--trace-max-steps',
|
||||||
|
'262144')
|
||||||
|
rk4_02 = ref_map('rk4_02', '--integrator', 'rk4',
|
||||||
|
'--ode-initial-step', 0.02, '--trace-max-steps',
|
||||||
|
'262144')
|
||||||
|
dp_tight = ref_map('dp_tight', '--ode-rtol', '1e-12',
|
||||||
|
'--ode-atol-x', '1e-12', '--ode-atol-pi',
|
||||||
|
'1e-12', '--ode-atol-l', '1e-12')
|
||||||
|
assert sum(1 for v in rk4_02 if v[10] == 0) > 0, \
|
||||||
|
'reference scene has no escaped ray'
|
||||||
|
mism, ref_dev = endpoint_deviation(rk4_04, rk4_02)
|
||||||
|
assert mism == 0, 'RK4 reference levels disagree on outcome/end'
|
||||||
|
assert ref_dev < ENDPOINT_ASSERT, \
|
||||||
|
f'RK4 reference not converged: {ref_dev}; report to parent'
|
||||||
|
mism, dp_dev = endpoint_deviation(dp_tight, rk4_02)
|
||||||
|
assert mism == 0, 'DP54 default disagrees with RK4 reference'
|
||||||
|
assert dp_dev < ENDPOINT_ASSERT, (dp_dev,)
|
||||||
|
print(f'schwarzschild: RK4 ref convergence {ref_dev:.3g}, '
|
||||||
|
f'DP default vs fine RK4 {dp_dev:.3g}', flush=True)
|
||||||
|
|
||||||
|
print(f'{backend}: adaptive CLI checks passed', flush=True)
|
||||||
|
|
||||||
|
# Alcubierre production-default smoke: the DP54 default policy must
|
||||||
|
# validate and the migrated lookback budget must actually cover the warp
|
||||||
|
# bubble feature (rays integrate and escape) instead of pre-routing all
|
||||||
|
# misses. No movie/thread sweep for this third backend.
|
||||||
|
alc = BUILD / 'alcubierre_sky'
|
||||||
|
if not alc.exists():
|
||||||
|
print('alcubierre: binary absent, skipping', flush=True)
|
||||||
|
else:
|
||||||
|
alc_help = run(alc, '--help').stdout
|
||||||
|
ext = 'png' if '.png' in alc_help else 'ppm'
|
||||||
|
alc_map = tmp / 'alcubierre_default.grlens'
|
||||||
|
alc_out = tmp / f'alcubierre_default.{ext}'
|
||||||
|
run(alc, '--alcubierre-vs', 0.3, '--alcubierre-radius', 1,
|
||||||
|
'--alcubierre-sigma', 1, '--catalog', 'assets/sky_grid_5deg.csv',
|
||||||
|
'--width', 16, '--height', 8, '--fov-deg', 80, '--exposure', 1e-3,
|
||||||
|
'--coarse-cell-pixels', 8, '--refine-max-level', 0,
|
||||||
|
'--psf-relative-tail', 1e-4, '--verbose', '--output', alc_out,
|
||||||
|
'--lens-map-output', alc_map)
|
||||||
|
_, _, alc_prov = map_provenance(alc_map)
|
||||||
|
assert alc_prov['integrator'] == 1, alc_prov
|
||||||
|
assert alc_prov['min_step'] <= alc_prov['coordinate_time_step'] \
|
||||||
|
<= alc_prov['max_step']
|
||||||
|
assert alc_prov['max_lookback_time'] > 0
|
||||||
|
alc_vertices, _ = map_vertices(alc_map)
|
||||||
|
outcomes = {v[10] for v in alc_vertices}
|
||||||
|
assert 3 not in outcomes, f'Alcubierre default left INCOMPLETE rays'
|
||||||
|
assert any(v[10] == 0 for v in alc_vertices), \
|
||||||
|
'Alcubierre default produced no escaped ray'
|
||||||
|
assert sum_rhs(alc_vertices) > 0, \
|
||||||
|
'Alcubierre default pre-routed every ray; lookback misses feature'
|
||||||
|
assert image_payload(alc_out)
|
||||||
|
|
||||||
|
# The migrated coordinate-time coverage is the physical geometry budget
|
||||||
|
# margin*4*escape/(1-|v_s|) with escape = R + 20/sigma, and it is
|
||||||
|
# independent of the accepted-step count and of the chosen initial
|
||||||
|
# step. Two cheap maps with different resource overrides must keep the
|
||||||
|
# same lookback.
|
||||||
|
alc_escape = 1.0 + 20.0 / 1.0 # R + 20/sigma for R=sigma=1
|
||||||
|
alc_sep = 1.0 - abs(0.3)
|
||||||
|
alc_expected_lookback = 1.25 * 4.0 * alc_escape / alc_sep
|
||||||
|
assert abs(alc_prov['max_lookback_time'] - alc_expected_lookback) \
|
||||||
|
< 1e-12, alc_prov['max_lookback_time']
|
||||||
|
|
||||||
|
def alc_map_with(tag, *options):
|
||||||
|
m = tmp / f'alcubierre_{tag}.grlens'
|
||||||
|
run(alc, '--alcubierre-vs', 0.3, '--alcubierre-radius', 1,
|
||||||
|
'--alcubierre-sigma', 1, '--catalog', 'assets/sky_grid_5deg.csv',
|
||||||
|
'--width', 16, '--height', 8, '--fov-deg', 80, '--exposure',
|
||||||
|
1e-3, '--coarse-cell-pixels', 8, '--refine-max-level', 0,
|
||||||
|
'--psf-relative-tail', 1e-4, '--allow-incomplete',
|
||||||
|
'--output', tmp / f'alcubierre_{tag}.{ext}',
|
||||||
|
'--lens-map-output', m, *options)
|
||||||
|
return map_provenance(m)[2]
|
||||||
|
|
||||||
|
steps_override = alc_map_with('steps_override', '--trace-max-steps', 8)
|
||||||
|
assert steps_override['initial_max_steps'] == 8
|
||||||
|
assert abs(steps_override['max_lookback_time'] - alc_expected_lookback) \
|
||||||
|
< 1e-12, steps_override
|
||||||
|
step_override = alc_map_with('step_override', '--ode-initial-step', 0.02)
|
||||||
|
assert abs(step_override['coordinate_time_step'] - 0.02) < 1e-15
|
||||||
|
assert abs(step_override['max_lookback_time'] - alc_expected_lookback) \
|
||||||
|
< 1e-12, step_override
|
||||||
|
|
||||||
|
# Extreme separation (v_s = 0.99999999) where the legacy fixed-step
|
||||||
|
# estimate far exceeds the cap. The DP path must accept an explicit
|
||||||
|
# tiny coordinate-time budget instead of being rejected at startup by
|
||||||
|
# the fixed-step guard, and it must actually exercise the quota path
|
||||||
|
# (UNRESOLVED rays or real RHS work), not pre-route everything to
|
||||||
|
# escapes. --allow-incomplete publishes the diagnostic frame.
|
||||||
|
extreme = ['--alcubierre-vs', 0.99999999, '--alcubierre-radius', 1,
|
||||||
|
'--alcubierre-sigma', 1, '--catalog',
|
||||||
|
'assets/sky_grid_5deg.csv', '--width', 8, '--height', 4,
|
||||||
|
'--fov-deg', 80, '--exposure', 1e-3,
|
||||||
|
'--coarse-cell-pixels', 4, '--refine-max-level', 0,
|
||||||
|
'--psf-relative-tail', 1e-4,
|
||||||
|
'--observer-position', 0, 0, 0,
|
||||||
|
'--observer-velocity', 0.99999999, 0, 0,
|
||||||
|
'--look-ra-deg', 0, '--look-dec-deg', 0]
|
||||||
|
ext_map = tmp / 'alcubierre_extreme.grlens'
|
||||||
|
run(alc, *extreme, '--integrator', 'dp54',
|
||||||
|
'--trace-lookback-time', 1, '--trace-max-steps', 4,
|
||||||
|
'--max-total-steps', 4, '--retry-step-increment', 0,
|
||||||
|
'--max-total-lookback-time', 1, '--retry-lookback-increment', 0,
|
||||||
|
'--allow-incomplete', '--output',
|
||||||
|
tmp / f'alcubierre_extreme.{ext}', '--lens-map-output', ext_map)
|
||||||
|
_, _, ext_prov = map_provenance(ext_map)
|
||||||
|
assert ext_prov['integrator'] == 1
|
||||||
|
assert abs(ext_prov['max_lookback_time'] - 1.0) < 1e-15, ext_prov
|
||||||
|
assert ext_prov['initial_max_steps'] == 4, ext_prov
|
||||||
|
ext_vertices, _ = map_vertices(ext_map)
|
||||||
|
assert any(v[10] == 2 for v in ext_vertices) or \
|
||||||
|
sum_rhs(ext_vertices) > 0, \
|
||||||
|
'extreme Alcubierre case did not exercise the quota path'
|
||||||
|
|
||||||
|
# The same parameters without explicit DP budgets keep the legacy
|
||||||
|
# fixed-step startup guard, which still rejects the estimated domain.
|
||||||
|
rk4_extreme = run(
|
||||||
|
alc, '--integrator', 'rk4', '--alcubierre-vs', 0.99999999,
|
||||||
|
'--alcubierre-radius', 1, '--alcubierre-sigma', 1, '--catalog',
|
||||||
|
'assets/sky_grid_5deg.csv', '--width', 8, '--height', 4,
|
||||||
|
'--fov-deg', 80, '--exposure', 1e-3, '--coarse-cell-pixels', 4,
|
||||||
|
'--refine-max-level', 0, '--psf-relative-tail', 1e-4,
|
||||||
|
'--output', tmp / f'alcubierre_rk4_extreme.{ext}', ok=False)
|
||||||
|
assert rk4_extreme.returncode == 2, rk4_extreme.stderr
|
||||||
|
assert 'cap' in rk4_extreme.stderr, rk4_extreme.stderr
|
||||||
|
|
||||||
|
print('alcubierre: default DP config validated and produced escapes; '
|
||||||
|
'extreme DP quota path ok, RK4 guard still rejects', flush=True)
|
||||||
+52
-38
@@ -307,10 +307,11 @@ static void test_boundary_semantics_minkowski(void) {
|
|||||||
spacetime_destroy(&source);
|
spacetime_destroy(&source);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_boundary_semantics_generic(void) {
|
static void test_nonconstant_route_unsupported(void) {
|
||||||
/* velocity_constant == 0 forces the generic bracketed driver. A finite
|
/* velocity_constant == 0 signals an arbitrary accelerated worldtube. The
|
||||||
* history bounds the outward/tangent searches, which must not be reported
|
* camera-inside containment test still runs first; once the ray starts
|
||||||
* as entries (they end as TIME_RANGE_EXHAUSTED instead). */
|
* outside, the non-constant route is refused explicitly instead of being
|
||||||
|
* searched with a coarse bracket. */
|
||||||
SyntheticContext context = {.radius = 10.0,
|
SyntheticContext context = {.radius = 10.0,
|
||||||
.valid_t_min = -100.0,
|
.valid_t_min = -100.0,
|
||||||
.constant = 0};
|
.constant = 0};
|
||||||
@@ -321,15 +322,15 @@ static void test_boundary_semantics_generic(void) {
|
|||||||
&source, &on_boundary, (double[]){-1.0, 0.0, 0.0}, &route);
|
&source, &on_boundary, (double[]){-1.0, 0.0, 0.0}, &route);
|
||||||
CHECK(inward == ASYMPTOTIC_OK &&
|
CHECK(inward == ASYMPTOTIC_OK &&
|
||||||
route.kind == ASYMPTOTIC_ROUTE_INSIDE,
|
route.kind == ASYMPTOTIC_ROUTE_INSIDE,
|
||||||
"generic on-boundary inward is inside");
|
"nonconstant on-boundary inward is still inside");
|
||||||
const AsymptoticStatus outward = asymptotic_route_camera(
|
const AsymptoticStatus outward = asymptotic_route_camera(
|
||||||
&source, &on_boundary, (double[]){1.0, 0.0, 0.0}, &route);
|
&source, &on_boundary, (double[]){1.0, 0.0, 0.0}, &route);
|
||||||
CHECK(outward == ASYMPTOTIC_TIME_RANGE_EXHAUSTED,
|
CHECK(outward == ASYMPTOTIC_UNSUPPORTED,
|
||||||
"generic on-boundary outward is not an entry");
|
"nonconstant on-boundary outward is unsupported");
|
||||||
const AsymptoticStatus tangent = asymptotic_route_camera(
|
const AsymptoticStatus tangent = asymptotic_route_camera(
|
||||||
&source, &on_boundary, (double[]){0.0, 1.0, 0.0}, &route);
|
&source, &on_boundary, (double[]){0.0, 1.0, 0.0}, &route);
|
||||||
CHECK(tangent == ASYMPTOTIC_TIME_RANGE_EXHAUSTED,
|
CHECK(tangent == ASYMPTOTIC_UNSUPPORTED,
|
||||||
"generic on-boundary tangent is not an entry");
|
"nonconstant on-boundary tangent is unsupported");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_negative_radius_root_guard(void) {
|
static void test_negative_radius_root_guard(void) {
|
||||||
@@ -525,11 +526,12 @@ static void test_interior_crossing_bisection_failure(void) {
|
|||||||
"interior crossing bisection propagates history exhaustion");
|
"interior crossing bisection propagates history exhaustion");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_generic_bisection_failure(void) {
|
static void test_nonconstant_preroute_unsupported(void) {
|
||||||
/* The isolated invalid window lands on a bisection midpoint while the
|
/* The accelerated fixture is refused explicitly at the route entry; its
|
||||||
* bracket endpoints stay valid, so only the bisection can see it. With the
|
* former coarse bracketed search (and the bisection-midpoint history-hole
|
||||||
* strict F < 0 entry test, the bracket is s = 80 (F == 0) to s = 90
|
* case it exercised) is replaced by the unsupported contract. The history
|
||||||
* (F < 0), so the first midpoint is t = -85. */
|
* reason itself stays covered by the constant and piecewise-constant
|
||||||
|
* worldtube tests below. */
|
||||||
SyntheticContext context = {.radius = 20.0,
|
SyntheticContext context = {.radius = 20.0,
|
||||||
.valid_t_min = -1.0e30,
|
.valid_t_min = -1.0e30,
|
||||||
.constant = 0,
|
.constant = 0,
|
||||||
@@ -538,9 +540,26 @@ static void test_generic_bisection_failure(void) {
|
|||||||
SpacetimeSource source = {.ops = &synthetic_ops, .context = &context};
|
SpacetimeSource source = {.ops = &synthetic_ops, .context = &context};
|
||||||
const ObserverState camera = flat_observer(100.0, 0.0, 0.0);
|
const ObserverState camera = flat_observer(100.0, 0.0, 0.0);
|
||||||
AsymptoticRoute route;
|
AsymptoticRoute route;
|
||||||
|
CHECK(asymptotic_route_camera(&source, &camera, (double[]){-1.0, 0.0, 0.0},
|
||||||
|
&route) == ASYMPTOTIC_UNSUPPORTED,
|
||||||
|
"nonconstant worldtube route is unsupported");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_piecewise_constant_history_hole(void) {
|
||||||
|
/* Piecewise-constant motion stays supported, including its history
|
||||||
|
* contract: when the segment walk steps past the valid history, the route
|
||||||
|
* reports TIME_RANGE_EXHAUSTED and never disguises it as a miss. */
|
||||||
|
SyntheticContext context = {.radius = 10.0,
|
||||||
|
.valid_t_min = -3.0,
|
||||||
|
.constant = 1,
|
||||||
|
.segment_t = -5.0,
|
||||||
|
.has_segment = 1};
|
||||||
|
SpacetimeSource source = {.ops = &synthetic_ops, .context = &context};
|
||||||
|
const ObserverState camera = flat_observer(50.0, 0.0, 0.0);
|
||||||
|
AsymptoticRoute route;
|
||||||
CHECK(asymptotic_route_camera(&source, &camera, (double[]){-1.0, 0.0, 0.0},
|
CHECK(asymptotic_route_camera(&source, &camera, (double[]){-1.0, 0.0, 0.0},
|
||||||
&route) == ASYMPTOTIC_TIME_RANGE_EXHAUSTED,
|
&route) == ASYMPTOTIC_TIME_RANGE_EXHAUSTED,
|
||||||
"generic worldtube bisection propagates sample failure");
|
"piecewise-constant segment history hole is exhausted");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_interior_history_exhaustion(void) {
|
static void test_interior_history_exhaustion(void) {
|
||||||
@@ -641,36 +660,30 @@ static void test_moving_sphere(void) {
|
|||||||
"co-moving ray misses");
|
"co-moving ray misses");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_accelerated_worldtube(void) {
|
static void test_accelerated_worldtube_unsupported(void) {
|
||||||
|
/* A genuinely accelerating (non-constant velocity) worldtube has no strict
|
||||||
|
* relative-motion interval bound, so the route is explicitly unsupported.
|
||||||
|
* Its former finite-history branch is covered by the constant and
|
||||||
|
* piecewise-constant history tests instead. */
|
||||||
SyntheticContext context = {.vx = 0.0, .accel = 0.02, .radius = 20.0,
|
SyntheticContext context = {.vx = 0.0, .accel = 0.02, .radius = 20.0,
|
||||||
.valid_t_min = -1.0e30, .constant = 0};
|
.valid_t_min = -1.0e30, .constant = 0};
|
||||||
SpacetimeSource source = {.ops = &synthetic_ops, .context = &context};
|
SpacetimeSource source = {.ops = &synthetic_ops, .context = &context};
|
||||||
const ObserverState camera = flat_observer(100.0, 0.0, 0.0);
|
const ObserverState camera = flat_observer(100.0, 0.0, 0.0);
|
||||||
AsymptoticRoute route;
|
AsymptoticRoute route;
|
||||||
CHECK(asymptotic_route_camera(&source, &camera, (double[]){-1.0, 0.0, 0.0},
|
CHECK(asymptotic_route_camera(&source, &camera, (double[]){-1.0, 0.0, 0.0},
|
||||||
&route) == ASYMPTOTIC_OK &&
|
&route) == ASYMPTOTIC_UNSUPPORTED,
|
||||||
route.kind == ASYMPTOTIC_ROUTE_ENTRY,
|
"accelerated worldtube route is unsupported");
|
||||||
"accelerated worldtube entry");
|
|
||||||
double value;
|
|
||||||
CHECK(asymptotic_worldtube_value(&source, route.end_id, route.activate_t,
|
|
||||||
route.x, &value) == 0 &&
|
|
||||||
fabs(value) <= 1e-13 * 20.0 * 20.0,
|
|
||||||
"accelerated entry lies on worldtube");
|
|
||||||
CHECK(route.activate_t < -40.0 && route.activate_t > -60.0,
|
|
||||||
"accelerated entry time in range");
|
|
||||||
|
|
||||||
context.valid_t_min = -30.0;
|
|
||||||
CHECK(asymptotic_route_camera(&source, &camera, (double[]){-1.0, 0.0, 0.0},
|
|
||||||
&route) == ASYMPTOTIC_TIME_RANGE_EXHAUSTED,
|
|
||||||
"exhausted history is not a miss");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_accelerated_segment(void) {
|
static void test_piecewise_segment_entry(void) {
|
||||||
|
/* The two-segment motion is piecewise constant, so velocity_constant == 1
|
||||||
|
* per segment and the closed quadratic path must still find the entry in
|
||||||
|
* the second segment (the analytic segmented first-entry case). */
|
||||||
SyntheticContext context = {.vx = 0.0,
|
SyntheticContext context = {.vx = 0.0,
|
||||||
.accel = 0.0,
|
.accel = 0.0,
|
||||||
.radius = 20.0,
|
.radius = 20.0,
|
||||||
.valid_t_min = -1.0e30,
|
.valid_t_min = -1.0e30,
|
||||||
.constant = 0,
|
.constant = 1,
|
||||||
.segment_t = -50.0,
|
.segment_t = -50.0,
|
||||||
.has_segment = 1};
|
.has_segment = 1};
|
||||||
SpacetimeSource source = {.ops = &synthetic_ops, .context = &context};
|
SpacetimeSource source = {.ops = &synthetic_ops, .context = &context};
|
||||||
@@ -679,7 +692,7 @@ static void test_accelerated_segment(void) {
|
|||||||
CHECK(asymptotic_route_camera(&source, &camera, (double[]){-1.0, 0.0, 0.0},
|
CHECK(asymptotic_route_camera(&source, &camera, (double[]){-1.0, 0.0, 0.0},
|
||||||
&route) == ASYMPTOTIC_OK &&
|
&route) == ASYMPTOTIC_OK &&
|
||||||
route.kind == ASYMPTOTIC_ROUTE_ENTRY,
|
route.kind == ASYMPTOTIC_ROUTE_ENTRY,
|
||||||
"cross-segment entry");
|
"piecewise cross-segment entry");
|
||||||
CHECK(route.activate_t < context.segment_t,
|
CHECK(route.activate_t < context.segment_t,
|
||||||
"entry lies past the motion-segment boundary");
|
"entry lies past the motion-segment boundary");
|
||||||
CHECK(fabs(route.activate_t + 65.0) < 1e-6, "cross-segment entry time");
|
CHECK(fabs(route.activate_t + 65.0) < 1e-6, "cross-segment entry time");
|
||||||
@@ -731,16 +744,17 @@ int main(void) {
|
|||||||
test_large_radius_quadratic();
|
test_large_radius_quadratic();
|
||||||
test_round_trip();
|
test_round_trip();
|
||||||
test_moving_sphere();
|
test_moving_sphere();
|
||||||
test_accelerated_worldtube();
|
test_accelerated_worldtube_unsupported();
|
||||||
test_accelerated_segment();
|
test_piecewise_segment_entry();
|
||||||
test_boundary_semantics_minkowski();
|
test_boundary_semantics_minkowski();
|
||||||
test_boundary_semantics_generic();
|
test_nonconstant_route_unsupported();
|
||||||
test_negative_radius_root_guard();
|
test_negative_radius_root_guard();
|
||||||
test_source_finalize();
|
test_source_finalize();
|
||||||
test_motion_segment_domain();
|
test_motion_segment_domain();
|
||||||
test_schwarzschild_sample_failures();
|
test_schwarzschild_sample_failures();
|
||||||
test_end_protocol_error();
|
test_end_protocol_error();
|
||||||
test_generic_bisection_failure();
|
test_nonconstant_preroute_unsupported();
|
||||||
|
test_piecewise_constant_history_hole();
|
||||||
test_interior_history_exhaustion();
|
test_interior_history_exhaustion();
|
||||||
test_interior_crossing_bisection_failure();
|
test_interior_crossing_bisection_failure();
|
||||||
test_ray_pool_lifecycle();
|
test_ray_pool_lifecycle();
|
||||||
|
|||||||
+25
-10
@@ -88,19 +88,31 @@ def image_payload(path, dimensions=(64, 48), allow_black=False):
|
|||||||
return raw
|
return raw
|
||||||
|
|
||||||
|
|
||||||
|
# Version 3 wire layout. The first 100 bytes are the v2 provenance; the v3
|
||||||
|
# adaptive policy appends 9 doubles and a u32 (76 bytes) so the provenance
|
||||||
|
# block ends at 176. Each frame header is 48 bytes, so vertex payload starts at
|
||||||
|
# 224. A v3 vertex keeps the 84-byte v2 record and appends three u64 cost
|
||||||
|
# counters; a triangle stays 32 bytes. The CRC covers only the vertex+triangle
|
||||||
|
# payload, never the header.
|
||||||
|
MAP_PROVENANCE_END = 176
|
||||||
|
MAP_FRAME_HEADER_START = MAP_PROVENANCE_END
|
||||||
|
MAP_VERTEX_START = MAP_PROVENANCE_END + 48
|
||||||
|
MAP_VERTEX_SIZE = 84 + 24
|
||||||
|
MAP_TRIANGLE_SIZE = 32
|
||||||
|
|
||||||
|
|
||||||
def map_vertices(path):
|
def map_vertices(path):
|
||||||
data = path.read_bytes()
|
data = path.read_bytes()
|
||||||
assert data[:8] == b'GRLENS\x01\x00'
|
assert data[:8] == b'GRLENS\x01\x00'
|
||||||
|
assert struct.unpack_from('<I', data, 8)[0] == 3, 'expected v3 lens map'
|
||||||
assert struct.unpack_from('<Q', data, 32)[0] == 1 # frame_count
|
assert struct.unpack_from('<Q', data, 32)[0] == 1 # frame_count
|
||||||
# Header: 40 bytes, then a 60-byte provenance block, then the 48-byte
|
vertices, triangles = struct.unpack_from('<QQ', data, MAP_FRAME_HEADER_START + 24)
|
||||||
# per-frame header, so vertices start at offset 148 in the v2 format.
|
offset = MAP_VERTEX_START
|
||||||
vertices, triangles = struct.unpack_from('<QQ', data, 124)
|
|
||||||
offset = 148
|
|
||||||
values = []
|
values = []
|
||||||
for _ in range(vertices):
|
for _ in range(vertices):
|
||||||
values.append(struct.unpack_from('<9dIII', data, offset))
|
values.append(struct.unpack_from('<9dIIIQQQ', data, offset))
|
||||||
offset += 84
|
offset += MAP_VERTEX_SIZE
|
||||||
return values, data[offset:offset + triangles * 32]
|
return values, data[offset:offset + triangles * MAP_TRIANGLE_SIZE]
|
||||||
|
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory(prefix='gr-camera-cli-') as directory:
|
with tempfile.TemporaryDirectory(prefix='gr-camera-cli-') as directory:
|
||||||
@@ -282,7 +294,10 @@ with tempfile.TemporaryDirectory(prefix='gr-camera-cli-') as directory:
|
|||||||
assert len(a) == len(b) and ta == tb
|
assert len(a) == len(b) and ta == tb
|
||||||
max_error = 0
|
max_error = 0
|
||||||
for x, y in zip(a, b):
|
for x, y in zip(a, b):
|
||||||
assert x[9:] == y[9:], 'ray endpoint provenance mismatch'
|
# Indices 9..11 are end_id/outcome/reason; indices 12..14 are the
|
||||||
|
# per-vertex integration cost counters, which are not physical ray
|
||||||
|
# provenance and may differ between the single and movie schedulers.
|
||||||
|
assert x[9:12] == y[9:12], 'ray endpoint provenance mismatch'
|
||||||
max_error = max(max_error, *(abs(v - w) for v, w in zip(x[:9], y[:9])))
|
max_error = max(max_error, *(abs(v - w) for v, w in zip(x[:9], y[:9])))
|
||||||
assert max_error < 1e-9, max_error
|
assert max_error < 1e-9, max_error
|
||||||
|
|
||||||
@@ -305,9 +320,9 @@ with tempfile.TemporaryDirectory(prefix='gr-camera-cli-') as directory:
|
|||||||
# so this tests completion semantics rather than corruption detection.
|
# so this tests completion semantics rather than corruption detection.
|
||||||
incomplete_map = tmp / f'{backend}_incomplete.grlens'
|
incomplete_map = tmp / f'{backend}_incomplete.grlens'
|
||||||
payload = bytearray(single_map.read_bytes())
|
payload = bytearray(single_map.read_bytes())
|
||||||
struct.pack_into('<II', payload, 148 + 76, 3, 5) # INCOMPLETE / INVALID_METRIC
|
struct.pack_into('<II', payload, MAP_VERTEX_START + 76, 3, 5) # INCOMPLETE / INVALID_METRIC
|
||||||
struct.pack_into('<I', payload, len(payload)-4,
|
struct.pack_into('<I', payload, len(payload)-4,
|
||||||
zlib.crc32(payload[148:-4]))
|
zlib.crc32(payload[MAP_VERTEX_START:-4]))
|
||||||
incomplete_map.write_bytes(payload)
|
incomplete_map.write_bytes(payload)
|
||||||
refused = tmp / f'{backend}_refused.{ext}'
|
refused = tmp / f'{backend}_refused.{ext}'
|
||||||
failure = run(binary, *common, '--lens-map-input', incomplete_map,
|
failure = run(binary, *common, '--lens-map-input', incomplete_map,
|
||||||
|
|||||||
+644
-2
@@ -9,6 +9,107 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/* Self-contained legacy v2 lens-map fixture writer. The production writer now
|
||||||
|
* emits v3, so this serializes a real little-endian v2 map (v2 provenance, no
|
||||||
|
* per-vertex cost counters) from a live mesh to keep the import path covered by
|
||||||
|
* genuine bytes instead of a hand-maintained golden blob. */
|
||||||
|
static uint32_t v2_crc32(uint32_t crc, const void *data, size_t size) {
|
||||||
|
const unsigned char *bytes = data;
|
||||||
|
for (size_t i = 0; i < size; ++i) {
|
||||||
|
crc ^= bytes[i];
|
||||||
|
for (int bit = 0; bit < 8; ++bit)
|
||||||
|
crc = (crc >> 1) ^ (0xedb88320u & (uint32_t)-(int)(crc & 1));
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
static int v2_fwrite_u32(FILE *f, uint32_t v) {
|
||||||
|
unsigned char b[4] = {(unsigned char)v, (unsigned char)(v >> 8),
|
||||||
|
(unsigned char)(v >> 16), (unsigned char)(v >> 24)};
|
||||||
|
return fwrite(b, 1, sizeof b, f) == sizeof b ? 0 : -1;
|
||||||
|
}
|
||||||
|
static int v2_fwrite_u64(FILE *f, uint64_t v) {
|
||||||
|
unsigned char b[8];
|
||||||
|
for (int i = 0; i < 8; ++i) b[i] = (unsigned char)(v >> (8 * i));
|
||||||
|
return fwrite(b, 1, sizeof b, f) == sizeof b ? 0 : -1;
|
||||||
|
}
|
||||||
|
static int v2_fwrite_double(FILE *f, double v) {
|
||||||
|
uint64_t bits; memcpy(&bits, &v, sizeof bits);
|
||||||
|
return v2_fwrite_u64(f, bits);
|
||||||
|
}
|
||||||
|
static int write_v2_lens_map(const char *path, int width, int height, double fov,
|
||||||
|
const LensMapProvenance *p,
|
||||||
|
const LensMapFrame *frame) {
|
||||||
|
static const unsigned char magic[8] = {'G', 'R', 'L', 'E', 'N', 'S', 1, 0};
|
||||||
|
FILE *f = fopen(path, "wb");
|
||||||
|
if (f == NULL) return -1;
|
||||||
|
int failed = fwrite(magic, 1, sizeof magic, f) != sizeof magic ||
|
||||||
|
v2_fwrite_u32(f, 2) || v2_fwrite_u32(f, 0x01020304u) ||
|
||||||
|
v2_fwrite_u32(f, (uint32_t)width) || v2_fwrite_u32(f, (uint32_t)height) ||
|
||||||
|
v2_fwrite_double(f, fov) || v2_fwrite_u64(f, 1) ||
|
||||||
|
v2_fwrite_u32(f, p->threshold_kind) ||
|
||||||
|
v2_fwrite_u32(f, p->threshold_policy_version) ||
|
||||||
|
v2_fwrite_double(f, p->threshold_value) ||
|
||||||
|
v2_fwrite_u32(f, p->retry_step_increment) ||
|
||||||
|
v2_fwrite_u32(f, p->max_total_steps) || v2_fwrite_u32(f, p->max_level) ||
|
||||||
|
v2_fwrite_u32(f, p->integrator) ||
|
||||||
|
v2_fwrite_double(f, p->min_edge_pixels) ||
|
||||||
|
v2_fwrite_double(f, p->min_area_pixels2) ||
|
||||||
|
v2_fwrite_double(f, p->coordinate_time_step) ||
|
||||||
|
v2_fwrite_u32(f, p->initial_max_steps);
|
||||||
|
const FrameLensMesh *m = &frame->mesh;
|
||||||
|
failed = failed || v2_fwrite_u64(f, frame->frame_id) ||
|
||||||
|
v2_fwrite_double(f, frame->coordinate_time) ||
|
||||||
|
v2_fwrite_double(f, frame->proper_time) ||
|
||||||
|
v2_fwrite_u64(f, (uint64_t)m->vertex_count) ||
|
||||||
|
v2_fwrite_u64(f, (uint64_t)m->triangle_count) ||
|
||||||
|
v2_fwrite_u64(f, (uint64_t)m->retry_requests);
|
||||||
|
/* The payload CRC covers vertices+triangles only; the header stays
|
||||||
|
* deliberately independent, exactly as in the production writers. */
|
||||||
|
uint32_t crc = UINT32_MAX;
|
||||||
|
for (size_t i = 0; i < m->vertex_count; ++i) {
|
||||||
|
const LensVertex *v = &m->vertices[i];
|
||||||
|
const double vals[9] = {v->image_x, v->image_y, v->camera_direction[0],
|
||||||
|
v->camera_direction[1], v->camera_direction[2],
|
||||||
|
v->n_infinity[0], v->n_infinity[1], v->n_infinity[2],
|
||||||
|
v->log_frequency_ratio};
|
||||||
|
const uint32_t tail[3] = {(uint32_t)v->end_id, (uint32_t)v->outcome,
|
||||||
|
(uint32_t)v->reason};
|
||||||
|
unsigned char b[84]; size_t off = 0;
|
||||||
|
for (int k = 0; k < 9; ++k) {
|
||||||
|
uint64_t bits; memcpy(&bits, &vals[k], sizeof bits);
|
||||||
|
for (int q = 0; q < 8; ++q) b[off++] = (unsigned char)(bits >> (8 * q));
|
||||||
|
}
|
||||||
|
for (int k = 0; k < 3; ++k) {
|
||||||
|
b[off++] = (unsigned char)tail[k];
|
||||||
|
b[off++] = (unsigned char)(tail[k] >> 8);
|
||||||
|
b[off++] = (unsigned char)(tail[k] >> 16);
|
||||||
|
b[off++] = (unsigned char)(tail[k] >> 24);
|
||||||
|
}
|
||||||
|
if (fwrite(b, 1, sizeof b, f) != sizeof b) failed = 1;
|
||||||
|
crc = v2_crc32(crc, b, sizeof b);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < m->triangle_count; ++i) {
|
||||||
|
unsigned char b[32]; size_t off = 0;
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
const uint64_t idx = (uint64_t)m->triangles[i].vertex[j];
|
||||||
|
for (int q = 0; q < 8; ++q) b[off++] = (unsigned char)(idx >> (8 * q));
|
||||||
|
}
|
||||||
|
const uint32_t tail[2] = {m->triangles[i].level,
|
||||||
|
(uint32_t)m->triangles[i].approx_black};
|
||||||
|
for (int k = 0; k < 2; ++k) {
|
||||||
|
b[off++] = (unsigned char)tail[k];
|
||||||
|
b[off++] = (unsigned char)(tail[k] >> 8);
|
||||||
|
b[off++] = (unsigned char)(tail[k] >> 16);
|
||||||
|
b[off++] = (unsigned char)(tail[k] >> 24);
|
||||||
|
}
|
||||||
|
if (fwrite(b, 1, sizeof b, f) != sizeof b) failed = 1;
|
||||||
|
crc = v2_crc32(crc, b, sizeof b);
|
||||||
|
}
|
||||||
|
if (v2_fwrite_u32(f, crc ^ UINT32_MAX)) failed = 1;
|
||||||
|
if (fclose(f)) failed = 1;
|
||||||
|
return failed ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int mesh_has_hanging_vertex(const FrameLensMesh *mesh) {
|
static int mesh_has_hanging_vertex(const FrameLensMesh *mesh) {
|
||||||
for (size_t triangle = 0; triangle < mesh->triangle_count; ++triangle)
|
for (size_t triangle = 0; triangle < mesh->triangle_count; ++triangle)
|
||||||
for (size_t side = 0; side < 3; ++side) {
|
for (size_t side = 0; side < 3; ++side) {
|
||||||
@@ -139,6 +240,9 @@ static int review_probe_regressions(void) {
|
|||||||
m.vertices[i].n_infinity[0]=1;
|
m.vertices[i].n_infinity[0]=1;
|
||||||
}
|
}
|
||||||
m.vertices[0].outcome=RAY_OUTCOME_UNRESOLVED;
|
m.vertices[0].outcome=RAY_OUTCOME_UNRESOLVED;
|
||||||
|
/* A genuinely budget-exhausted vertex has consumed its accepted-step
|
||||||
|
* quota; the retry layer keys on that blocking quota. */
|
||||||
|
m.vertices[0].continuation_steps=10;
|
||||||
m.vertices[0].continuation_limit=10;
|
m.vertices[0].continuation_limit=10;
|
||||||
if (frame_lens_mesh_prepare_generation(&m,&c)<1 || m.retry_requests==0)
|
if (frame_lens_mesh_prepare_generation(&m,&c)<1 || m.retry_requests==0)
|
||||||
return -1; /* the retry counter is produced by real retry requests */
|
return -1; /* the retry counter is produced by real retry requests */
|
||||||
@@ -153,11 +257,408 @@ static int review_probe_regressions(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A budget-exhausted vertex carrying the full adaptive resume state, so the
|
||||||
|
* retry layer sees the same payload the production store_endpoint path writes. */
|
||||||
|
static LensVertex unresolved_vertex(double image_x, double t, double start,
|
||||||
|
unsigned int steps,
|
||||||
|
unsigned int step_limit,
|
||||||
|
double lookback_limit) {
|
||||||
|
LensVertex v;
|
||||||
|
memset(&v, 0, sizeof v);
|
||||||
|
v.image_x = image_x;
|
||||||
|
v.image_y = 0.0;
|
||||||
|
v.camera_direction[0] = 1.0;
|
||||||
|
v.outcome = RAY_OUTCOME_UNRESOLVED;
|
||||||
|
v.traced = 1;
|
||||||
|
v.continuation_t = t;
|
||||||
|
v.continuation_x[0] = 1.0;
|
||||||
|
v.continuation_Pi[0] = -1.0;
|
||||||
|
v.continuation_log_alpha_p0 = 0.125;
|
||||||
|
v.continuation_log_alpha_p0_0 = 0.5;
|
||||||
|
v.continuation_steps = steps;
|
||||||
|
v.continuation_limit = step_limit;
|
||||||
|
v.continuation_integration_start_time = start;
|
||||||
|
v.continuation_next_step = 0.25;
|
||||||
|
v.continuation_rejected_steps = 2;
|
||||||
|
v.continuation_rhs_evaluations = 20;
|
||||||
|
v.continuation_previous_rejected = 0;
|
||||||
|
v.continuation_lookback_limit = lookback_limit;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int uuu_fixture(LensVertex vertices[3], LensTriangle *triangle) {
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
vertices[i].camera_direction[0] = 1.0;
|
||||||
|
*triangle = (LensTriangle){{0, 1, 2}, 0, 0, 0};
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Independent step/time retry budgets: a request is allowed only while every
|
||||||
|
* quota that actually blocked the ray can still grow, and the two quotas are
|
||||||
|
* saturated separately. Also verifies the resume-state round trip used by
|
||||||
|
* both the frame and movie paths. */
|
||||||
|
static int review_retry_quota_regressions(void) {
|
||||||
|
/* 1. Step-blocked, both quotas growable: the step quota advances, and the
|
||||||
|
* request records the independently saturated time quota. */
|
||||||
|
{
|
||||||
|
LensVertex vertices[3] = {
|
||||||
|
unresolved_vertex(0.0, -1.0, 0.0, 20, 20, 2.0),
|
||||||
|
unresolved_vertex(10.0, -1.0, 0.0, 20, 20, 2.0),
|
||||||
|
unresolved_vertex(0.0, -1.0, 0.0, 20, 20, 2.0)};
|
||||||
|
LensTriangle triangle;
|
||||||
|
uuu_fixture(vertices, &triangle);
|
||||||
|
FrameLensMesh m = {.vertices = vertices, .vertex_count = 3,
|
||||||
|
.triangles = &triangle, .triangle_count = 1};
|
||||||
|
RefinementConfig c = {.max_level = 0,
|
||||||
|
.retry_step_increment = 10,
|
||||||
|
.max_total_steps = 100,
|
||||||
|
.retry_lookback_increment = 1.0,
|
||||||
|
.max_total_lookback_time = 10.0};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&m, &c) != 3) {
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < m.sample_count; ++i)
|
||||||
|
if (m.samples[i].kind != FRAME_SAMPLE_RETRY ||
|
||||||
|
m.samples[i].step_limit != 30 ||
|
||||||
|
m.samples[i].lookback_limit != 3.0) {
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
}
|
||||||
|
/* 2. Step quota at its cap while time can still grow: no request, because
|
||||||
|
* more time cannot buy an accepted step. The UUU triangle stays a
|
||||||
|
* budget-incomplete boundary, never blackened. */
|
||||||
|
{
|
||||||
|
LensVertex vertices[3] = {
|
||||||
|
unresolved_vertex(0.0, -1.0, 0.0, 20, 20, 2.0),
|
||||||
|
unresolved_vertex(10.0, -1.0, 0.0, 20, 20, 2.0),
|
||||||
|
unresolved_vertex(0.0, -1.0, 0.0, 20, 20, 2.0)};
|
||||||
|
LensTriangle triangle;
|
||||||
|
uuu_fixture(vertices, &triangle);
|
||||||
|
FrameLensMesh m = {.vertices = vertices, .vertex_count = 3,
|
||||||
|
.triangles = &triangle, .triangle_count = 1};
|
||||||
|
RefinementConfig c = {.max_level = 0,
|
||||||
|
.retry_step_increment = 10,
|
||||||
|
.max_total_steps = 20,
|
||||||
|
.retry_lookback_increment = 1.0,
|
||||||
|
.max_total_lookback_time = 10.0};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&m, &c) != 0) {
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
FrameBoundaryStats stats;
|
||||||
|
frame_lens_mesh_boundary_stats(&m, &c, &stats);
|
||||||
|
if (stats.uuu != 1 || stats.budget_incomplete_triangles == 0 ||
|
||||||
|
stats.approx_black_triangles != 0) {
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
}
|
||||||
|
/* 3. Time-blocked with a disabled step increment: the time quota alone
|
||||||
|
* enables the retry and the step budget is left untouched. */
|
||||||
|
{
|
||||||
|
LensVertex vertices[3] = {
|
||||||
|
unresolved_vertex(0.0, -3.0, 0.0, 5, 10, 2.0),
|
||||||
|
unresolved_vertex(10.0, -3.0, 0.0, 5, 10, 2.0),
|
||||||
|
unresolved_vertex(0.0, -3.0, 0.0, 5, 10, 2.0)};
|
||||||
|
LensTriangle triangle;
|
||||||
|
uuu_fixture(vertices, &triangle);
|
||||||
|
FrameLensMesh m = {.vertices = vertices, .vertex_count = 3,
|
||||||
|
.triangles = &triangle, .triangle_count = 1};
|
||||||
|
RefinementConfig c = {.max_level = 0,
|
||||||
|
.retry_step_increment = 0,
|
||||||
|
.max_total_steps = 10,
|
||||||
|
.retry_lookback_increment = 1.0,
|
||||||
|
.max_total_lookback_time = 10.0};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&m, &c) != 3) {
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < m.sample_count; ++i)
|
||||||
|
if (m.samples[i].kind != FRAME_SAMPLE_RETRY ||
|
||||||
|
m.samples[i].step_limit != 10 ||
|
||||||
|
m.samples[i].lookback_limit != 3.0) {
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
}
|
||||||
|
/* 4. Both blocking quotas at their caps: no request. */
|
||||||
|
{
|
||||||
|
LensVertex vertices[3] = {
|
||||||
|
unresolved_vertex(0.0, -6.0, 0.0, 20, 20, 5.0),
|
||||||
|
unresolved_vertex(10.0, -6.0, 0.0, 20, 20, 5.0),
|
||||||
|
unresolved_vertex(0.0, -6.0, 0.0, 20, 20, 5.0)};
|
||||||
|
LensTriangle triangle;
|
||||||
|
uuu_fixture(vertices, &triangle);
|
||||||
|
FrameLensMesh m = {.vertices = vertices, .vertex_count = 3,
|
||||||
|
.triangles = &triangle, .triangle_count = 1};
|
||||||
|
RefinementConfig c = {.max_level = 0,
|
||||||
|
.retry_step_increment = 10,
|
||||||
|
.max_total_steps = 20,
|
||||||
|
.retry_lookback_increment = 1.0,
|
||||||
|
.max_total_lookback_time = 5.0};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&m, &c) != 0) {
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(m.samples); free(m.probe_slots);
|
||||||
|
}
|
||||||
|
/* 5. Resume-state round trip: the helper reproduces every control field, and
|
||||||
|
* install back-fills the vertex with the endpoint's new state and quota. */
|
||||||
|
{
|
||||||
|
LensVertex source = unresolved_vertex(0.0, -1.0, 0.0, 20, 20, 2.0);
|
||||||
|
GeodesicRayState state;
|
||||||
|
if (frame_vertex_continuation_state(&source, &state) ||
|
||||||
|
state.coordinate_time != -1.0 || state.steps != 20 ||
|
||||||
|
state.integration_start_time != 0.0 || state.next_step != 0.25 ||
|
||||||
|
state.rejected_steps != 2 || state.rhs_evaluations != 20 ||
|
||||||
|
state.previous_rejected != 0 || state.log_alpha_p0 != 0.125 ||
|
||||||
|
state.log_alpha_p0_0 != 0.5 || state.x[0] != 1.0 ||
|
||||||
|
state.Pi[0] != -1.0)
|
||||||
|
return -1;
|
||||||
|
LensVertex target = {.image_x = 0.0, .camera_direction = {1.0, 0.0, 0.0}};
|
||||||
|
FrameLensMesh mesh = {.vertices = &target, .vertex_count = 1};
|
||||||
|
RefinementConfig plain = {.max_level = 0};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&mesh, &plain) != 1) {
|
||||||
|
free(mesh.samples); free(mesh.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
const RayEndpoint endpoint = {
|
||||||
|
.magnification = 1.0,
|
||||||
|
.end_id = SPACETIME_END_NONE,
|
||||||
|
.outcome = RAY_OUTCOME_UNRESOLVED,
|
||||||
|
.reason = RAY_REASON_BUDGET_EXHAUSTED,
|
||||||
|
.stop_coordinate_time = -4.0,
|
||||||
|
.accepted_steps = 7,
|
||||||
|
.final_x = {5.0, 0.0, 0.0},
|
||||||
|
.final_Pi = {-1.0, 0.0, 0.0},
|
||||||
|
.final_log_alpha_p0 = 0.125,
|
||||||
|
.final_log_alpha_p0_0 = 0.5,
|
||||||
|
.threshold_value = NAN,
|
||||||
|
.integration_start_time = 0.0,
|
||||||
|
.next_step = 0.5,
|
||||||
|
.rejected_steps = 3,
|
||||||
|
.rhs_evaluations = 70,
|
||||||
|
.previous_rejected = 1,
|
||||||
|
.lookback_limit = 2.5};
|
||||||
|
if (frame_lens_mesh_install_sample(&mesh, 0, &endpoint) ||
|
||||||
|
target.outcome != RAY_OUTCOME_UNRESOLVED ||
|
||||||
|
target.continuation_t != -4.0 || target.continuation_steps != 7 ||
|
||||||
|
target.continuation_limit != 7 ||
|
||||||
|
target.continuation_integration_start_time != 0.0 ||
|
||||||
|
target.continuation_next_step != 0.5 ||
|
||||||
|
target.continuation_rejected_steps != 3 ||
|
||||||
|
target.continuation_rhs_evaluations != 70 ||
|
||||||
|
target.continuation_previous_rejected != 1 ||
|
||||||
|
target.continuation_lookback_limit != 2.5) {
|
||||||
|
free(mesh.samples); free(mesh.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
GeodesicRayState rebuilt;
|
||||||
|
if (frame_vertex_continuation_state(&target, &rebuilt) ||
|
||||||
|
rebuilt.coordinate_time != -4.0 || rebuilt.steps != 7 ||
|
||||||
|
rebuilt.next_step != 0.5 || rebuilt.rejected_steps != 3 ||
|
||||||
|
rebuilt.rhs_evaluations != 70 || rebuilt.previous_rejected != 1) {
|
||||||
|
free(mesh.samples); free(mesh.probe_slots);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(mesh.samples); free(mesh.probe_slots);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GeodesicTraceConfig frame_dp_config(double lookback) {
|
||||||
|
GeodesicTraceConfig c;
|
||||||
|
memset(&c, 0, sizeof c);
|
||||||
|
c.stepper = GEODESIC_STEPPER_DP54;
|
||||||
|
c.coordinate_time_step = 0.5;
|
||||||
|
c.max_steps = 100;
|
||||||
|
c.threshold = (ThresholdPolicy){.kind = THRESHOLD_DISABLED, .value = 0.0,
|
||||||
|
.policy_version = 0};
|
||||||
|
c.atol_x = c.atol_Pi = c.atol_L = c.rtol = 1e-9;
|
||||||
|
c.min_step = 1e-12;
|
||||||
|
c.max_step = 1e6;
|
||||||
|
c.consecutive_rejection_limit = 1000;
|
||||||
|
c.max_lookback_time = lookback;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A real production trace must record the configured step/time grant distinct
|
||||||
|
* from the spent counts, so a time-limited ray can retry with extra time while
|
||||||
|
* keeping its full step grant. A retry candidate also counts only when it
|
||||||
|
* opens a strictly larger representable region. */
|
||||||
|
static int review_real_grant_and_time_growth(void) {
|
||||||
|
SpacetimeSource source = {0};
|
||||||
|
if (spacetime_create_minkowski(&source, 10.0))
|
||||||
|
return -1;
|
||||||
|
const ObserverState observer = observer_fixed_at_origin();
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
|
/* A. Real trace at the origin, time-limited after ~2 of 100 granted steps.
|
||||||
|
* With the step increment disabled and the time increment enabled, the
|
||||||
|
* retry must keep step_limit == 100 and only grow the time budget. */
|
||||||
|
{
|
||||||
|
LensVertex vertices[3] = {{.camera_direction = {1.0, 0.0, 0.0}},
|
||||||
|
{.camera_direction = {1.0, 0.0, 0.0}},
|
||||||
|
{.camera_direction = {1.0, 0.0, 0.0}}};
|
||||||
|
LensTriangle triangle = {{0, 1, 2}, 0, 0, 0};
|
||||||
|
FrameLensMesh m = {.vertices = vertices, .vertex_count = 3,
|
||||||
|
.triangles = &triangle, .triangle_count = 1};
|
||||||
|
const GeodesicTraceConfig trace = frame_dp_config(1.0);
|
||||||
|
if (frame_lens_mesh_trace(&m, &source, &observer, &trace))
|
||||||
|
failed = 1;
|
||||||
|
for (size_t i = 0; i < 3 && !failed; ++i) {
|
||||||
|
if (vertices[i].outcome != RAY_OUTCOME_UNRESOLVED ||
|
||||||
|
vertices[i].continuation_limit != 100u ||
|
||||||
|
vertices[i].continuation_steps >= 100u ||
|
||||||
|
vertices[i].continuation_lookback_limit != 1.0)
|
||||||
|
failed = 1;
|
||||||
|
}
|
||||||
|
const RefinementConfig retry = {.max_level = 0,
|
||||||
|
.retry_step_increment = 0,
|
||||||
|
.max_total_steps = 100,
|
||||||
|
.retry_lookback_increment = 1.0,
|
||||||
|
.max_total_lookback_time = 100.0};
|
||||||
|
if (!failed && frame_lens_mesh_prepare_generation(&m, &retry) != 3)
|
||||||
|
failed = 1;
|
||||||
|
for (size_t i = 0; i < m.sample_count && !failed; ++i)
|
||||||
|
if (m.samples[i].kind != FRAME_SAMPLE_RETRY ||
|
||||||
|
m.samples[i].step_limit != 100u ||
|
||||||
|
m.samples[i].lookback_limit != 2.0)
|
||||||
|
failed = 1;
|
||||||
|
free(m.samples);
|
||||||
|
free(m.probe_slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* B. Translated time origins (positive, negative and zero) still detect the
|
||||||
|
* lookback boundary with the integrator's own comparison and retry with a
|
||||||
|
* strictly larger time region while preserving the step grant. */
|
||||||
|
for (int origin = 0; origin < 3 && !failed; ++origin) {
|
||||||
|
const double t0 = origin == 0 ? 0.0 : origin == 1 ? 1.0e9 : -1.0e9;
|
||||||
|
ObserverState o = observer_fixed_at_origin();
|
||||||
|
o.coordinate_time = t0;
|
||||||
|
const GeodesicTraceConfig trace = frame_dp_config(0.3);
|
||||||
|
MetricData metric;
|
||||||
|
if (spacetime_eval(&source, t0, o.coordinate_position, &metric)) {
|
||||||
|
failed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GeodesicRayState state;
|
||||||
|
if (geodesic_initialize_past_ray_metric(&metric, &o, (double[]){1, 0, 0},
|
||||||
|
&state)) {
|
||||||
|
failed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const RayEndpoint endpoint =
|
||||||
|
geodesic_trace_past_from_state(&source, &state, &trace);
|
||||||
|
if (endpoint.outcome != RAY_OUTCOME_UNRESOLVED ||
|
||||||
|
endpoint.accepted_step_limit != 100u || endpoint.accepted_steps != 1u) {
|
||||||
|
failed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LensVertex vertices[3];
|
||||||
|
memset(vertices, 0, sizeof vertices);
|
||||||
|
vertices[1].traced = vertices[2].traced = 1;
|
||||||
|
vertices[1].outcome = vertices[2].outcome = RAY_OUTCOME_ESCAPED;
|
||||||
|
vertices[1].n_infinity[0] = vertices[2].n_infinity[0] = 1.0;
|
||||||
|
vertices[1].end_id = vertices[2].end_id = 0;
|
||||||
|
LensTriangle triangle = {{0, 1, 2}, 0, 0, 0};
|
||||||
|
FrameLensMesh m = {.vertices = vertices, .vertex_count = 3,
|
||||||
|
.triangles = &triangle, .triangle_count = 1};
|
||||||
|
const RefinementConfig plain = {.max_level = 0};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&m, &plain) != 1 ||
|
||||||
|
frame_lens_mesh_install_sample(&m, 0, &endpoint) ||
|
||||||
|
vertices[0].continuation_limit != 100u ||
|
||||||
|
vertices[0].continuation_lookback_limit != 0.3) {
|
||||||
|
free(m.samples);
|
||||||
|
free(m.probe_slots);
|
||||||
|
failed = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(m.samples);
|
||||||
|
m.samples = NULL;
|
||||||
|
m.sample_count = m.sample_capacity = 0;
|
||||||
|
const RefinementConfig retry = {.max_level = 0,
|
||||||
|
.retry_step_increment = 0,
|
||||||
|
.max_total_steps = 100,
|
||||||
|
.retry_lookback_increment = 0.3,
|
||||||
|
.max_total_lookback_time = 10.0};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&m, &retry) != 1 ||
|
||||||
|
m.samples[0].kind != FRAME_SAMPLE_RETRY ||
|
||||||
|
m.samples[0].step_limit != 100u ||
|
||||||
|
m.samples[0].lookback_limit != 0.6)
|
||||||
|
failed = 1;
|
||||||
|
free(m.samples);
|
||||||
|
free(m.probe_slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C. A larger quota that does not move the left boundary (increment rounds
|
||||||
|
* away, or a large time origin absorbs it) must not launch a retry. */
|
||||||
|
{
|
||||||
|
LensVertex vertices[3] = {
|
||||||
|
unresolved_vertex(0.0, -1.0e9, 0.0, 1, 100, 1.0e9),
|
||||||
|
unresolved_vertex(10.0, -1.0e9, 0.0, 1, 100, 1.0e9),
|
||||||
|
unresolved_vertex(0.0, -1.0e9, 0.0, 1, 100, 1.0e9)};
|
||||||
|
LensTriangle triangle;
|
||||||
|
uuu_fixture(vertices, &triangle);
|
||||||
|
FrameLensMesh m = {.vertices = vertices, .vertex_count = 3,
|
||||||
|
.triangles = &triangle, .triangle_count = 1};
|
||||||
|
const RefinementConfig rounded = {.max_level = 0,
|
||||||
|
.retry_step_increment = 0,
|
||||||
|
.max_total_steps = 100,
|
||||||
|
.retry_lookback_increment = 1.0e-8,
|
||||||
|
.max_total_lookback_time = 2.0e9};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&m, &rounded) != 0)
|
||||||
|
failed = 1;
|
||||||
|
FrameBoundaryStats stats;
|
||||||
|
frame_lens_mesh_boundary_stats(&m, &rounded, &stats);
|
||||||
|
if (stats.uuu != 1 || stats.budget_incomplete_triangles == 0)
|
||||||
|
failed = 1;
|
||||||
|
free(m.samples);
|
||||||
|
free(m.probe_slots);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const double start = 1.0e12;
|
||||||
|
const double quota = 1.0e6;
|
||||||
|
LensVertex vertices[3] = {
|
||||||
|
unresolved_vertex(0.0, start - quota, start, 1, 100, quota),
|
||||||
|
unresolved_vertex(10.0, start - quota, start, 1, 100, quota),
|
||||||
|
unresolved_vertex(0.0, start - quota, start, 1, 100, quota)};
|
||||||
|
LensTriangle triangle;
|
||||||
|
uuu_fixture(vertices, &triangle);
|
||||||
|
FrameLensMesh m = {.vertices = vertices, .vertex_count = 3,
|
||||||
|
.triangles = &triangle, .triangle_count = 1};
|
||||||
|
const RefinementConfig absorbed = {.max_level = 0,
|
||||||
|
.retry_step_increment = 0,
|
||||||
|
.max_total_steps = 100,
|
||||||
|
.retry_lookback_increment = 1.0e-6,
|
||||||
|
.max_total_lookback_time = 2.0e6};
|
||||||
|
if (frame_lens_mesh_prepare_generation(&m, &absorbed) != 0)
|
||||||
|
failed = 1;
|
||||||
|
free(m.samples);
|
||||||
|
free(m.probe_slots);
|
||||||
|
}
|
||||||
|
spacetime_destroy(&source);
|
||||||
|
return failed ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
if (review_probe_regressions()) {
|
if (review_probe_regressions()) {
|
||||||
fputs("probe persistence / retry invalidation regression failed\n",stderr);
|
fputs("probe persistence / retry invalidation regression failed\n",stderr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (review_retry_quota_regressions()) {
|
||||||
|
fputs("independent retry quota regression failed\n", stderr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (review_real_grant_and_time_growth()) {
|
||||||
|
fputs("real grant / representable time growth regression failed\n", stderr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
const int width = 100, height = 100;
|
const int width = 100, height = 100;
|
||||||
const double test_exposure = 1e-3;
|
const double test_exposure = 1e-3;
|
||||||
const double psf_relative_tail = 1e-8;
|
const double psf_relative_tail = 1e-8;
|
||||||
@@ -187,7 +688,7 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
/* A finalized mesh can be persisted independently of spacetime and then
|
/* A finalized mesh can be persisted independently of spacetime and then
|
||||||
* drive the exact same catalog inverse-map and PSF pass. */
|
* drive the exact same catalog inverse-map and PSF pass. */
|
||||||
const char *lens_map_path = "/tmp/gr_lens_map_test.grlens";
|
const char *lens_map_path = "/tmp/opencode/gr_lens_map_test.grlens";
|
||||||
mesh.retry_requests = 2; /* cumulative per-frame retry accounting round-trips */
|
mesh.retry_requests = 2; /* cumulative per-frame retry accounting round-trips */
|
||||||
const LensMapFrame saved_frame = {.frame_id = 7,
|
const LensMapFrame saved_frame = {.frame_id = 7,
|
||||||
.coordinate_time = 3.0,
|
.coordinate_time = 3.0,
|
||||||
@@ -259,7 +760,7 @@ int main(void) {
|
|||||||
/* A version-1 header must be rejected outright: its captured bit cannot be
|
/* A version-1 header must be rejected outright: its captured bit cannot be
|
||||||
* upgraded into the new dark/unresolved/error provenance. */
|
* upgraded into the new dark/unresolved/error provenance. */
|
||||||
{
|
{
|
||||||
const char *legacy_path = "/tmp/gr_lens_map_v1_test.grlens";
|
const char *legacy_path = "/tmp/opencode/gr_lens_map_v1_test.grlens";
|
||||||
FILE *legacy = fopen(legacy_path, "wb");
|
FILE *legacy = fopen(legacy_path, "wb");
|
||||||
int legacy_failed = legacy == NULL;
|
int legacy_failed = legacy == NULL;
|
||||||
if (!legacy_failed) {
|
if (!legacy_failed) {
|
||||||
@@ -906,6 +1407,147 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
free(ud_mesh.probe_slots);
|
free(ud_mesh.probe_slots);
|
||||||
}
|
}
|
||||||
|
/* v3 DP54 round-trip: every adaptive/quota field and the per-vertex cost
|
||||||
|
* counters must survive the wire exactly. */
|
||||||
|
{
|
||||||
|
const char *dp_path = "/tmp/opencode/gr_lens_map_v3_dp_test.grlens";
|
||||||
|
LensVertex dv[3];
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
dv[i] = (LensVertex){.image_x = (double)i, .image_y = 2.0,
|
||||||
|
.camera_direction = {0.0, 0.0, -1.0},
|
||||||
|
.outcome = RAY_OUTCOME_DARK,
|
||||||
|
.reason = RAY_REASON_REDSHIFT_LIMIT,
|
||||||
|
.end_id = SPACETIME_END_NONE, .traced = 1};
|
||||||
|
dv[0].trace_accepted_steps = 11; dv[0].trace_rejected_steps = 2;
|
||||||
|
dv[0].trace_rhs_evaluations = 79;
|
||||||
|
dv[1].trace_accepted_steps = 5;
|
||||||
|
LensTriangle dt = {{0, 1, 2}, 1, 1, 0};
|
||||||
|
FrameLensMesh dm = {.vertices = dv, .triangles = &dt, .vertex_count = 3,
|
||||||
|
.vertex_capacity = 3, .triangle_count = 1,
|
||||||
|
.triangle_capacity = 1};
|
||||||
|
LensMapFrame df = {.frame_id = 3, .coordinate_time = 1.5,
|
||||||
|
.proper_time = 1.25, .mesh = dm};
|
||||||
|
const LensMapProvenance dp = {.threshold_kind = THRESHOLD_LOG_ENERGY_GROWTH,
|
||||||
|
.threshold_policy_version = 3, .threshold_value = 8.0,
|
||||||
|
.retry_step_increment = 64, .max_total_steps = 256, .max_level = 2,
|
||||||
|
.integrator = (uint32_t)GEODESIC_STEPPER_DP54,
|
||||||
|
.min_edge_pixels = 0.5, .min_area_pixels2 = 0.25,
|
||||||
|
.coordinate_time_step = 0.1, .initial_max_steps = 1024,
|
||||||
|
.atol_x = 1e-9, .atol_Pi = 1e-9, .atol_L = 1e-9, .rtol = 1e-9,
|
||||||
|
.min_step = 1e-12, .max_step = 2.0, .max_lookback_time = 102.4,
|
||||||
|
.retry_lookback_increment = 102.4, .max_total_lookback_time = 409.6,
|
||||||
|
.max_consecutive_rejections = 32};
|
||||||
|
LensMap dloaded = {0};
|
||||||
|
if (lens_map_write(dp_path, 4, 3, 30.0, &dp, &df, 1) ||
|
||||||
|
lens_map_read(dp_path, NULL, &dloaded)) {
|
||||||
|
fputs("lens-map v3 DP54 round-trip regression failed\n", stderr);
|
||||||
|
lens_map_destroy(&dloaded); unlink(dp_path); goto done;
|
||||||
|
}
|
||||||
|
const LensMapProvenance *lp = &dloaded.provenance;
|
||||||
|
if (dloaded.file_version != 3 ||
|
||||||
|
lp->integrator != (uint32_t)GEODESIC_STEPPER_DP54 ||
|
||||||
|
lp->atol_x != 1e-9 || lp->atol_Pi != 1e-9 || lp->atol_L != 1e-9 ||
|
||||||
|
lp->rtol != 1e-9 || lp->min_step != 1e-12 || lp->max_step != 2.0 ||
|
||||||
|
lp->max_lookback_time != 102.4 ||
|
||||||
|
lp->retry_lookback_increment != 102.4 ||
|
||||||
|
lp->max_total_lookback_time != 409.6 ||
|
||||||
|
lp->max_consecutive_rejections != 32 ||
|
||||||
|
lp->retry_step_increment != 64 || lp->max_total_steps != 256 ||
|
||||||
|
lp->coordinate_time_step != 0.1 || lp->initial_max_steps != 1024 ||
|
||||||
|
dloaded.frames[0].mesh.vertices[0].trace_accepted_steps != 11 ||
|
||||||
|
dloaded.frames[0].mesh.vertices[0].trace_rejected_steps != 2 ||
|
||||||
|
dloaded.frames[0].mesh.vertices[0].trace_rhs_evaluations != 79 ||
|
||||||
|
dloaded.frames[0].mesh.vertices[1].trace_accepted_steps != 5 ||
|
||||||
|
dloaded.frames[0].mesh.triangles[0].level != 1) {
|
||||||
|
fputs("lens-map v3 DP54 field round-trip regression failed\n", stderr);
|
||||||
|
lens_map_destroy(&dloaded); unlink(dp_path); goto done;
|
||||||
|
}
|
||||||
|
lens_map_destroy(&dloaded);
|
||||||
|
/* Unknown wire code and non-finite/out-of-bounds DP fields must be rejected
|
||||||
|
* by the shared schema validator, not accepted as a usable map. */
|
||||||
|
{
|
||||||
|
/* offset, is_double, double_value, u32_value */
|
||||||
|
const struct { long offset; int is_double; double dvalue; uint32_t uvalue; }
|
||||||
|
corruptions[4] = {{68, 0, 0.0, 7u}, /* unknown integrator code */
|
||||||
|
{100, 1, NAN, 0u}, /* atol_x = NaN */
|
||||||
|
{108, 1, -1.0, 0u}, /* atol_Pi below zero */
|
||||||
|
{156, 1, -1.0, 0u}}; /* max_lookback below zero */
|
||||||
|
for (size_t c = 0; c < 4; ++c) {
|
||||||
|
if (lens_map_write(dp_path, 4, 3, 30.0, &dp, &df, 1)) {
|
||||||
|
fputs("lens-map v3 corruption fixture write failed\n", stderr);
|
||||||
|
unlink(dp_path); goto done;
|
||||||
|
}
|
||||||
|
FILE *bad = fopen(dp_path, "r+b");
|
||||||
|
int bad_failed =
|
||||||
|
bad == NULL || fseek(bad, corruptions[c].offset, SEEK_SET);
|
||||||
|
if (!bad_failed) {
|
||||||
|
if (corruptions[c].is_double)
|
||||||
|
bad_failed = fwrite(&corruptions[c].dvalue,
|
||||||
|
sizeof(double), 1, bad) != 1;
|
||||||
|
else
|
||||||
|
bad_failed = fwrite(&corruptions[c].uvalue,
|
||||||
|
sizeof(uint32_t), 1, bad) != 1;
|
||||||
|
}
|
||||||
|
if (bad != NULL && fclose(bad)) bad_failed = 1;
|
||||||
|
if (bad_failed || !lens_map_read(dp_path, NULL, &dloaded)) {
|
||||||
|
fputs("lens-map v3 invalid DP54 field rejection regression failed\n",
|
||||||
|
stderr);
|
||||||
|
lens_map_destroy(&dloaded); unlink(dp_path); goto done;
|
||||||
|
}
|
||||||
|
lens_map_destroy(&dloaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlink(dp_path);
|
||||||
|
}
|
||||||
|
/* Legacy v2 import: a real v2 map (no adaptive fields, no cost counters)
|
||||||
|
* must load as RK4 with an explicit zero adaptive policy and render
|
||||||
|
* identically to the live mesh. */
|
||||||
|
{
|
||||||
|
const char *v2_path = "/tmp/opencode/gr_lens_map_v2_legacy_test.grlens";
|
||||||
|
const LensMapProvenance v2p = {.threshold_kind = THRESHOLD_LOG_ALPHA_P0,
|
||||||
|
.threshold_policy_version = 1, .threshold_value = 8.0,
|
||||||
|
.retry_step_increment = 16, .max_total_steps = 64, .max_level = 2,
|
||||||
|
.integrator = (uint32_t)GEODESIC_STEPPER_RK4,
|
||||||
|
.min_edge_pixels = 0.5, .min_area_pixels2 = 0.25,
|
||||||
|
.coordinate_time_step = 0.1, .initial_max_steps = 4096};
|
||||||
|
const LensMapFrame v2f = {.frame_id = 7, .coordinate_time = 3.0,
|
||||||
|
.proper_time = 2.0, .mesh = mesh};
|
||||||
|
LensMap v2loaded = {0};
|
||||||
|
double *v2_hdr = calloc((size_t)width * height * 3, sizeof *v2_hdr);
|
||||||
|
double *live_hdr = calloc((size_t)width * height * 3, sizeof *live_hdr);
|
||||||
|
if (v2_hdr == NULL || live_hdr == NULL ||
|
||||||
|
write_v2_lens_map(v2_path, width, height, 30.0, &v2p, &v2f) ||
|
||||||
|
lens_map_read(v2_path, NULL, &v2loaded) ||
|
||||||
|
v2loaded.file_version != 2 ||
|
||||||
|
v2loaded.provenance.integrator != (uint32_t)GEODESIC_STEPPER_RK4 ||
|
||||||
|
v2loaded.provenance.atol_x != 0.0 ||
|
||||||
|
v2loaded.provenance.max_lookback_time != 0.0 ||
|
||||||
|
v2loaded.provenance.max_total_lookback_time != 0.0 ||
|
||||||
|
v2loaded.provenance.max_consecutive_rejections != 0 ||
|
||||||
|
v2loaded.frames[0].mesh.vertices[0].trace_accepted_steps != 0 ||
|
||||||
|
v2loaded.frames[0].mesh.vertices[0].trace_rhs_evaluations != 0) {
|
||||||
|
fputs("lens-map v2 legacy import regression failed\n", stderr);
|
||||||
|
free(v2_hdr); free(live_hdr); lens_map_destroy(&v2loaded);
|
||||||
|
unlink(v2_path); goto done;
|
||||||
|
}
|
||||||
|
const size_t live_images = frame_splat_catalog(
|
||||||
|
&mesh, &catalog, live_hdr, width, height, test_exposure, &psf, NULL,
|
||||||
|
INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1,
|
||||||
|
FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
const size_t v2_images = frame_splat_catalog(
|
||||||
|
&v2loaded.frames[0].mesh, &catalog, v2_hdr, width, height,
|
||||||
|
test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1,
|
||||||
|
FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL);
|
||||||
|
int render_equal = live_images == v2_images && live_images == images;
|
||||||
|
for (int k = 0; render_equal && k < width * height * 3; ++k)
|
||||||
|
if (live_hdr[k] != v2_hdr[k]) render_equal = 0;
|
||||||
|
free(v2_hdr); free(live_hdr);
|
||||||
|
lens_map_destroy(&v2loaded); unlink(v2_path);
|
||||||
|
if (!render_equal) {
|
||||||
|
fputs("lens-map v2 legacy render mismatch regression failed\n", stderr);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
result = 0;
|
result = 0;
|
||||||
done:
|
done:
|
||||||
frame_lens_mesh_destroy(&mesh);
|
frame_lens_mesh_destroy(&mesh);
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -208,6 +208,59 @@ Movie rays from all frames share a newest-to-oldest coordinate-time sweep.
|
|||||||
backends use logical slabs without metric I/O; [Nmesh](https://github.com/nmeshsource/nmesh) metric loading remains
|
backends use logical slabs without metric I/O; [Nmesh](https://github.com/nmeshsource/nmesh) metric loading remains
|
||||||
future work.
|
future work.
|
||||||
|
|
||||||
|
## Geodesic integration and tracing budgets
|
||||||
|
|
||||||
|
The default `--integrator dp54` selects adaptive Dormand–Prince 5(4). Position, photon
|
||||||
|
direction/momentum, and log-energy errors have separate absolute tolerances:
|
||||||
|
|
||||||
|
```text
|
||||||
|
--ode-rtol R
|
||||||
|
--ode-atol-x X
|
||||||
|
--ode-atol-pi P
|
||||||
|
--ode-atol-l L
|
||||||
|
--ode-initial-step H
|
||||||
|
--ode-min-step HMIN
|
||||||
|
--ode-max-step HMAX
|
||||||
|
--ode-max-rejections N
|
||||||
|
```
|
||||||
|
|
||||||
|
All tolerance and step values must be finite and positive; the initial step
|
||||||
|
must lie between the step bounds. The position absolute tolerance has the
|
||||||
|
backend's coordinate-length units. Smaller tolerances control local ODE error,
|
||||||
|
not a guaranteed bound on final sky-direction or image error near critical rays.
|
||||||
|
|
||||||
|
Default minimum steps are `1e-12` in Minkowski and Schwarzschild (`M=1`), and
|
||||||
|
`1e-12 * R` in Alcubierre. This is a conservative numerical guard, not a measured
|
||||||
|
physical minimum. Default maximum steps are `16`, `8M`, and eight times
|
||||||
|
`min(0.1, 0.05/sigma)`, respectively. Schwarzschild starts at `0.1M`; increasing
|
||||||
|
the upper bound does not force large steps through strong-field regions.
|
||||||
|
Use tolerance convergence for near-critical rays rather than interpreting the
|
||||||
|
upper bound as a global accuracy guarantee. See the bounded
|
||||||
|
[step-bound experiments](benchmarks/adaptive_step_bounds_2026-10-05/README.md).
|
||||||
|
|
||||||
|
Tracing has independent accepted-step and coordinate-time budgets:
|
||||||
|
|
||||||
|
```text
|
||||||
|
--trace-max-steps N
|
||||||
|
--trace-lookback-time T
|
||||||
|
--retry-step-increment N
|
||||||
|
--max-total-steps N
|
||||||
|
--retry-lookback-increment T
|
||||||
|
--max-total-lookback-time T
|
||||||
|
```
|
||||||
|
|
||||||
|
Changing the accepted-step allowance does not change the time allowance. A
|
||||||
|
trustworthy ray that exhausts either allowance is unresolved and can be resumed
|
||||||
|
by refinement with additional resources; it is not a physical dark endpoint.
|
||||||
|
Retries keep the last accepted state and camera energy reference, without
|
||||||
|
relaxing numerical tolerances. A hard limit that prevents a required retry
|
||||||
|
blocks normal output; `--allow-incomplete` is a diagnostic override.
|
||||||
|
|
||||||
|
`--integrator rk4` retains the fixed-step comparison path. Adaptive-only
|
||||||
|
tolerances and time-budget overrides are not applicable to that path. Use an
|
||||||
|
explicit stepper when reproducing a fixed-step reference rather than relying
|
||||||
|
on the executable's default.
|
||||||
|
|
||||||
## Reuse a completed lens map
|
## Reuse a completed lens map
|
||||||
|
|
||||||
`--lens-map-output FILE` saves the finalized inverse-lens mesh after tracing
|
`--lens-map-output FILE` saves the finalized inverse-lens mesh after tracing
|
||||||
@@ -237,6 +290,13 @@ on import. Explicit conflicting dimensions or FOV are rejected. The reader
|
|||||||
checks the format version, finite values, unit directions, triangle indices,
|
checks the format version, finite values, unit directions, triangle indices,
|
||||||
and per-frame CRCs.
|
and per-frame CRCs.
|
||||||
|
|
||||||
|
The map also records the stepper, numerical tolerances and step bounds, tracing
|
||||||
|
and retry allowances, and accepted/rejected/RHS costs. Replay uses this saved
|
||||||
|
provenance; tracing-option overrides are rejected because replay does not
|
||||||
|
integrate rays. Version 3 preserves adaptive provenance. Version 2 imports as
|
||||||
|
fixed RK4 with unavailable adaptive fields and cost diagnostics; version 1 is
|
||||||
|
rejected because its capture semantics cannot be reconstructed reliably.
|
||||||
|
|
||||||
A movie export stores all final frame meshes in one file. To render it again,
|
A movie export stores all final frame meshes in one file. To render it again,
|
||||||
pass `--lens-map-input FILE`, the catalog, `--frames-dir DIR`, and
|
pass `--lens-map-input FILE`, the catalog, `--frames-dir DIR`, and
|
||||||
`--frames-prefix NAME`; no observer track is needed on import.
|
`--frames-prefix NAME`; no observer track is needed on import.
|
||||||
|
|||||||
Reference in new issue
Block a user