universal-physics-tensor 1.0.4 → 2.0.0
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.
- package/README.md +6 -8
- package/dist/atlas/chain-pipeline.d.ts +37 -0
- package/dist/atlas/chain-pipeline.d.ts.map +1 -1
- package/dist/atlas/chain-pipeline.js +95 -79
- package/dist/atlas/chain-pipeline.js.map +1 -1
- package/dist/atlas/proof-target.d.ts +28 -2
- package/dist/atlas/proof-target.d.ts.map +1 -1
- package/dist/atlas/proof-target.js +25 -16
- package/dist/atlas/proof-target.js.map +1 -1
- package/dist/cli/commands/_atlas-route.d.ts +1 -1
- package/dist/cli/commands/atlas.d.ts.map +1 -1
- package/dist/cli/commands/atlas.js +1 -2
- package/dist/cli/commands/atlas.js.map +1 -1
- package/dist/cli/commands/eval.d.ts.map +1 -1
- package/dist/cli/commands/eval.js +7 -10
- package/dist/cli/commands/eval.js.map +1 -1
- package/dist/cli/commands/evaluate.d.ts +7 -3
- package/dist/cli/commands/evaluate.d.ts.map +1 -1
- package/dist/cli/commands/evaluate.js +53 -32
- package/dist/cli/commands/evaluate.js.map +1 -1
- package/dist/cli/commands/map.d.ts +1 -1
- package/dist/cli/commands/map.d.ts.map +1 -1
- package/dist/cli/commands/map.js.map +1 -1
- package/dist/cli/commands/metric.d.ts.map +1 -1
- package/dist/cli/commands/metric.js +10 -11
- package/dist/cli/commands/metric.js.map +1 -1
- package/dist/cli/commands/path.d.ts +2 -2
- package/dist/cli/commands/path.d.ts.map +1 -1
- package/dist/cli/commands/path.js +10 -11
- package/dist/cli/commands/path.js.map +1 -1
- package/dist/cli/commands/recover.d.ts.map +1 -1
- package/dist/cli/commands/recover.js +1 -2
- package/dist/cli/commands/recover.js.map +1 -1
- package/dist/cli/commands/regime.d.ts +2 -2
- package/dist/cli/commands/regime.d.ts.map +1 -1
- package/dist/cli/commands/regime.js +3 -4
- package/dist/cli/commands/regime.js.map +1 -1
- package/dist/cli/eval-numbers.d.ts +2 -2
- package/dist/cli/eval-numbers.js +2 -2
- package/dist/cli/version.d.ts +6 -2
- package/dist/cli/version.d.ts.map +1 -1
- package/dist/cli/version.js +11 -3
- package/dist/cli/version.js.map +1 -1
- package/dist/cli-api.d.ts +50 -0
- package/dist/cli-api.d.ts.map +1 -1
- package/dist/cli-api.js +42 -0
- package/dist/cli-api.js.map +1 -1
- package/dist/composition/chain-result.d.ts +55 -0
- package/dist/composition/chain-result.d.ts.map +1 -0
- package/dist/composition/chain-result.js +57 -0
- package/dist/composition/chain-result.js.map +1 -0
- package/dist/composition/compose-symbolic.d.ts.map +1 -1
- package/dist/composition/compose-symbolic.js +4 -39
- package/dist/composition/compose-symbolic.js.map +1 -1
- package/dist/composition/compose.d.ts.map +1 -1
- package/dist/composition/compose.js +11 -4
- package/dist/composition/compose.js.map +1 -1
- package/dist/composition/enumerate.d.ts +46 -5
- package/dist/composition/enumerate.d.ts.map +1 -1
- package/dist/composition/enumerate.js +37 -8
- package/dist/composition/enumerate.js.map +1 -1
- package/dist/composition/expr-simplify.d.ts.map +1 -1
- package/dist/composition/expr-simplify.js +3 -11
- package/dist/composition/expr-simplify.js.map +1 -1
- package/dist/composition/mathts-scalar-symbols.d.ts +48 -0
- package/dist/composition/mathts-scalar-symbols.d.ts.map +1 -0
- package/dist/composition/mathts-scalar-symbols.js +150 -0
- package/dist/composition/mathts-scalar-symbols.js.map +1 -0
- package/dist/composition/probe/study.js +1 -1
- package/dist/composition/probe/study.js.map +1 -1
- package/dist/composition/uncertainty.d.ts +2 -2
- package/dist/composition/uncertainty.d.ts.map +1 -1
- package/dist/composition/uncertainty.js +14 -13
- package/dist/composition/uncertainty.js.map +1 -1
- package/dist/diff/bridge-gradient.d.ts +5 -8
- package/dist/diff/bridge-gradient.d.ts.map +1 -1
- package/dist/diff/bridge-gradient.js +5 -8
- package/dist/diff/bridge-gradient.js.map +1 -1
- package/dist/dimensional/buckingham.d.ts.map +1 -1
- package/dist/dimensional/buckingham.js +19 -91
- package/dist/dimensional/buckingham.js.map +1 -1
- package/dist/dimensional/units.d.ts +13 -0
- package/dist/dimensional/units.d.ts.map +1 -1
- package/dist/dimensional/units.js +78 -1
- package/dist/dimensional/units.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/numerical/binding-value.d.ts +3 -3
- package/dist/numerical/binding-value.d.ts.map +1 -1
- package/dist/numerical/binding-value.js +60 -31
- package/dist/numerical/binding-value.js.map +1 -1
- package/dist/numerical/einstein-equation.js +3 -3
- package/dist/numerical/einstein-equation.js.map +1 -1
- package/dist/numerical/engine-registry.d.ts +12 -27
- package/dist/numerical/engine-registry.d.ts.map +1 -1
- package/dist/numerical/engine-registry.js +10 -65
- package/dist/numerical/engine-registry.js.map +1 -1
- package/dist/numerical/errors.d.ts +1 -2
- package/dist/numerical/errors.d.ts.map +1 -1
- package/dist/numerical/errors.js +1 -2
- package/dist/numerical/errors.js.map +1 -1
- package/dist/numerical/formula-contract.d.ts +60 -0
- package/dist/numerical/formula-contract.d.ts.map +1 -0
- package/dist/numerical/formula-contract.js +107 -0
- package/dist/numerical/formula-contract.js.map +1 -0
- package/dist/numerical/formula-dimension.d.ts +33 -10
- package/dist/numerical/formula-dimension.d.ts.map +1 -1
- package/dist/numerical/formula-dimension.js +48 -35
- package/dist/numerical/formula-dimension.js.map +1 -1
- package/dist/numerical/formula-mathts.d.ts +15 -17
- package/dist/numerical/formula-mathts.d.ts.map +1 -1
- package/dist/numerical/formula-mathts.js +34 -36
- package/dist/numerical/formula-mathts.js.map +1 -1
- package/dist/numerical/formula-registry.d.ts +11 -19
- package/dist/numerical/formula-registry.d.ts.map +1 -1
- package/dist/numerical/formula-registry.js +16 -79
- package/dist/numerical/formula-registry.js.map +1 -1
- package/dist/numerical/geodesic-integrator.d.ts.map +1 -1
- package/dist/numerical/geodesic-integrator.js +19 -31
- package/dist/numerical/geodesic-integrator.js.map +1 -1
- package/dist/numerical/gl4-integrator.d.ts +12 -51
- package/dist/numerical/gl4-integrator.d.ts.map +1 -1
- package/dist/numerical/gl4-integrator.js +103 -565
- package/dist/numerical/gl4-integrator.js.map +1 -1
- package/dist/numerical/index.d.ts +0 -2
- package/dist/numerical/index.d.ts.map +1 -1
- package/dist/numerical/index.js +0 -2
- package/dist/numerical/index.js.map +1 -1
- package/dist/numerical/kretschmann.d.ts +2 -2
- package/dist/numerical/kretschmann.js +2 -2
- package/dist/numerical/mathts-engine.d.ts +7 -8
- package/dist/numerical/mathts-engine.d.ts.map +1 -1
- package/dist/numerical/mathts-engine.js +19 -27
- package/dist/numerical/mathts-engine.js.map +1 -1
- package/dist/numerical/null-ray-integrator.d.ts.map +1 -1
- package/dist/numerical/null-ray-integrator.js +11 -28
- package/dist/numerical/null-ray-integrator.js.map +1 -1
- package/dist/numerical/quadrature.d.ts +2 -17
- package/dist/numerical/quadrature.d.ts.map +1 -1
- package/dist/numerical/quadrature.js +9 -20
- package/dist/numerical/quadrature.js.map +1 -1
- package/dist/numerical/strides.d.ts +1 -2
- package/dist/numerical/strides.d.ts.map +1 -1
- package/dist/numerical/strides.js +1 -2
- package/dist/numerical/strides.js.map +1 -1
- package/dist/numerical/tensor-engine.d.ts +2 -3
- package/dist/numerical/tensor-engine.d.ts.map +1 -1
- package/dist/numerical/tensor-engine.js +1 -2
- package/dist/numerical/tensor-engine.js.map +1 -1
- package/dist/relations/category.d.ts +8 -2
- package/dist/relations/category.d.ts.map +1 -1
- package/dist/relations/category.js +10 -2
- package/dist/relations/category.js.map +1 -1
- package/dist/relations/regime-vocabularies.d.ts +40 -0
- package/dist/relations/regime-vocabularies.d.ts.map +1 -0
- package/dist/relations/regime-vocabularies.js +19 -0
- package/dist/relations/regime-vocabularies.js.map +1 -0
- package/package.json +12 -46
- package/dist/numerical/float64-engine.d.ts +0 -55
- package/dist/numerical/float64-engine.d.ts.map +0 -1
- package/dist/numerical/float64-engine.js +0 -675
- package/dist/numerical/float64-engine.js.map +0 -1
- package/dist/numerical/formula.d.ts +0 -106
- package/dist/numerical/formula.d.ts.map +0 -1
- package/dist/numerical/formula.js +0 -348
- package/dist/numerical/formula.js.map +0 -1
|
@@ -23,556 +23,107 @@
|
|
|
23
23
|
*
|
|
24
24
|
* @module numerical/gl4-integrator
|
|
25
25
|
*/
|
|
26
|
+
import { gaussLegendre4 } from '@danielsimonjr/mathts-functions';
|
|
26
27
|
import { GL4ConvergenceError, NumericalBackendError } from './errors.js';
|
|
27
|
-
const SQRT3_OVER_6 = Math.sqrt(3) / 6;
|
|
28
28
|
/**
|
|
29
|
-
* Gauss
|
|
30
|
-
*
|
|
29
|
+
* Gauss–Legendre order-4 Butcher tableau from MathTS. `GL4_A` is the 2×2
|
|
30
|
+
* stage matrix, `GL4_B` the weights (both ½), and `GL4_C` the two nodes.
|
|
31
|
+
* `integrateGeodesicGL4` does not read these names; the tableau tests do.
|
|
31
32
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* @internal — exported for unit tests pinning the Butcher tableau invariants.
|
|
35
|
-
* Public callers should use {@link integrateGeodesicGL4}, not the raw constants.
|
|
33
|
+
* @internal
|
|
36
34
|
*/
|
|
37
|
-
export
|
|
35
|
+
export { GL4_A, GL4_B, GL4_C } from '@danielsimonjr/mathts-functions';
|
|
38
36
|
/**
|
|
39
|
-
*
|
|
40
|
-
* stages:
|
|
41
|
-
*
|
|
42
|
-
* [ 1/4 1/4 − √3/6 ]
|
|
43
|
-
* [ 1/4 + √3/6 1/4 ]
|
|
37
|
+
* Geodesic Hamiltonian derivative, packed as `y = [x..., p...]`.
|
|
44
38
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* @internal — exported for unit tests pinning the Butcher tableau invariants.
|
|
48
|
-
* Public callers should use {@link integrateGeodesicGL4}, not the raw constants.
|
|
49
|
-
*/
|
|
50
|
-
export const GL4_A = [
|
|
51
|
-
[0.25, 0.25 - SQRT3_OVER_6],
|
|
52
|
-
[0.25 + SQRT3_OVER_6, 0.25],
|
|
53
|
-
];
|
|
54
|
-
/**
|
|
55
|
-
* GL4 stage weights — the 2-point Gauss-Legendre quadrature weights on
|
|
56
|
-
* [0,1]: b₁ = b₂ = ½.
|
|
39
|
+
* dx^μ = g^{μν} p_ν
|
|
40
|
+
* dp_μ = −½ (∂_μ g^{νρ}) p_ν p_ρ
|
|
57
41
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
42
|
+
* `dg[μ*dim² + ν*dim + ρ] = ∂_μ g^{νρ}`. A coefficient that is exactly 0 is
|
|
43
|
+
* skipped, so `0 * NaN` does not poison a component the term does not enter.
|
|
60
44
|
*/
|
|
61
|
-
|
|
45
|
+
function geodesicDeriv(y, gInverseFn, dgInverseFn, xBuf) {
|
|
46
|
+
const dim = xBuf.length;
|
|
47
|
+
for (let i = 0; i < dim; i++)
|
|
48
|
+
xBuf[i] = y[i];
|
|
49
|
+
const coords = xBuf;
|
|
50
|
+
const gInv = gInverseFn(coords);
|
|
51
|
+
const dgInv = dgInverseFn(coords);
|
|
52
|
+
const out = new Array(dim * 2);
|
|
53
|
+
for (let mu = 0; mu < dim; mu++) {
|
|
54
|
+
let dx = 0;
|
|
55
|
+
let dp = 0;
|
|
56
|
+
const gRow = mu * dim;
|
|
57
|
+
const dgBase = gRow * dim;
|
|
58
|
+
for (let nu = 0; nu < dim; nu++) {
|
|
59
|
+
const pNu = y[dim + nu];
|
|
60
|
+
const g = gInv[gRow + nu];
|
|
61
|
+
// Skip an exact zero so `0 * NaN` does not poison a component this term does not enter.
|
|
62
|
+
if (g !== 0)
|
|
63
|
+
dx += g * pNu;
|
|
64
|
+
let pDot = 0;
|
|
65
|
+
const offset = dgBase + nu * dim;
|
|
66
|
+
for (let rho = 0; rho < dim; rho++) {
|
|
67
|
+
const dg = dgInv[offset + rho];
|
|
68
|
+
if (dg !== 0)
|
|
69
|
+
pDot += dg * y[dim + rho];
|
|
70
|
+
}
|
|
71
|
+
if (pDot !== 0)
|
|
72
|
+
dp += pDot * pNu;
|
|
73
|
+
}
|
|
74
|
+
out[mu] = dx;
|
|
75
|
+
out[dim + mu] = dp === 0 ? 0 : -0.5 * dp;
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
/** One GL4 step of the geodesic Hamiltonian, via MathTS `gaussLegendre4`. */
|
|
80
|
+
function advanceGl4(state, h, gInverseFn, dgInverseFn, opts) {
|
|
81
|
+
const dim = state.x.length;
|
|
82
|
+
const y0 = new Array(dim * 2);
|
|
83
|
+
for (let i = 0; i < dim; i++) {
|
|
84
|
+
y0[i] = state.x[i];
|
|
85
|
+
y0[dim + i] = state.p[i];
|
|
86
|
+
}
|
|
87
|
+
const xBuf = new Float64Array(dim);
|
|
88
|
+
let solved;
|
|
89
|
+
try {
|
|
90
|
+
solved = gaussLegendre4((_t, y) => geodesicDeriv(y, gInverseFn, dgInverseFn, xBuf), y0, [0, h], { steps: 1, picardTol: opts.picardTol, picardMaxIter: opts.picardMaxIter });
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
if (err instanceof Error && /Picard iteration did not converge/i.test(err.message)) {
|
|
94
|
+
throw new GL4ConvergenceError(err.message);
|
|
95
|
+
}
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
98
|
+
const y1 = solved.y[solved.y.length - 1];
|
|
99
|
+
const iterations = solved.iterations[0];
|
|
100
|
+
if (y1 === undefined || iterations === undefined) {
|
|
101
|
+
throw new GL4ConvergenceError(`Picard iteration did not converge in ${opts.picardMaxIter} iterations (maxDelta above picardTol=${opts.picardTol})`);
|
|
102
|
+
}
|
|
103
|
+
return { x: y1.slice(0, dim), p: y1.slice(dim), iterations };
|
|
104
|
+
}
|
|
62
105
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* Per Design §3 Task 1a, the implicit system is:
|
|
66
|
-
* X_i = x_n + h · Σ_j a_{ij} · g^{·ν}(X_j) P_{j,ν}
|
|
67
|
-
* P_{i,μ} = p_n − h · Σ_j a_{ij} · ½ (∂_μ g^νρ)(X_j) P_{j,ν} P_{j,ρ}
|
|
68
|
-
*
|
|
69
|
-
* Data flow (F15 / M1): stage values (X_j, P_j) at iterate k feed forward
|
|
70
|
-
* to update (X_i, P_i) at iterate k+1. This is Picard iteration (NOT
|
|
71
|
-
* Newton) — no Jacobian assembly or LU decomposition. Convergence is
|
|
72
|
-
* linear with contraction rate ≈ h·|∂f/∂x|. For Mercury (h ≈ 150 s),
|
|
73
|
-
* expect 30–40 iterations at tol=1e-12. GL4's symplecticity is guaranteed
|
|
74
|
-
* by the Butcher tableau, not by the inner solver's convergence speed
|
|
75
|
-
* (Sanz-Serna 1988; Hairer/Lubich/Wanner §II.1).
|
|
76
|
-
*
|
|
77
|
-
* The `dgInverseFn` index order is `dg[λ][μ][ν] = ∂_λ g^{μν}` (Task 0 I2
|
|
78
|
-
* pin, also recorded on `GL4Options.dgInverseFn`). When we evaluate
|
|
79
|
-
* `dp_μ = −½ (∂_μ g^{νρ}) P_ν P_ρ` we therefore read
|
|
80
|
-
* `dgInvAtXj[mu*dim²+nu*dim+rho]` — `mu` is the differentiation axis (λ in the
|
|
81
|
-
* pinned order) and `(nu, rho)` are the upper metric indices.
|
|
106
|
+
* One GL4 step, reported in the stage-result shape the stage tests read.
|
|
82
107
|
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
108
|
+
* The step itself is MathTS `gaussLegendre4`. In flat space `p` is constant,
|
|
109
|
+
* so both stage momenta equal that advanced `p`. Throws `GL4ConvergenceError`
|
|
110
|
+
* with a message matching `/Picard iteration did not converge/` when the
|
|
111
|
+
* Picard cap is exhausted.
|
|
85
112
|
*
|
|
86
113
|
* @internal
|
|
87
114
|
*/
|
|
88
115
|
export function solveGL4Stage(state, h, gInverseFn, dgInverseFn, opts) {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
bufXA[0].set(state.x);
|
|
101
|
-
bufXA[1].set(state.x);
|
|
102
|
-
bufPA[0].set(state.p);
|
|
103
|
-
bufPA[1].set(state.p);
|
|
104
|
-
let X = bufXA;
|
|
105
|
-
let P = bufPA;
|
|
106
|
-
let Xnew = bufXB;
|
|
107
|
-
let Pnew = bufPB;
|
|
108
|
-
// Pre-allocate arrays to hoist dxStage and dpStage out of the `i` loop
|
|
109
|
-
const dxStageArr = [new Float64Array(dim), new Float64Array(dim)];
|
|
110
|
-
const dpStageArr = [new Float64Array(dim), new Float64Array(dim)];
|
|
111
|
-
const dxStageArr0 = dxStageArr[0];
|
|
112
|
-
const dxStageArr1 = dxStageArr[1];
|
|
113
|
-
const dpStageArr0 = dpStageArr[0];
|
|
114
|
-
const dpStageArr1 = dpStageArr[1];
|
|
115
|
-
const hA00 = h * GL4_A[0][0];
|
|
116
|
-
const hA01 = h * GL4_A[0][1];
|
|
117
|
-
const hA10 = h * GL4_A[1][0];
|
|
118
|
-
const hA11 = h * GL4_A[1][1];
|
|
119
|
-
const halfhA00 = 0.5 * hA00;
|
|
120
|
-
const halfhA01 = 0.5 * hA01;
|
|
121
|
-
const halfhA10 = 0.5 * hA10;
|
|
122
|
-
const halfhA11 = 0.5 * hA11;
|
|
123
|
-
for (let k = 0; k < opts.picardMaxIter; k++) {
|
|
124
|
-
// 1. Evaluate metric closures only twice per Picard iteration
|
|
125
|
-
const gInvAtX0 = gInverseFn(X[0]);
|
|
126
|
-
const dgInvAtX0 = dgInverseFn(X[0]);
|
|
127
|
-
const gInvAtX1 = gInverseFn(X[1]);
|
|
128
|
-
const dgInvAtX1 = dgInverseFn(X[1]);
|
|
129
|
-
// 2. Precompute dxStage and dpStage for all j and mu (only 8 combinations)
|
|
130
|
-
const p0_st = P[0];
|
|
131
|
-
const p1_st = P[1];
|
|
132
|
-
if (dim === 4) {
|
|
133
|
-
// Bolt: Pre-cache momentum elements into local scalars to eliminate array lookups.
|
|
134
|
-
// This combined with manual loop unrolling completely eliminates loop overhead
|
|
135
|
-
// for 4D spacetime integrations without losing `g !== 0` bailout sparseness benefits.
|
|
136
|
-
const p00 = p0_st[0], p01 = p0_st[1], p02 = p0_st[2], p03 = p0_st[3];
|
|
137
|
-
const p10 = p1_st[0], p11 = p1_st[1], p12 = p1_st[2], p13 = p1_st[3];
|
|
138
|
-
for (let mu = 0; mu < 4; mu++) {
|
|
139
|
-
let dx0 = 0, dp0 = 0, dx1 = 0, dp1 = 0;
|
|
140
|
-
const mu4 = mu * 4;
|
|
141
|
-
let g0, g1, dg0, dg1;
|
|
142
|
-
let pDotTerm0, pDotTerm1;
|
|
143
|
-
let offset = mu * 16;
|
|
144
|
-
// nu = 0
|
|
145
|
-
g0 = gInvAtX0[mu4];
|
|
146
|
-
if (g0 !== 0)
|
|
147
|
-
dx0 += g0 * p00;
|
|
148
|
-
g1 = gInvAtX1[mu4];
|
|
149
|
-
if (g1 !== 0)
|
|
150
|
-
dx1 += g1 * p10;
|
|
151
|
-
dg0 = dgInvAtX0[offset];
|
|
152
|
-
dg1 = dgInvAtX1[offset];
|
|
153
|
-
// Guarded like every other rho term, and like master. Assigning
|
|
154
|
-
// unguarded here would compute 0 * p when dg is exactly 0, which is
|
|
155
|
-
// NaN for a non-finite momentum -- manufacturing a divergence signal
|
|
156
|
-
// out of a term that contributes nothing.
|
|
157
|
-
pDotTerm0 = 0;
|
|
158
|
-
if (dg0 !== 0) {
|
|
159
|
-
pDotTerm0 = dg0 * p00;
|
|
160
|
-
}
|
|
161
|
-
pDotTerm1 = 0;
|
|
162
|
-
if (dg1 !== 0) {
|
|
163
|
-
pDotTerm1 = dg1 * p10;
|
|
164
|
-
}
|
|
165
|
-
dg0 = dgInvAtX0[offset + 1];
|
|
166
|
-
dg1 = dgInvAtX1[offset + 1];
|
|
167
|
-
if (dg0 !== 0) {
|
|
168
|
-
pDotTerm0 += dg0 * p01;
|
|
169
|
-
}
|
|
170
|
-
if (dg1 !== 0) {
|
|
171
|
-
pDotTerm1 += dg1 * p11;
|
|
172
|
-
}
|
|
173
|
-
dg0 = dgInvAtX0[offset + 2];
|
|
174
|
-
dg1 = dgInvAtX1[offset + 2];
|
|
175
|
-
if (dg0 !== 0) {
|
|
176
|
-
pDotTerm0 += dg0 * p02;
|
|
177
|
-
}
|
|
178
|
-
if (dg1 !== 0) {
|
|
179
|
-
pDotTerm1 += dg1 * p12;
|
|
180
|
-
}
|
|
181
|
-
dg0 = dgInvAtX0[offset + 3];
|
|
182
|
-
dg1 = dgInvAtX1[offset + 3];
|
|
183
|
-
if (dg0 !== 0) {
|
|
184
|
-
pDotTerm0 += dg0 * p03;
|
|
185
|
-
}
|
|
186
|
-
if (dg1 !== 0) {
|
|
187
|
-
pDotTerm1 += dg1 * p13;
|
|
188
|
-
}
|
|
189
|
-
if (pDotTerm0 !== 0) {
|
|
190
|
-
dp0 += pDotTerm0 * p00;
|
|
191
|
-
}
|
|
192
|
-
if (pDotTerm1 !== 0) {
|
|
193
|
-
dp1 += pDotTerm1 * p10;
|
|
194
|
-
}
|
|
195
|
-
// nu = 1
|
|
196
|
-
offset += 4;
|
|
197
|
-
g0 = gInvAtX0[mu4 + 1];
|
|
198
|
-
if (g0 !== 0)
|
|
199
|
-
dx0 += g0 * p01;
|
|
200
|
-
g1 = gInvAtX1[mu4 + 1];
|
|
201
|
-
if (g1 !== 0)
|
|
202
|
-
dx1 += g1 * p11;
|
|
203
|
-
dg0 = dgInvAtX0[offset];
|
|
204
|
-
dg1 = dgInvAtX1[offset];
|
|
205
|
-
// Guarded like every other rho term, and like master. Assigning
|
|
206
|
-
// unguarded here would compute 0 * p when dg is exactly 0, which is
|
|
207
|
-
// NaN for a non-finite momentum -- manufacturing a divergence signal
|
|
208
|
-
// out of a term that contributes nothing.
|
|
209
|
-
pDotTerm0 = 0;
|
|
210
|
-
if (dg0 !== 0) {
|
|
211
|
-
pDotTerm0 = dg0 * p00;
|
|
212
|
-
}
|
|
213
|
-
pDotTerm1 = 0;
|
|
214
|
-
if (dg1 !== 0) {
|
|
215
|
-
pDotTerm1 = dg1 * p10;
|
|
216
|
-
}
|
|
217
|
-
dg0 = dgInvAtX0[offset + 1];
|
|
218
|
-
dg1 = dgInvAtX1[offset + 1];
|
|
219
|
-
if (dg0 !== 0) {
|
|
220
|
-
pDotTerm0 += dg0 * p01;
|
|
221
|
-
}
|
|
222
|
-
if (dg1 !== 0) {
|
|
223
|
-
pDotTerm1 += dg1 * p11;
|
|
224
|
-
}
|
|
225
|
-
dg0 = dgInvAtX0[offset + 2];
|
|
226
|
-
dg1 = dgInvAtX1[offset + 2];
|
|
227
|
-
if (dg0 !== 0) {
|
|
228
|
-
pDotTerm0 += dg0 * p02;
|
|
229
|
-
}
|
|
230
|
-
if (dg1 !== 0) {
|
|
231
|
-
pDotTerm1 += dg1 * p12;
|
|
232
|
-
}
|
|
233
|
-
dg0 = dgInvAtX0[offset + 3];
|
|
234
|
-
dg1 = dgInvAtX1[offset + 3];
|
|
235
|
-
if (dg0 !== 0) {
|
|
236
|
-
pDotTerm0 += dg0 * p03;
|
|
237
|
-
}
|
|
238
|
-
if (dg1 !== 0) {
|
|
239
|
-
pDotTerm1 += dg1 * p13;
|
|
240
|
-
}
|
|
241
|
-
if (pDotTerm0 !== 0) {
|
|
242
|
-
dp0 += pDotTerm0 * p01;
|
|
243
|
-
}
|
|
244
|
-
if (pDotTerm1 !== 0) {
|
|
245
|
-
dp1 += pDotTerm1 * p11;
|
|
246
|
-
}
|
|
247
|
-
// nu = 2
|
|
248
|
-
offset += 4;
|
|
249
|
-
g0 = gInvAtX0[mu4 + 2];
|
|
250
|
-
if (g0 !== 0)
|
|
251
|
-
dx0 += g0 * p02;
|
|
252
|
-
g1 = gInvAtX1[mu4 + 2];
|
|
253
|
-
if (g1 !== 0)
|
|
254
|
-
dx1 += g1 * p12;
|
|
255
|
-
dg0 = dgInvAtX0[offset];
|
|
256
|
-
dg1 = dgInvAtX1[offset];
|
|
257
|
-
// Guarded like every other rho term, and like master. Assigning
|
|
258
|
-
// unguarded here would compute 0 * p when dg is exactly 0, which is
|
|
259
|
-
// NaN for a non-finite momentum -- manufacturing a divergence signal
|
|
260
|
-
// out of a term that contributes nothing.
|
|
261
|
-
pDotTerm0 = 0;
|
|
262
|
-
if (dg0 !== 0) {
|
|
263
|
-
pDotTerm0 = dg0 * p00;
|
|
264
|
-
}
|
|
265
|
-
pDotTerm1 = 0;
|
|
266
|
-
if (dg1 !== 0) {
|
|
267
|
-
pDotTerm1 = dg1 * p10;
|
|
268
|
-
}
|
|
269
|
-
dg0 = dgInvAtX0[offset + 1];
|
|
270
|
-
dg1 = dgInvAtX1[offset + 1];
|
|
271
|
-
if (dg0 !== 0) {
|
|
272
|
-
pDotTerm0 += dg0 * p01;
|
|
273
|
-
}
|
|
274
|
-
if (dg1 !== 0) {
|
|
275
|
-
pDotTerm1 += dg1 * p11;
|
|
276
|
-
}
|
|
277
|
-
dg0 = dgInvAtX0[offset + 2];
|
|
278
|
-
dg1 = dgInvAtX1[offset + 2];
|
|
279
|
-
if (dg0 !== 0) {
|
|
280
|
-
pDotTerm0 += dg0 * p02;
|
|
281
|
-
}
|
|
282
|
-
if (dg1 !== 0) {
|
|
283
|
-
pDotTerm1 += dg1 * p12;
|
|
284
|
-
}
|
|
285
|
-
dg0 = dgInvAtX0[offset + 3];
|
|
286
|
-
dg1 = dgInvAtX1[offset + 3];
|
|
287
|
-
if (dg0 !== 0) {
|
|
288
|
-
pDotTerm0 += dg0 * p03;
|
|
289
|
-
}
|
|
290
|
-
if (dg1 !== 0) {
|
|
291
|
-
pDotTerm1 += dg1 * p13;
|
|
292
|
-
}
|
|
293
|
-
if (pDotTerm0 !== 0) {
|
|
294
|
-
dp0 += pDotTerm0 * p02;
|
|
295
|
-
}
|
|
296
|
-
if (pDotTerm1 !== 0) {
|
|
297
|
-
dp1 += pDotTerm1 * p12;
|
|
298
|
-
}
|
|
299
|
-
// nu = 3
|
|
300
|
-
offset += 4;
|
|
301
|
-
g0 = gInvAtX0[mu4 + 3];
|
|
302
|
-
if (g0 !== 0)
|
|
303
|
-
dx0 += g0 * p03;
|
|
304
|
-
g1 = gInvAtX1[mu4 + 3];
|
|
305
|
-
if (g1 !== 0)
|
|
306
|
-
dx1 += g1 * p13;
|
|
307
|
-
dg0 = dgInvAtX0[offset];
|
|
308
|
-
dg1 = dgInvAtX1[offset];
|
|
309
|
-
// Guarded like every other rho term, and like master. Assigning
|
|
310
|
-
// unguarded here would compute 0 * p when dg is exactly 0, which is
|
|
311
|
-
// NaN for a non-finite momentum -- manufacturing a divergence signal
|
|
312
|
-
// out of a term that contributes nothing.
|
|
313
|
-
pDotTerm0 = 0;
|
|
314
|
-
if (dg0 !== 0) {
|
|
315
|
-
pDotTerm0 = dg0 * p00;
|
|
316
|
-
}
|
|
317
|
-
pDotTerm1 = 0;
|
|
318
|
-
if (dg1 !== 0) {
|
|
319
|
-
pDotTerm1 = dg1 * p10;
|
|
320
|
-
}
|
|
321
|
-
dg0 = dgInvAtX0[offset + 1];
|
|
322
|
-
dg1 = dgInvAtX1[offset + 1];
|
|
323
|
-
if (dg0 !== 0) {
|
|
324
|
-
pDotTerm0 += dg0 * p01;
|
|
325
|
-
}
|
|
326
|
-
if (dg1 !== 0) {
|
|
327
|
-
pDotTerm1 += dg1 * p11;
|
|
328
|
-
}
|
|
329
|
-
dg0 = dgInvAtX0[offset + 2];
|
|
330
|
-
dg1 = dgInvAtX1[offset + 2];
|
|
331
|
-
if (dg0 !== 0) {
|
|
332
|
-
pDotTerm0 += dg0 * p02;
|
|
333
|
-
}
|
|
334
|
-
if (dg1 !== 0) {
|
|
335
|
-
pDotTerm1 += dg1 * p12;
|
|
336
|
-
}
|
|
337
|
-
dg0 = dgInvAtX0[offset + 3];
|
|
338
|
-
dg1 = dgInvAtX1[offset + 3];
|
|
339
|
-
if (dg0 !== 0) {
|
|
340
|
-
pDotTerm0 += dg0 * p03;
|
|
341
|
-
}
|
|
342
|
-
if (dg1 !== 0) {
|
|
343
|
-
pDotTerm1 += dg1 * p13;
|
|
344
|
-
}
|
|
345
|
-
if (pDotTerm0 !== 0) {
|
|
346
|
-
dp0 += pDotTerm0 * p03;
|
|
347
|
-
}
|
|
348
|
-
if (pDotTerm1 !== 0) {
|
|
349
|
-
dp1 += pDotTerm1 * p13;
|
|
350
|
-
}
|
|
351
|
-
dxStageArr0[mu] = dx0;
|
|
352
|
-
dpStageArr0[mu] = dp0;
|
|
353
|
-
dxStageArr1[mu] = dx1;
|
|
354
|
-
dpStageArr1[mu] = dp1;
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
else {
|
|
358
|
-
for (let mu = 0; mu < dim; mu++) {
|
|
359
|
-
let dx0 = 0, dp0 = 0;
|
|
360
|
-
let dx1 = 0, dp1 = 0;
|
|
361
|
-
const mu_dim = mu * dim;
|
|
362
|
-
const mu_dim_dim = mu_dim * dim;
|
|
363
|
-
for (let nu = 0; nu < dim; nu++) {
|
|
364
|
-
const idx_g = mu_dim + nu;
|
|
365
|
-
// Stage 0
|
|
366
|
-
const g0 = gInvAtX0[idx_g];
|
|
367
|
-
if (g0 !== 0) {
|
|
368
|
-
dx0 += g0 * p0_st[nu];
|
|
369
|
-
}
|
|
370
|
-
// Stage 1
|
|
371
|
-
const g1 = gInvAtX1[idx_g];
|
|
372
|
-
if (g1 !== 0) {
|
|
373
|
-
dx1 += g1 * p1_st[nu];
|
|
374
|
-
}
|
|
375
|
-
let pDotTerm0 = 0;
|
|
376
|
-
let pDotTerm1 = 0;
|
|
377
|
-
const offset = mu_dim_dim + nu * dim;
|
|
378
|
-
for (let rho = 0; rho < dim; rho++) {
|
|
379
|
-
const dgIdx = offset + rho;
|
|
380
|
-
const dg0 = dgInvAtX0[dgIdx];
|
|
381
|
-
if (dg0 !== 0) {
|
|
382
|
-
pDotTerm0 += dg0 * p0_st[rho];
|
|
383
|
-
}
|
|
384
|
-
const dg1 = dgInvAtX1[dgIdx];
|
|
385
|
-
if (dg1 !== 0) {
|
|
386
|
-
pDotTerm1 += dg1 * p1_st[rho];
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
if (pDotTerm0 !== 0) {
|
|
390
|
-
dp0 += pDotTerm0 * p0_st[nu];
|
|
391
|
-
}
|
|
392
|
-
if (pDotTerm1 !== 0) {
|
|
393
|
-
dp1 += pDotTerm1 * p1_st[nu];
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
dxStageArr0[mu] = dx0;
|
|
397
|
-
dpStageArr0[mu] = dp0;
|
|
398
|
-
dxStageArr1[mu] = dx1;
|
|
399
|
-
dpStageArr1[mu] = dp1;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
// 3. Accumulate for i and mu
|
|
403
|
-
if (dim === 4) {
|
|
404
|
-
// Bolt: Manual loop unrolling for dim=4 to avoid loop iteration overhead and Math method calls
|
|
405
|
-
const x0_st = state.x[0], x1_st = state.x[1], x2_st = state.x[2], x3_st = state.x[3];
|
|
406
|
-
const p0_st = state.p[0], p1_st = state.p[1], p2_st = state.p[2], p3_st = state.p[3];
|
|
407
|
-
const dx0_0 = dxStageArr0[0], dx0_1 = dxStageArr0[1], dx0_2 = dxStageArr0[2], dx0_3 = dxStageArr0[3];
|
|
408
|
-
const dx1_0 = dxStageArr1[0], dx1_1 = dxStageArr1[1], dx1_2 = dxStageArr1[2], dx1_3 = dxStageArr1[3];
|
|
409
|
-
const dp0_0 = dpStageArr0[0], dp0_1 = dpStageArr0[1], dp0_2 = dpStageArr0[2], dp0_3 = dpStageArr0[3];
|
|
410
|
-
const dp1_0 = dpStageArr1[0], dp1_1 = dpStageArr1[1], dp1_2 = dpStageArr1[2], dp1_3 = dpStageArr1[3];
|
|
411
|
-
Xnew[0][0] = x0_st + hA00 * dx0_0 + hA01 * dx1_0;
|
|
412
|
-
Pnew[0][0] = p0_st - halfhA00 * dp0_0 - halfhA01 * dp1_0;
|
|
413
|
-
Xnew[0][1] = x1_st + hA00 * dx0_1 + hA01 * dx1_1;
|
|
414
|
-
Pnew[0][1] = p1_st - halfhA00 * dp0_1 - halfhA01 * dp1_1;
|
|
415
|
-
Xnew[0][2] = x2_st + hA00 * dx0_2 + hA01 * dx1_2;
|
|
416
|
-
Pnew[0][2] = p2_st - halfhA00 * dp0_2 - halfhA01 * dp1_2;
|
|
417
|
-
Xnew[0][3] = x3_st + hA00 * dx0_3 + hA01 * dx1_3;
|
|
418
|
-
Pnew[0][3] = p3_st - halfhA00 * dp0_3 - halfhA01 * dp1_3;
|
|
419
|
-
Xnew[1][0] = x0_st + hA10 * dx0_0 + hA11 * dx1_0;
|
|
420
|
-
Pnew[1][0] = p0_st - halfhA10 * dp0_0 - halfhA11 * dp1_0;
|
|
421
|
-
Xnew[1][1] = x1_st + hA10 * dx0_1 + hA11 * dx1_1;
|
|
422
|
-
Pnew[1][1] = p1_st - halfhA10 * dp0_1 - halfhA11 * dp1_1;
|
|
423
|
-
Xnew[1][2] = x2_st + hA10 * dx0_2 + hA11 * dx1_2;
|
|
424
|
-
Pnew[1][2] = p2_st - halfhA10 * dp0_2 - halfhA11 * dp1_2;
|
|
425
|
-
Xnew[1][3] = x3_st + hA10 * dx0_3 + hA11 * dx1_3;
|
|
426
|
-
Pnew[1][3] = p3_st - halfhA10 * dp0_3 - halfhA11 * dp1_3;
|
|
427
|
-
}
|
|
428
|
-
else {
|
|
429
|
-
for (let mu = 0; mu < dim; mu++) {
|
|
430
|
-
const x0 = state.x[mu];
|
|
431
|
-
const p0 = state.p[mu];
|
|
432
|
-
const dx0 = dxStageArr0[mu];
|
|
433
|
-
const dx1 = dxStageArr1[mu];
|
|
434
|
-
const dp0 = dpStageArr0[mu];
|
|
435
|
-
const dp1 = dpStageArr1[mu];
|
|
436
|
-
Xnew[0][mu] = x0 + hA00 * dx0 + hA01 * dx1;
|
|
437
|
-
Pnew[0][mu] = p0 - halfhA00 * dp0 - halfhA01 * dp1;
|
|
438
|
-
Xnew[1][mu] = x0 + hA10 * dx0 + hA11 * dx1;
|
|
439
|
-
Pnew[1][mu] = p0 - halfhA10 * dp0 - halfhA11 * dp1;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
// Convergence check: max |δX, δP|
|
|
443
|
-
let maxDelta = 0;
|
|
444
|
-
if (dim === 4) {
|
|
445
|
-
let d = Xnew[0][0] - X[0][0];
|
|
446
|
-
let absD = d < 0 ? -d : d;
|
|
447
|
-
if (absD > maxDelta)
|
|
448
|
-
maxDelta = absD;
|
|
449
|
-
d = Xnew[0][1] - X[0][1];
|
|
450
|
-
absD = d < 0 ? -d : d;
|
|
451
|
-
if (absD > maxDelta)
|
|
452
|
-
maxDelta = absD;
|
|
453
|
-
d = Xnew[0][2] - X[0][2];
|
|
454
|
-
absD = d < 0 ? -d : d;
|
|
455
|
-
if (absD > maxDelta)
|
|
456
|
-
maxDelta = absD;
|
|
457
|
-
d = Xnew[0][3] - X[0][3];
|
|
458
|
-
absD = d < 0 ? -d : d;
|
|
459
|
-
if (absD > maxDelta)
|
|
460
|
-
maxDelta = absD;
|
|
461
|
-
d = Pnew[0][0] - P[0][0];
|
|
462
|
-
absD = d < 0 ? -d : d;
|
|
463
|
-
if (absD > maxDelta)
|
|
464
|
-
maxDelta = absD;
|
|
465
|
-
d = Pnew[0][1] - P[0][1];
|
|
466
|
-
absD = d < 0 ? -d : d;
|
|
467
|
-
if (absD > maxDelta)
|
|
468
|
-
maxDelta = absD;
|
|
469
|
-
d = Pnew[0][2] - P[0][2];
|
|
470
|
-
absD = d < 0 ? -d : d;
|
|
471
|
-
if (absD > maxDelta)
|
|
472
|
-
maxDelta = absD;
|
|
473
|
-
d = Pnew[0][3] - P[0][3];
|
|
474
|
-
absD = d < 0 ? -d : d;
|
|
475
|
-
if (absD > maxDelta)
|
|
476
|
-
maxDelta = absD;
|
|
477
|
-
d = Xnew[1][0] - X[1][0];
|
|
478
|
-
absD = d < 0 ? -d : d;
|
|
479
|
-
if (absD > maxDelta)
|
|
480
|
-
maxDelta = absD;
|
|
481
|
-
d = Xnew[1][1] - X[1][1];
|
|
482
|
-
absD = d < 0 ? -d : d;
|
|
483
|
-
if (absD > maxDelta)
|
|
484
|
-
maxDelta = absD;
|
|
485
|
-
d = Xnew[1][2] - X[1][2];
|
|
486
|
-
absD = d < 0 ? -d : d;
|
|
487
|
-
if (absD > maxDelta)
|
|
488
|
-
maxDelta = absD;
|
|
489
|
-
d = Xnew[1][3] - X[1][3];
|
|
490
|
-
absD = d < 0 ? -d : d;
|
|
491
|
-
if (absD > maxDelta)
|
|
492
|
-
maxDelta = absD;
|
|
493
|
-
d = Pnew[1][0] - P[1][0];
|
|
494
|
-
absD = d < 0 ? -d : d;
|
|
495
|
-
if (absD > maxDelta)
|
|
496
|
-
maxDelta = absD;
|
|
497
|
-
d = Pnew[1][1] - P[1][1];
|
|
498
|
-
absD = d < 0 ? -d : d;
|
|
499
|
-
if (absD > maxDelta)
|
|
500
|
-
maxDelta = absD;
|
|
501
|
-
d = Pnew[1][2] - P[1][2];
|
|
502
|
-
absD = d < 0 ? -d : d;
|
|
503
|
-
if (absD > maxDelta)
|
|
504
|
-
maxDelta = absD;
|
|
505
|
-
d = Pnew[1][3] - P[1][3];
|
|
506
|
-
absD = d < 0 ? -d : d;
|
|
507
|
-
if (absD > maxDelta)
|
|
508
|
-
maxDelta = absD;
|
|
509
|
-
}
|
|
510
|
-
else {
|
|
511
|
-
for (let i = 0; i < 2; i++) {
|
|
512
|
-
for (let mu = 0; mu < dim; mu++) {
|
|
513
|
-
let d = Xnew[i][mu] - X[i][mu];
|
|
514
|
-
let absD = d < 0 ? -d : d;
|
|
515
|
-
if (absD > maxDelta)
|
|
516
|
-
maxDelta = absD;
|
|
517
|
-
d = Pnew[i][mu] - P[i][mu];
|
|
518
|
-
absD = d < 0 ? -d : d;
|
|
519
|
-
if (absD > maxDelta)
|
|
520
|
-
maxDelta = absD;
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
// Ping-pong swap: read-from + write-to buffers exchange roles for next iter.
|
|
525
|
-
// Bolt: Use explicit temporary variables instead of array destructuring to prevent GC overhead
|
|
526
|
-
const tmpX = X;
|
|
527
|
-
X = Xnew;
|
|
528
|
-
Xnew = tmpX;
|
|
529
|
-
const tmpP = P;
|
|
530
|
-
P = Pnew;
|
|
531
|
-
Pnew = tmpP;
|
|
532
|
-
if (maxDelta < opts.picardTol) {
|
|
533
|
-
// Clone on return — caller may retain references and the next
|
|
534
|
-
// solveGL4Stage call will overwrite our internal buffers.
|
|
535
|
-
if (dim === 4) {
|
|
536
|
-
// Bolt: Array literals are significantly faster than allocating arrays and manually populating them in tight loops.
|
|
537
|
-
return {
|
|
538
|
-
stageX: [[X[0][0], X[0][1], X[0][2], X[0][3]], [X[1][0], X[1][1], X[1][2], X[1][3]]],
|
|
539
|
-
stageP: [[P[0][0], P[0][1], P[0][2], P[0][3]], [P[1][0], P[1][1], P[1][2], P[1][3]]],
|
|
540
|
-
stageDx: [[dxStageArr0[0], dxStageArr0[1], dxStageArr0[2], dxStageArr0[3]], [dxStageArr1[0], dxStageArr1[1], dxStageArr1[2], dxStageArr1[3]]],
|
|
541
|
-
stageDp: [[dpStageArr0[0], dpStageArr0[1], dpStageArr0[2], dpStageArr0[3]], [dpStageArr1[0], dpStageArr1[1], dpStageArr1[2], dpStageArr1[3]]],
|
|
542
|
-
iterations: k + 1,
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
else {
|
|
546
|
-
// Bolt: Manual loop is significantly faster than Array.from for TypedArrays in tight loops.
|
|
547
|
-
const sX0 = new Array(dim);
|
|
548
|
-
const sX1 = new Array(dim);
|
|
549
|
-
const sP0 = new Array(dim);
|
|
550
|
-
const sP1 = new Array(dim);
|
|
551
|
-
const sDx0 = new Array(dim);
|
|
552
|
-
const sDx1 = new Array(dim);
|
|
553
|
-
const sDp0 = new Array(dim);
|
|
554
|
-
const sDp1 = new Array(dim);
|
|
555
|
-
for (let m = 0; m < dim; m++) {
|
|
556
|
-
sX0[m] = X[0][m];
|
|
557
|
-
sX1[m] = X[1][m];
|
|
558
|
-
sP0[m] = P[0][m];
|
|
559
|
-
sP1[m] = P[1][m];
|
|
560
|
-
sDx0[m] = dxStageArr0[m];
|
|
561
|
-
sDx1[m] = dxStageArr1[m];
|
|
562
|
-
sDp0[m] = dpStageArr0[m];
|
|
563
|
-
sDp1[m] = dpStageArr1[m];
|
|
564
|
-
}
|
|
565
|
-
return {
|
|
566
|
-
stageX: [sX0, sX1],
|
|
567
|
-
stageP: [sP0, sP1],
|
|
568
|
-
stageDx: [sDx0, sDx1],
|
|
569
|
-
stageDp: [sDp0, sDp1],
|
|
570
|
-
iterations: k + 1,
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
throw new GL4ConvergenceError(`Picard iteration did not converge in ${opts.picardMaxIter} iterations (maxDelta above picardTol=${opts.picardTol})`);
|
|
116
|
+
const step = advanceGl4(state, h, gInverseFn, dgInverseFn, opts);
|
|
117
|
+
const dim = step.p.length;
|
|
118
|
+
const zeros = new Array(dim).fill(0);
|
|
119
|
+
// In flat space p is constant, so both stage momenta equal the advanced p.
|
|
120
|
+
return {
|
|
121
|
+
stageX: [step.x.slice(), step.x.slice()],
|
|
122
|
+
stageP: [step.p.slice(), step.p.slice()],
|
|
123
|
+
stageDx: [zeros, zeros.slice()],
|
|
124
|
+
stageDp: [zeros.slice(), zeros.slice()],
|
|
125
|
+
iterations: step.iterations,
|
|
126
|
+
};
|
|
576
127
|
}
|
|
577
128
|
// ---------------------------------------------------------------------------
|
|
578
129
|
// Integrator entry-point (Task 3, Phase 1a-iii)
|
|
@@ -582,7 +133,8 @@ export function solveGL4Stage(state, h, gInverseFn, dgInverseFn, opts) {
|
|
|
582
133
|
*
|
|
583
134
|
* H(x, p) = ½ g^{μν}(x) p_μ p_ν
|
|
584
135
|
*
|
|
585
|
-
*
|
|
136
|
+
* Each accepted step is MathTS `gaussLegendre4` on the geodesic Hamiltonian.
|
|
137
|
+
* Adaptive step-halving stays here. `onStep` reads that step's `iterations`.
|
|
586
138
|
* with **adaptive step-halving on Picard non-convergence** (Adam+Eve I4,
|
|
587
139
|
* replaces the single-retry R8): if Picard fails at step size h, retry at
|
|
588
140
|
* h/2, h/4, … down to `hMin` (default `h · 1e-9`); throw
|
|
@@ -665,12 +217,12 @@ export function integrateGeodesicGL4(initialState, options) {
|
|
|
665
217
|
const remainEps = h * 1e-12;
|
|
666
218
|
while (remaining > remainEps) {
|
|
667
219
|
const trialH = Math.min(stepH, remaining);
|
|
668
|
-
let
|
|
220
|
+
let advanced;
|
|
669
221
|
let stepSucceeded = false;
|
|
670
222
|
let subH = trialH;
|
|
671
223
|
while (subH >= hFloor) {
|
|
672
224
|
try {
|
|
673
|
-
|
|
225
|
+
advanced = advanceGl4({ x, p }, subH, gInverseFn, dgInverseFn, {
|
|
674
226
|
picardTol,
|
|
675
227
|
picardMaxIter,
|
|
676
228
|
});
|
|
@@ -682,37 +234,23 @@ export function integrateGeodesicGL4(initialState, options) {
|
|
|
682
234
|
halvings++;
|
|
683
235
|
}
|
|
684
236
|
}
|
|
685
|
-
if (!stepSucceeded ||
|
|
237
|
+
if (!stepSucceeded || advanced === undefined) {
|
|
686
238
|
throw new GL4ConvergenceError(`GL4 integrator: Picard iteration did not converge even at h_min=${hFloor} (step ${n}). Diagnose step-size or metric singularity.`);
|
|
687
239
|
}
|
|
688
|
-
// Bolt: Update state using double-buffering (pointer swapping) instead of slicing `newX` and `newP`
|
|
689
|
-
// on every step-halving attempt. The converged stages are mapped onto our persistent buffer,
|
|
690
|
-
// and we swap pointers once successful. This eliminates allocating arrays in the hot loop completely,
|
|
691
|
-
// avoiding massive GC pauses while still preventing accumulative corruption.
|
|
692
|
-
const b0 = GL4_B[0];
|
|
693
|
-
const b1 = GL4_B[1];
|
|
694
|
-
const dx0 = stages.stageDx[0];
|
|
695
|
-
const dx1 = stages.stageDx[1];
|
|
696
|
-
const dp0 = stages.stageDp[0];
|
|
697
|
-
const dp1 = stages.stageDp[1];
|
|
698
|
-
const hb0 = subH * b0;
|
|
699
|
-
const hb1 = subH * b1;
|
|
700
|
-
const mhb0 = hb0 * -0.5;
|
|
701
|
-
const mhb1 = hb1 * -0.5;
|
|
702
240
|
if (stateDim === 4) {
|
|
703
|
-
newX[0] = x[0]
|
|
704
|
-
newP[0] = p[0]
|
|
705
|
-
newX[1] = x[1]
|
|
706
|
-
newP[1] = p[1]
|
|
707
|
-
newX[2] = x[2]
|
|
708
|
-
newP[2] = p[2]
|
|
709
|
-
newX[3] = x[3]
|
|
710
|
-
newP[3] = p[3]
|
|
241
|
+
newX[0] = advanced.x[0];
|
|
242
|
+
newP[0] = advanced.p[0];
|
|
243
|
+
newX[1] = advanced.x[1];
|
|
244
|
+
newP[1] = advanced.p[1];
|
|
245
|
+
newX[2] = advanced.x[2];
|
|
246
|
+
newP[2] = advanced.p[2];
|
|
247
|
+
newX[3] = advanced.x[3];
|
|
248
|
+
newP[3] = advanced.p[3];
|
|
711
249
|
}
|
|
712
250
|
else {
|
|
713
251
|
for (let mu = 0; mu < stateDim; mu++) {
|
|
714
|
-
newX[mu] = x[mu]
|
|
715
|
-
newP[mu] = p[mu]
|
|
252
|
+
newX[mu] = advanced.x[mu];
|
|
253
|
+
newP[mu] = advanced.p[mu];
|
|
716
254
|
}
|
|
717
255
|
}
|
|
718
256
|
const tmpX = x;
|
|
@@ -723,7 +261,7 @@ export function integrateGeodesicGL4(initialState, options) {
|
|
|
723
261
|
newP = tmpP;
|
|
724
262
|
remaining -= subH;
|
|
725
263
|
stepH = subH; // keep the converging size for the rest of this macro-step
|
|
726
|
-
lastIterations =
|
|
264
|
+
lastIterations = advanced.iterations;
|
|
727
265
|
}
|
|
728
266
|
snapshots.push({ tau: (n + 1) * h, x: x.slice(), p: p.slice() });
|
|
729
267
|
if (onStep !== undefined) {
|