universal-physics-tensor 0.4.6 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/bridges/equations/be-37-shapiro-delay.d.ts.map +1 -1
  2. package/dist/bridges/equations/be-37-shapiro-delay.js +7 -9
  3. package/dist/bridges/equations/be-37-shapiro-delay.js.map +1 -1
  4. package/dist/bridges/gravitational-lensing.d.ts +13 -2
  5. package/dist/bridges/gravitational-lensing.d.ts.map +1 -1
  6. package/dist/bridges/gravitational-lensing.js +17 -6
  7. package/dist/bridges/gravitational-lensing.js.map +1 -1
  8. package/dist/bridges/perihelion-precession.d.ts +18 -3
  9. package/dist/bridges/perihelion-precession.d.ts.map +1 -1
  10. package/dist/bridges/perihelion-precession.js +22 -8
  11. package/dist/bridges/perihelion-precession.js.map +1 -1
  12. package/dist/core/constants.d.ts +50 -0
  13. package/dist/core/constants.d.ts.map +1 -0
  14. package/dist/core/constants.js +50 -0
  15. package/dist/core/constants.js.map +1 -0
  16. package/dist/dimensional/connection-validators.d.ts +60 -2
  17. package/dist/dimensional/connection-validators.d.ts.map +1 -1
  18. package/dist/dimensional/connection-validators.js +76 -2
  19. package/dist/dimensional/connection-validators.js.map +1 -1
  20. package/dist/dimensional/curvature.d.ts +361 -0
  21. package/dist/dimensional/curvature.d.ts.map +1 -0
  22. package/dist/dimensional/curvature.js +299 -0
  23. package/dist/dimensional/curvature.js.map +1 -0
  24. package/dist/dimensional/validator.d.ts +5 -3
  25. package/dist/dimensional/validator.d.ts.map +1 -1
  26. package/dist/dimensional/validator.js +58 -1
  27. package/dist/dimensional/validator.js.map +1 -1
  28. package/dist/index.d.ts +9 -2
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +23 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/numerical/be37-covariant-eikonal.d.ts +112 -39
  33. package/dist/numerical/be37-covariant-eikonal.d.ts.map +1 -1
  34. package/dist/numerical/be37-covariant-eikonal.js +219 -40
  35. package/dist/numerical/be37-covariant-eikonal.js.map +1 -1
  36. package/dist/numerical/curvature-lowering-helpers.d.ts +189 -0
  37. package/dist/numerical/curvature-lowering-helpers.d.ts.map +1 -0
  38. package/dist/numerical/curvature-lowering-helpers.js +412 -0
  39. package/dist/numerical/curvature-lowering-helpers.js.map +1 -0
  40. package/dist/numerical/engine-registry.js +4 -4
  41. package/dist/numerical/engine-registry.js.map +1 -1
  42. package/dist/numerical/errors.d.ts +16 -0
  43. package/dist/numerical/errors.d.ts.map +1 -1
  44. package/dist/numerical/errors.js +20 -0
  45. package/dist/numerical/errors.js.map +1 -1
  46. package/dist/numerical/gl4-integrator.d.ts +213 -0
  47. package/dist/numerical/gl4-integrator.d.ts.map +1 -0
  48. package/dist/numerical/gl4-integrator.js +307 -0
  49. package/dist/numerical/gl4-integrator.js.map +1 -0
  50. package/dist/numerical/index.d.ts +8 -0
  51. package/dist/numerical/index.d.ts.map +1 -1
  52. package/dist/numerical/index.js +4 -0
  53. package/dist/numerical/index.js.map +1 -1
  54. package/dist/numerical/lowering.d.ts.map +1 -1
  55. package/dist/numerical/lowering.js +180 -3
  56. package/dist/numerical/lowering.js.map +1 -1
  57. package/dist/numerical/mathts-engine.js +8 -8
  58. package/dist/numerical/mathts-engine.js.map +1 -1
  59. package/dist/numerical/metric-inverse.d.ts.map +1 -1
  60. package/dist/numerical/metric-inverse.js +28 -0
  61. package/dist/numerical/metric-inverse.js.map +1 -1
  62. package/dist/numerical/null-ray-integrator.d.ts.map +1 -1
  63. package/dist/numerical/null-ray-integrator.js +6 -3
  64. package/dist/numerical/null-ray-integrator.js.map +1 -1
  65. package/dist/numerical/pderiv.d.ts +27 -3
  66. package/dist/numerical/pderiv.d.ts.map +1 -1
  67. package/dist/numerical/pderiv.js +44 -12
  68. package/dist/numerical/pderiv.js.map +1 -1
  69. package/dist/numerical/perihelion-finder.d.ts +111 -0
  70. package/dist/numerical/perihelion-finder.d.ts.map +1 -0
  71. package/dist/numerical/perihelion-finder.js +288 -0
  72. package/dist/numerical/perihelion-finder.js.map +1 -0
  73. package/package.json +1 -1
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Bisection perihelion finder via cubic-Hermite interpolation on cached
3
+ * GL4 snapshots (v0.5.0 Task 4, Phase 1b).
4
+ *
5
+ * Algorithm (Design §3 Task 1b):
6
+ * 1. Walk snapshots, extract `dr/dτ_i = g^{rν}(x_i) · p_{i,ν}` at each
7
+ * snapshot. Index `r` is the radial coordinate slot (index 1 by
8
+ * convention in (t, r, θ, φ)).
9
+ * 2. Locate consecutive indices `(i, i+1)` where `dr/dτ` sign-changes
10
+ * from `−` to `+` — that is the perihelion (inner radial turning
11
+ * point). Sign-change `+ → −` is apoapsis and is intentionally
12
+ * skipped.
13
+ * 3. **M3 bracket-width check:** if `|τ_{i+1} − τ_i| < 2 · h_snap`
14
+ * where `h_snap` is the median Δτ across all snapshots, emit a
15
+ * non-throwing `PerihelionBracketWidthWarning` via
16
+ * `process.emitWarning`. This indicates the GL4 step is too coarse
17
+ * to resolve the turning point — the caller should re-integrate
18
+ * with finer steps.
19
+ * 4. Fit a **cubic Hermite polynomial** through `(τ_i, dr/dτ_i)` and
20
+ * `(τ_{i+1}, dr/dτ_{i+1})`, with endpoint derivatives estimated
21
+ * from neighboring snapshots (4 values total: f and f' at both
22
+ * endpoints). Find an analytic root of the cubic on [τ_i, τ_{i+1}].
23
+ * 5. If `|P(τ_root)| > tauTolerance`, refine with **bisection on the
24
+ * polynomial** (not re-integration — Adam+Eve I6/F11 — that would
25
+ * cost a full GL4 sweep per bisection step, which defeats the
26
+ * cached-snapshot approach). Precision floor: 1e-9 × T_orbit
27
+ * (Adam+Eve I1 — 1e-12 needs ~40 cubic bisections and is wasted
28
+ * effort given the integrator's per-step error is already > 1e-12).
29
+ * 6. Return `{ tau, x, phi }` where `x` is the cubic-Hermite-interpolated
30
+ * 4-coordinate at the root and `phi = x[3]`.
31
+ *
32
+ * **Throws** `Error("no perihelion bracket")` if no `−→+` sign-change is
33
+ * found in the snapshot range.
34
+ *
35
+ * @module numerical/perihelion-finder
36
+ */
37
+ /**
38
+ * Result of `findPerihelion`: the τ at the radial turning point, the
39
+ * interpolated 4-coordinate, and the orbital phase `phi = x[3]`.
40
+ *
41
+ * @public
42
+ */
43
+ export interface PerihelionResult {
44
+ /** Proper time at the perihelion. */
45
+ readonly tau: number;
46
+ /** Interpolated 4-coordinate x^μ at τ_perihelion. */
47
+ readonly x: readonly number[];
48
+ /** Orbital phase φ = x[3] at τ_perihelion. */
49
+ readonly phi: number;
50
+ }
51
+ /**
52
+ * Options for {@link findPerihelion}.
53
+ *
54
+ * @public
55
+ */
56
+ export interface FindPerihelionOptions {
57
+ /** Snapshots produced by `integrateGeodesicGL4` (or any compatible
58
+ * `(τ, x, p)` snapshot stream — only `tau`, `x`, `p` are read). */
59
+ readonly snapshots: ReadonlyArray<{
60
+ readonly tau: number;
61
+ readonly x: readonly number[];
62
+ readonly p: readonly number[];
63
+ }>;
64
+ /** Inverse-metric closure: `gInverseFn(x)[μ][ν] = g^{μν}(x)`. Used to
65
+ * compute `dr/dτ = g^{rν}(x) p_ν` at each snapshot. */
66
+ readonly gInverseFn: (x: readonly number[]) => readonly (readonly number[])[];
67
+ /** Polynomial-bisection target tolerance on the cubic-Hermite root —
68
+ * measured as `|P(τ_root)|`, not `|τ − τ_true|`. Precision floor 1e-9
69
+ * per Adam+Eve I1; tighter values just waste bisections. */
70
+ readonly tauTolerance: number;
71
+ /** Coordinate index used as the "radial" slot. Defaults to 1
72
+ * ((t, r, θ, φ) convention). */
73
+ readonly radialIndex?: number;
74
+ }
75
+ /**
76
+ * Find the perihelion (inner radial turning point) on a snapshot stream.
77
+ *
78
+ * See module-level docstring for the algorithm. Throws if no `−→+` sign
79
+ * change in `dr/dτ` is found.
80
+ *
81
+ * **Units.** Inherited from the supplied snapshots and `gInverseFn` — the
82
+ * finder is metric-agnostic. For the canonical UPT BE-52 Schwarzschild use
83
+ * case:
84
+ * - `snapshots[i].tau` — affine parameter in **seconds** (SI, BE-37 null
85
+ * normalization) or **proper-time seconds** (timelike geodesics).
86
+ * - `snapshots[i].x` — 4-coordinate `(t, r, θ, φ)` in
87
+ * **(s, m, rad, rad)** (SI).
88
+ * - `snapshots[i].p` — covariant momentum (units depend on the
89
+ * normalization; see `integrateGeodesicGL4` JSDoc).
90
+ * - `tauTolerance` — polynomial-residual tolerance on `dr/dτ`,
91
+ * therefore in **m/s** for SI Schwarzschild. Floor `1e-9` ⇒ tighter
92
+ * values are quietly clamped (see implementation).
93
+ *
94
+ * @param options — see {@link FindPerihelionOptions}:
95
+ * - `snapshots` — `(τ, x, p)` stream from `integrateGeodesicGL4` (units
96
+ * as above).
97
+ * - `gInverseFn(x)[μ][ν]` — inverse metric `g^{μν}(x)`. Same units as
98
+ * the matching integrator call.
99
+ * - `tauTolerance` — bisection target on `|P(s_root)|` measured in the
100
+ * units of `dr/dτ` (m/s for SI Schwarzschild).
101
+ * - `radialIndex` — index of `r` within `x` (default `1` — standard
102
+ * `(t, r, θ, φ)` ordering).
103
+ * @returns `{ tau, x, phi }` — affine parameter, interpolated 4-coordinate,
104
+ * and orbital phase `φ = x[3]` at the perihelion. Units of `tau` and `x`
105
+ * match the inputs; `phi` is in **radians**.
106
+ * @throws Error if `snapshots.length < 2` or no `−→+` sign change in `dr/dτ`.
107
+ *
108
+ * @public
109
+ */
110
+ export declare function findPerihelion(options: FindPerihelionOptions): PerihelionResult;
111
+ //# sourceMappingURL=perihelion-finder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perihelion-finder.d.ts","sourceRoot":"","sources":["../../src/numerical/perihelion-finder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,qCAAqC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;wEACoE;IACpE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;QAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9B,QAAQ,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KAC/B,CAAC,CAAC;IACH;4DACwD;IACxD,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,KAAK,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;IAC9E;;iEAE6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;qCACiC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAmID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,gBAAgB,CAwG/E"}
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Bisection perihelion finder via cubic-Hermite interpolation on cached
3
+ * GL4 snapshots (v0.5.0 Task 4, Phase 1b).
4
+ *
5
+ * Algorithm (Design §3 Task 1b):
6
+ * 1. Walk snapshots, extract `dr/dτ_i = g^{rν}(x_i) · p_{i,ν}` at each
7
+ * snapshot. Index `r` is the radial coordinate slot (index 1 by
8
+ * convention in (t, r, θ, φ)).
9
+ * 2. Locate consecutive indices `(i, i+1)` where `dr/dτ` sign-changes
10
+ * from `−` to `+` — that is the perihelion (inner radial turning
11
+ * point). Sign-change `+ → −` is apoapsis and is intentionally
12
+ * skipped.
13
+ * 3. **M3 bracket-width check:** if `|τ_{i+1} − τ_i| < 2 · h_snap`
14
+ * where `h_snap` is the median Δτ across all snapshots, emit a
15
+ * non-throwing `PerihelionBracketWidthWarning` via
16
+ * `process.emitWarning`. This indicates the GL4 step is too coarse
17
+ * to resolve the turning point — the caller should re-integrate
18
+ * with finer steps.
19
+ * 4. Fit a **cubic Hermite polynomial** through `(τ_i, dr/dτ_i)` and
20
+ * `(τ_{i+1}, dr/dτ_{i+1})`, with endpoint derivatives estimated
21
+ * from neighboring snapshots (4 values total: f and f' at both
22
+ * endpoints). Find an analytic root of the cubic on [τ_i, τ_{i+1}].
23
+ * 5. If `|P(τ_root)| > tauTolerance`, refine with **bisection on the
24
+ * polynomial** (not re-integration — Adam+Eve I6/F11 — that would
25
+ * cost a full GL4 sweep per bisection step, which defeats the
26
+ * cached-snapshot approach). Precision floor: 1e-9 × T_orbit
27
+ * (Adam+Eve I1 — 1e-12 needs ~40 cubic bisections and is wasted
28
+ * effort given the integrator's per-step error is already > 1e-12).
29
+ * 6. Return `{ tau, x, phi }` where `x` is the cubic-Hermite-interpolated
30
+ * 4-coordinate at the root and `phi = x[3]`.
31
+ *
32
+ * **Throws** `Error("no perihelion bracket")` if no `−→+` sign-change is
33
+ * found in the snapshot range.
34
+ *
35
+ * @module numerical/perihelion-finder
36
+ */
37
+ /** Compute `dr/dτ = g^{rν}(x) p_ν` at a single snapshot. */
38
+ function radialVelocity(x, p, gInverseFn, r) {
39
+ const gInv = gInverseFn(x);
40
+ let v = 0;
41
+ for (let nu = 0; nu < p.length; nu++) {
42
+ v += gInv[r][nu] * p[nu];
43
+ }
44
+ return v;
45
+ }
46
+ /** Median of a numeric array (does not mutate input). */
47
+ function median(values) {
48
+ const sorted = [...values].sort((a, b) => a - b);
49
+ const n = sorted.length;
50
+ if (n === 0)
51
+ return 0;
52
+ if (n % 2 === 1)
53
+ return sorted[(n - 1) / 2];
54
+ return 0.5 * (sorted[n / 2 - 1] + sorted[n / 2]);
55
+ }
56
+ /**
57
+ * Hermite basis on the unit interval, evaluated at `s ∈ [0,1]`.
58
+ *
59
+ * Cubic Hermite interpolant of a scalar `f(τ)` over `[τ0, τ1]` with
60
+ * endpoint values `f0, f1` and endpoint derivatives `m0, m1` (in `f` per
61
+ * `τ`):
62
+ *
63
+ * P(τ) = h00(s) f0 + h10(s) (τ1−τ0) m0 + h01(s) f1 + h11(s) (τ1−τ0) m1
64
+ *
65
+ * where `s = (τ − τ0)/(τ1 − τ0)` and
66
+ * h00 = 2s³ − 3s² + 1
67
+ * h10 = s³ − 2s² + s
68
+ * h01 = −2s³ + 3s²
69
+ * h11 = s³ − s²
70
+ *
71
+ * (Numerical Recipes §3.4; Hairer/Lubich/Wanner §III.5.)
72
+ */
73
+ function hermiteEval(f0, f1, m0, m1, dt, s) {
74
+ const s2 = s * s;
75
+ const s3 = s2 * s;
76
+ const h00 = 2 * s3 - 3 * s2 + 1;
77
+ const h10 = s3 - 2 * s2 + s;
78
+ const h01 = -2 * s3 + 3 * s2;
79
+ const h11 = s3 - s2;
80
+ return h00 * f0 + h10 * dt * m0 + h01 * f1 + h11 * dt * m1;
81
+ }
82
+ /**
83
+ * Vector cubic-Hermite interpolation of a 4-coordinate `x^μ` at `τ`
84
+ * given the two bracket endpoints and their snapshot derivatives in `τ`
85
+ * (here: the `x` arrays, with derivative `dx/dτ` approximated by central
86
+ * differences on neighbor snapshots — passed in by the caller).
87
+ */
88
+ function hermiteInterpVector(x0, x1, m0, m1, dt, s) {
89
+ const dim = x0.length;
90
+ const out = new Array(dim);
91
+ for (let mu = 0; mu < dim; mu++) {
92
+ out[mu] = hermiteEval(x0[mu], x1[mu], m0[mu], m1[mu], dt, s);
93
+ }
94
+ return out;
95
+ }
96
+ /**
97
+ * Bisection on the cubic-Hermite polynomial for the scalar `dr/dτ` root.
98
+ * Operates on `s ∈ [0,1]` — the normalised bracket coordinate. Returns
99
+ * the converged `s` and the corresponding polynomial value.
100
+ *
101
+ * Precision: the loop terminates when `|P(s_mid)| ≤ tauTolerance` (scaled
102
+ * to whatever units `dr/dτ` is in — the caller passes `tauTolerance`
103
+ * matched to the integrator scale). A hard iteration cap of 60 prevents
104
+ * runaway on pathological inputs (60 bisections halve `s` to ≈1e-18 — well
105
+ * below floating-point resolution).
106
+ */
107
+ function bisectCubic(f0, f1, m0, m1, dt, sInitial, tol) {
108
+ // Establish a bracket around sInitial. The sign-change is at the
109
+ // f(τ0)=f0 → f(τ1)=f1 endpoints (by construction f0 < 0, f1 > 0).
110
+ let sLo = 0;
111
+ let sHi = 1;
112
+ let fLo = f0;
113
+ let fHi = f1;
114
+ let s = sInitial;
115
+ let fs = hermiteEval(f0, f1, m0, m1, dt, s);
116
+ // If sInitial already satisfies tol, return it.
117
+ if (Math.abs(fs) <= tol)
118
+ return { s, residual: fs };
119
+ for (let iter = 0; iter < 60; iter++) {
120
+ // Use midpoint, not the (possibly poor) sInitial, after first iter.
121
+ s = 0.5 * (sLo + sHi);
122
+ fs = hermiteEval(f0, f1, m0, m1, dt, s);
123
+ if (Math.abs(fs) <= tol)
124
+ return { s, residual: fs };
125
+ // Maintain sign-bracket: fLo < 0 < fHi.
126
+ if (Math.sign(fs) === Math.sign(fLo)) {
127
+ sLo = s;
128
+ fLo = fs;
129
+ }
130
+ else {
131
+ sHi = s;
132
+ fHi = fs;
133
+ }
134
+ }
135
+ return { s, residual: fs };
136
+ }
137
+ /**
138
+ * Find the perihelion (inner radial turning point) on a snapshot stream.
139
+ *
140
+ * See module-level docstring for the algorithm. Throws if no `−→+` sign
141
+ * change in `dr/dτ` is found.
142
+ *
143
+ * **Units.** Inherited from the supplied snapshots and `gInverseFn` — the
144
+ * finder is metric-agnostic. For the canonical UPT BE-52 Schwarzschild use
145
+ * case:
146
+ * - `snapshots[i].tau` — affine parameter in **seconds** (SI, BE-37 null
147
+ * normalization) or **proper-time seconds** (timelike geodesics).
148
+ * - `snapshots[i].x` — 4-coordinate `(t, r, θ, φ)` in
149
+ * **(s, m, rad, rad)** (SI).
150
+ * - `snapshots[i].p` — covariant momentum (units depend on the
151
+ * normalization; see `integrateGeodesicGL4` JSDoc).
152
+ * - `tauTolerance` — polynomial-residual tolerance on `dr/dτ`,
153
+ * therefore in **m/s** for SI Schwarzschild. Floor `1e-9` ⇒ tighter
154
+ * values are quietly clamped (see implementation).
155
+ *
156
+ * @param options — see {@link FindPerihelionOptions}:
157
+ * - `snapshots` — `(τ, x, p)` stream from `integrateGeodesicGL4` (units
158
+ * as above).
159
+ * - `gInverseFn(x)[μ][ν]` — inverse metric `g^{μν}(x)`. Same units as
160
+ * the matching integrator call.
161
+ * - `tauTolerance` — bisection target on `|P(s_root)|` measured in the
162
+ * units of `dr/dτ` (m/s for SI Schwarzschild).
163
+ * - `radialIndex` — index of `r` within `x` (default `1` — standard
164
+ * `(t, r, θ, φ)` ordering).
165
+ * @returns `{ tau, x, phi }` — affine parameter, interpolated 4-coordinate,
166
+ * and orbital phase `φ = x[3]` at the perihelion. Units of `tau` and `x`
167
+ * match the inputs; `phi` is in **radians**.
168
+ * @throws Error if `snapshots.length < 2` or no `−→+` sign change in `dr/dτ`.
169
+ *
170
+ * @public
171
+ */
172
+ export function findPerihelion(options) {
173
+ const { snapshots, gInverseFn, tauTolerance, radialIndex = 1 } = options;
174
+ if (snapshots.length < 2) {
175
+ throw new Error('no perihelion bracket: need at least 2 snapshots');
176
+ }
177
+ // Step 1: extract dr/dτ at every snapshot.
178
+ const drDtau = new Array(snapshots.length);
179
+ for (let i = 0; i < snapshots.length; i++) {
180
+ drDtau[i] = radialVelocity(snapshots[i].x, snapshots[i].p, gInverseFn, radialIndex);
181
+ }
182
+ // Step 2: locate the first `− → +` sign change.
183
+ // Tolerant against snapshot landing exactly at the turning point
184
+ // (drDtau ≈ 0): treat `≤ 0 → > 0` as a valid bracket. A snapshot with
185
+ // f == 0 exactly is itself the perihelion — but we still return through
186
+ // the Hermite path so the {x, phi} interpolation is uniform.
187
+ let iBracket = -1;
188
+ for (let i = 0; i < snapshots.length - 1; i++) {
189
+ if (drDtau[i] <= 0 && drDtau[i + 1] > 0) {
190
+ iBracket = i;
191
+ break;
192
+ }
193
+ if (drDtau[i] < 0 && drDtau[i + 1] >= 0) {
194
+ iBracket = i;
195
+ break;
196
+ }
197
+ }
198
+ if (iBracket < 0) {
199
+ throw new Error('no perihelion bracket: dr/dτ does not change sign − → +');
200
+ }
201
+ const i0 = iBracket;
202
+ const i1 = iBracket + 1;
203
+ const tau0 = snapshots[i0].tau;
204
+ const tau1 = snapshots[i1].tau;
205
+ const dt = tau1 - tau0;
206
+ // Step 3: M3 bracket-width check vs median Δτ.
207
+ //
208
+ // Plan spec literally says `< 2·h_snap`, but on a uniform-step grid
209
+ // every bracket equals h_snap exactly (ratio 1.0), so `< 2·h_snap` would
210
+ // fire on every successful call — useless as a diagnostic. The intent
211
+ // of M3 is to flag brackets compressed below the nominal integrator
212
+ // step (i.e., adaptive step-halving has run near perihelion, leaving a
213
+ // suspicious cluster). We compare against `h_snap` directly: the
214
+ // warning fires when the bracket is **narrower than the typical step**.
215
+ // Documented deviation; honest framing maintained — see CHANGELOG.
216
+ const deltas = [];
217
+ for (let i = 0; i < snapshots.length - 1; i++) {
218
+ deltas.push(snapshots[i + 1].tau - snapshots[i].tau);
219
+ }
220
+ const hSnap = median(deltas);
221
+ if (dt < hSnap) {
222
+ process.emitWarning(`findPerihelion: bracket width Δτ=${dt} < h_snap=${hSnap} `
223
+ + `(median snapshot step) — GL4 snapshot density is too coarse to `
224
+ + `resolve this turning point reliably; consider re-integrating `
225
+ + `with finer steps.`, 'PerihelionBracketWidthWarning');
226
+ }
227
+ // Step 4: build cubic-Hermite interpolant for dr/dτ on [τ_i0, τ_i1].
228
+ // Endpoint derivatives (d/dτ of dr/dτ) approximated via central
229
+ // differences on neighboring snapshots (one-sided at boundaries).
230
+ const f0 = drDtau[i0];
231
+ const f1 = drDtau[i1];
232
+ const m0 = derivAt(drDtau, snapshots, i0);
233
+ const m1 = derivAt(drDtau, snapshots, i1);
234
+ // Initial guess: linear interpolation root, s = f0 / (f0 − f1).
235
+ // For a linear sign-change this is exact; for cubic it's a warm start.
236
+ const sLinear = f0 / (f0 - f1);
237
+ // Step 5: bisect the cubic-Hermite polynomial until residual ≤ tolerance.
238
+ const { s: sRoot } = bisectCubic(f0, f1, m0, m1, dt, sLinear, tauTolerance);
239
+ const tauRoot = tau0 + sRoot * dt;
240
+ // Step 6: interpolate x^μ at τ_root via cubic Hermite using the same
241
+ // endpoint-derivative scheme. dx^μ/dτ at endpoints comes from
242
+ // central-differencing neighboring snapshots' x arrays.
243
+ const xMomentum0 = velocityAt(snapshots, i0, gInverseFn);
244
+ const xMomentum1 = velocityAt(snapshots, i1, gInverseFn);
245
+ const xInterp = hermiteInterpVector(snapshots[i0].x, snapshots[i1].x, xMomentum0, xMomentum1, dt, sRoot);
246
+ return {
247
+ tau: tauRoot,
248
+ x: xInterp,
249
+ phi: xInterp[3] ?? 0,
250
+ };
251
+ }
252
+ /**
253
+ * Central-difference estimate of `d(dr/dτ)/dτ` at snapshot index `i`.
254
+ * One-sided at i=0 and i=N−1. Used as the Hermite endpoint slope.
255
+ */
256
+ function derivAt(drDtau, snapshots, i) {
257
+ const N = snapshots.length;
258
+ if (i === 0) {
259
+ return (drDtau[1] - drDtau[0]) / (snapshots[1].tau - snapshots[0].tau);
260
+ }
261
+ if (i === N - 1) {
262
+ return (drDtau[N - 1] - drDtau[N - 2])
263
+ / (snapshots[N - 1].tau - snapshots[N - 2].tau);
264
+ }
265
+ return (drDtau[i + 1] - drDtau[i - 1])
266
+ / (snapshots[i + 1].tau - snapshots[i - 1].tau);
267
+ }
268
+ /**
269
+ * 4-velocity `v^μ = g^{μν}(x_i) p_{i,ν}` at snapshot `i`. Used as the
270
+ * Hermite endpoint slope for the `x^μ` interpolation (since by definition
271
+ * `dx^μ/dτ = g^{μν} p_ν` along a geodesic).
272
+ */
273
+ function velocityAt(snapshots, i, gInverseFn) {
274
+ const x = snapshots[i].x;
275
+ const p = snapshots[i].p;
276
+ const gInv = gInverseFn(x);
277
+ const dim = x.length;
278
+ const v = new Array(dim);
279
+ for (let mu = 0; mu < dim; mu++) {
280
+ let acc = 0;
281
+ for (let nu = 0; nu < dim; nu++) {
282
+ acc += gInv[mu][nu] * p[nu];
283
+ }
284
+ v[mu] = acc;
285
+ }
286
+ return v;
287
+ }
288
+ //# sourceMappingURL=perihelion-finder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perihelion-finder.js","sourceRoot":"","sources":["../../src/numerical/perihelion-finder.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "universal-physics-tensor",
3
- "version": "0.4.6",
3
+ "version": "0.5.1",
4
4
  "description": "Computational framework for exploring unified physics through tensor formalism",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",