Feat: Rework ray termination into escaped/dark/unresolved/incomplete

Replace the position capture cutoff with a camera-relative dark threshold
shared by every backend, and carry explicit outcome/reason provenance
through the ray, RayPool, adaptive mesh, lens-map and replay paths.

- eval/eval_slab return SpacetimePointStatus; remove SPACETIME_RAY_CAPTURED
  and the Schwarzschild capture radius; decouple observer construction from
  ray position.
- RayEndpoint stores RayOutcome/RayReason plus the last trusted state;
  budget exhaustion is retryable UNRESOLVED, data/integration failures are
  INCOMPLETE.
- Normal dark terminal is L - L0 >= --dark-threshold (default 8), with L0
  taken at the camera event and kept distinct from the worldtube entry
  energy; photon energy and frequency ratio are never reset.
- Implement E/D/U triangle decisions with merged budget retries, persistent
  probe witnesses promoted in place by vertex identity, conformity settling,
  and approximate-black boundary provenance with achieved-scale statistics.
- Add RayPool continuation state and per-ray step budgets.
- Bump lens-map to v2 with explicit end/outcome/reason, approx_black,
  threshold/retry/geometry provenance and per-frame retry counts; reject v1.
- Gate production output on incomplete/error results, overridable with
  --allow-incomplete.
- Update AGENTS.md, the design document and usage docs; add the termination
  oracle and regression coverage.

make -B -j4 BUILD_TYPE=Debug test passes with bit-identical reference HDRs.
This commit is contained in:
wyj committed 2026-10-05 06:22:47 -04:00
1 parent 7fde49308b
commit f7380cbf75
31 files changed
+2349 -402

No files matched your search

+99 -33
View File
@@ -14,10 +14,9 @@
- 让平直时空、解析时空、数值时空在同一渲染框架中作为可替换 backend;
- 最终能够“看到”每次 NR 代码实际跑出来的时空,而不是只看 waveform 或标量诊断。
第一阶段不考虑物质辐射、吸积盘、流体、等离子体等局域发射源。每条 ray 的终点暂时只有两类:
1. 被黑洞捕获;
2. 到达无穷远天球。
第一阶段不考虑物质辐射、吸积盘、流体、等离子体等局域发射源。每条 ray 的正常终点
为:逃逸到某个无穷远天球,或达到红移暗阈值。预算耗尽与数据/积分失败是单独的
`UNRESOLVED` / `INCOMPLETE` 类别,不与物理暗终态混同(见 §18)。
---
@@ -79,7 +78,7 @@ C++ 并不是当前项目的必要条件。需要的抽象主要可以通过:
4. 将这些 rays 组成一个全局 `RayPool`;
5. 从视频结束时刻向过去,按 time slab 顺序加载数值时空;
6. 在每个 slab 内,把所有 active rays 一起推进到 slab 左边界;
7. ray 若到达无穷远或进入黑洞,则立即终止;
7. ray 若在某个渐近端逃逸、达到红移暗阈值、耗尽预算或遇到数据/积分失败,则按类别终止;
8. 一轮 ray tracing 完成后,把 endpoint 数据回填到各帧 image mesh;
9. 根据局部 lens mapping 误差判断哪些 image-plane triangles 需要进一步细分;
10. 生成下一批新增 rays;
@@ -116,7 +115,7 @@ Spacetime time-slab stream
│
▼
ray endpoint:
n∞, frequency shift, captured/escaped
n∞, frequency shift, end/outcome/reason
│
├──────────► next refinement pass
│
@@ -222,8 +221,8 @@ F^{-1}:\ \hat n_\infty \to (x,y)_\text{image}
每个 image-plane triangle 的三个顶点都保存:
- image-plane 坐标 `(x,y)`;
- ray 是否 escaped/captured;
- 若 escaped:无穷远方向 `n_inf`;
- ray 的终态类别 `ESCAPED`/`DARK`/`UNRESOLVED`/`INCOMPLETE` 及其 reason;
- 若 escaped:无穷远方向 `n_inf` 与所属 end;
- frequency shift / redshift accumulator。
示意:
@@ -235,7 +234,9 @@ typedef struct {
double n_inf[3];
double log_g;
uint8_t ray_status;
uint8_t outcome; /* ESCAPED / DARK / UNRESOLVED / INCOMPLETE */
uint8_t reason; /* REDSHIFT_LIMIT / BUDGET_EXHAUSTED / ... */
uint32_t end_id;
} LensVertex;
typedef struct {
@@ -417,8 +418,9 @@ $e'_3=-\sin\rho\,e_2+\cos\rho\,e_3$ 定义。
observer 构造只接收当地 metric 和已补全的参数,不加载 slab、不分类 ray。
调用方在昂贵的 catalog/PSF 初始化前验证相机及 backend 数据域。
现有 Schwarzschild cutoff 为 $r=1.5M$;相机必须在 cutoff 外,但允许在视界内。
此功能不改变捕获 cutoff 或向过去追踪的高红移终止条件。
相机合法性只由 metric 可用性、四速度 timelike、时间定向和 tetrad 正交归一决定;
视界内、旧 cutoff 内的相机都是正常渲染目标,位置本身不决定 ray 终态。
向过去追踪的高红移阈值截断仍正常生效(见 §18)。
单张相机参数与轨迹输入、lens-map 导入互斥;导入仍跳过 metric 与 observer 初始化。
验证包括 tetrad 正交归一和 null 初始化、平直时空平移不变性与解析光行差/多普勒、
@@ -708,27 +710,72 @@ slab 边界需要少量 overlapping temporal ghost slices。
---
# 18. 黑洞捕获判据
# 18. 黑洞终止与暗终态
目标使用 moving-puncture BBH,而不是 excision。
目标使用 moving-puncture BBH,而不是 excision。正常终态**不使用** horizon 内位置
cutoff、AH-calibrated puncture 小球或 armed/re-entry 状态机判定物理捕获。过去向光线
围绕渐近端逃逸、能量阈值截断和经可靠识别的渐近轨道组织;达到红移阈值后停止、渲染
为黑,是已确定需求。
production renderer 不希望依赖每次 NR run 都开启昂贵的 AH finder。
计划:
1. 用低分辨率 single-BH / BBH calibration run 开 AH finder;
2. 测量 horizon 相对于 puncture 的最小 coordinate radius;
3. 选择明显保守、始终位于 AH 内部的 puncture-centered cutoff;
4. 正式 renderer 只根据 puncture trajectory 做判断。
形式:
形式(相机相对局域能量增长,对全部 backend 统一;具体阈值通过小型
oracle/convergence test 标定,不宣称由论文给定):
\[
|\mathbf x-\mathbf x_p(t)|<r_\text{cut}
\Rightarrow \text{captured}
L-L_0=\ln\!\frac{\alpha p^0}{(\alpha p^0)_0}\ge L_\text{dark}
\Rightarrow \text{DARK (redshift limit)}
\]
未来 BBH merger 后若仅用两个 puncture-centered 小球导致大量 doomed rays 继续积分,可以再加入 common-horizon-derived termination 优化。
`L_0` 是相机事件的参考值,对全部 spacetime backend 生效,并随 ray 状态跨 slab 与
retry 传递;减去 `L_0` 只改变判据参考,不重置光子能量或频率比 `g`。必须区分 `L`
(Eulerian 能量对数)、`ln(p^0)=L-ln(alpha)` 和真正连接源端得到的
`g=E_camera/E_source`。当前默认 `L_dark=8`,由 CLI 参数覆盖,不宣称为论文值。
终态分为四类(详见 §18A 与终点协议):
- `ESCAPED`:成功完成某个 end 的外推,必须带有效 `end_id`、`n_infinity`、`g`;
- `DARK`:无天空贡献的暗终态,当前主要为红移阈值截断 `REDSHIFT_LIMIT`;不同 dark
reason 不制造 mesh seam;
- `UNRESOLVED/BUDGET_EXHAUSTED`:轨迹仍可信但计算预算用尽,可重试;
- `INCOMPLETE/FAILED`:历史耗尽、域外、invalid metric、I/O、积分误差不可控、
unsupported chart 或 protocol error;不得伪装成 dark。
数值失败、单次 metric eval failure 或单个超阈值 trial step 均不得推断为物理 capture;
阈值只检查可信的初始或 accepted 状态。`ASYMPTOTIC_TRAPPED` 与 `SINGULARITY` 仅在存在
可靠 backend 判据及明确源边界条件时启用。有限几何分辨率导致的 shadow 略偏大与未解析
高阶像尾部由三角形近似处理,并保留 triangle provenance 与面积统计;这属于渲染近似,
不是物理捕获。跨 chart、跨 region 或穿越视界本身不是暗终态;moving-puncture trumpet
不解释成可穿越的第二个宇宙。production renderer 不假定每次 NR run 都运行昂贵的 AH
finder,也不依赖 capture sidecar。
解析 Schwarzschild 的 policy version 3 使用相机相对局域能量增长
\[
A_0 = L - L_0 \ge L_\text{dark}.
\]
`L_0` 是该 ray 积分起点的参考值,随 ray 状态跨 slab 与 retry 携带,不在每次
检查时用即时状态重算,也不重置光子能量或 frequency ratio。Eulerian 观者测得
的能量为 `e^L`,故 `A_0 = ln(E_euler/E_euler,0)`;一个常数相机 boost 在减法中
抵消,因此大 boost 或内部相机不会仅因初始 `L` 大而被判暗。这正是与视界无限
红移对应的局域相对量。对静止时空,理论上也可用 Killing 相对量
`A_K = L - ln|E_K|`,但沿精确光线 `A_K - A_0 = -ln|alpha_0 - beta_0.Pi_0|`
只是初始常数,不能仅凭守恒证明其优于 `A_0`;该 stationary 参考作为独立对照保留
在 `test_termination_oracle.c`,不进入生产判据,也不移植到动态 NR。阈值
`L_dark=8` 仍是待标定参数;生产条件不含绝对 `L` 或 backend applicability
guard。
所有 midpoint probes 同样属于完成性检查范围。失败/未决 probe 保存为 off-mesh
witness;未决 witness 合并到下一轮续追请求,完成 witness 可复用。重试回填使相关
叶子决策失效,不能借用其他叶子的 `evaluated` 标记跳过新出现的边界。最大层数、
最长边和面积共用同一停止判据;近似标黑统计报告实际最大边长、最大面积及层数停止
数量。Replay 使用文件保存的几何策略进行同样的完成性检查,诊断覆盖必须报告
`INCOMPLETE`,不得绕过发布 gate。conformity/几何限制取消全部请求边的 triangle
必须显式 settle(记录 `evaluated`),不得每代重复请求同一组 probes;被取消而
几何仍允许的 UUD/UDD 结算为 budget-incomplete,达到停止尺度的结算为近似标黑。
witness 提升为正式 midpoint 时原地复用同一 vertex id,只保留一份连续状态;只有
真正 off-mesh 的未决 witness 独立重试。lens-map 每帧保存累计 `retry_requests`,
provenance 保存 coordinate-time step 与初始 step 预算,使实际积分来源与成本可
replay。
---
@@ -963,6 +1010,21 @@ residual、Chebyshev 表或解析主项;运行期不得建表。
- generic accelerated driver 的初始条件同样用 $F<0$,或 $F=0$ 且
$\mathrm dF/\mathrm ds<0$ 才计为 entry;搜索只用严格 $F<0$ 的采样点确认
entry,单点 $F=0$ 切触不算。
- 终态契约已升级为两组枚举:渲染类别 `ESCAPED/DARK/UNRESOLVED/INCOMPLETE`
与诊断 reason。位置 cutoff 与 `SPACETIME_RAY_CAPTURED` 已删除;正常暗终态为
相机相对局域能量增长 `L - L0 >= L_dark`(默认 `L_dark=8`,可用
`--dark-threshold` 覆盖,对全部 spacetime backend 统一生效)。计算配额耗尽
返回可重试的 `UNRESOLVED/BUDGET_EXHAUSTED`,
保留最后可信连续状态;数据/积分/历史耗尽返回具体 `INCOMPLETE` reason。
- `eval`/`eval_slab` 返回 `SpacetimePointStatus`(时间不足、域外、invalid
metric、内部错误);observer 合法性只由 metric 可用性、timelike 四速度、
时间定向和 tetrad 正交归一决定,不再调用位置分类。
- 三角形决策实现 $E/D/U$ 账目:`UUU` 与含逃逸顶点的未决组合强制追加预算重试;
`UUD/UDD` 在几何停止尺度处近似标黑并记录 image-plane 面积与 triangle
provenance;含 `INCOMPLETE` 的三角形计为错误,不参与近似标黑。总资源上限
耗尽而未决时报告 incomplete,诊断可用 `--allow-incomplete` 覆盖。
- lens-map 文件格式升级为 v2:显式存储 `end_id/outcome/reason`、triangle
`approx_black` 以及 policy/retry/几何阈值 provenance;v1 文件被明确拒绝。
## 18A.11 $M>0$ 解析外区:闭式约化与验证
@@ -1707,7 +1769,9 @@ void rays_trace_generation(
- metric interpolation;
- spatial derivatives;
- 必要的 temporal derivatives;
- capture/infinity classification。
- metric/data 状态(成功、时间不足、空间域不足、invalid metric、内部错误);
- 渐近端声明与 escape worldtube 能力。物理暗终态由能量阈值 policy 判定,不由
位置分类决定。
---
@@ -1811,7 +1875,7 @@ map 共用同一入口。每个 RGB 通道独立、各向同性地把超过有
验证:
- capture;
- 红移暗阈值截断与 shadow;
- Einstein ring;
- multiple images;
- adaptive refinement;
@@ -1839,7 +1903,7 @@ map 共用同一入口。每个 RGB 通道独立、各向同性地把超过有
\quad
g,
\quad
\text{captured/escaped classification}
\text{end/outcome classification}
\]
---
@@ -1868,7 +1932,7 @@ renderer 顶层架构原则上不应为 BBH 重新设计。
- time slab 最佳内存大小;
- BBH production node 数;
- 4D 输出总数据量;
- AH calibration 后 puncture cutoff;
- 相机相对能量阈值 `L-L0` 的默认值标定(当前 `L_dark=8`,可 CLI 覆盖);
- adaptive triangle refinement criterion;
- critical curve 附近最大 refinement level;
- Gaia 与 2MASS 的最终组合;
@@ -1879,7 +1943,9 @@ renderer 顶层架构原则上不应为 BBH 重新设计。
Reinhard 作为兼容模式保留;最终 production color management、传感器模型、
曝光标定和 HDR 视频编码规则仍未决定;
- 是否需要 diffuse Milky Way background;
- 是否将 ray redshift 变量定义为 `log(alpha p^0)` 或其他更方便的量。
- 阈值监测量当前统一采用相机相对增长 `L-L0`(对全部 backend 生效),不再使用
绝对 `L`、`ln(p^0)` 或 Killing 相对量;这些量均不得与真正的 infinity
`g=E_camera/E_source` 混同。
---
@@ -1917,8 +1983,8 @@ $e_{(0)}=u$ 同时满足自由落体方程;四加速度为零时费米–沃
DOP853 默认 rtol=$10^{-10}$、atol=$10^{-12}$,可配置并通过解析径向自由落体、
圆轨道和圆轨道平行输运的收敛回归验证。视界不终止相机;默认 $r=10^{-3}M$
只是可配置的奇点数值保护边界,不等于精确撞击奇点。它独立于光线的 $1.5M$
捕获 cutoff;该 cutoff 内的轨迹可输出,但当前 renderer 的光线会立即被捕获。
只是可配置的奇点数值保护边界,不等于精确撞击奇点。相机轨迹与光线终态解耦:
相机合法性与位置 cutoff 无关,光线正常暗终态由 §18 的能量阈值 policy 决定。
CSV 保持 21 列不变,记录 $\tau=k/\mathrm{fps}$ 与积分得到的真实坐标时间。
只保留不超过请求持续本征时或提前终止时刻的规则采样,包含 $\tau=0$。