@essrt/physics 20.0.1 → 22.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 +4 -4
- package/package.json +4 -8
- package/src/cardinal/one-source-structure.cjs +3 -2
- package/src/chain-cycles/index.cjs +12 -30
- package/src/climate/l1-orbital.cjs +3 -1
- package/src/constants/coefficients.d.ts +17 -93
- package/src/constants/coefficients.js +7 -22
- package/src/constants/generated.d.ts +18 -156
- package/src/constants/generated.js +33 -168
- package/src/deltat/deep-time.cjs +36 -92
- package/src/deltat/recession-history.cjs +2 -1
- package/src/earth/deep-orbital-history.cjs +4 -4
- package/src/earth/frame-of-date.cjs +25 -1
- package/src/earth/precession-composed.cjs +3 -3
- package/src/earth/year-lengths.cjs +16 -1
- package/src/eclipse/sun-planetary-completion.cjs +11 -12
- package/src/index.js +28 -48
- package/src/layer0/derive-params.js +10 -5
- package/src/layer0/index.js +27 -73
- package/src/layer1/index.js +6 -37
- package/src/model.js +200 -225
- package/src/moon/arguments.cjs +57 -83
- package/src/moon/deep-modes-artifact.cjs +2 -2
- package/src/moon/month-chain.cjs +25 -59
- package/src/moon/series.cjs +14 -10
- package/src/phase/deep-calendar.cjs +35 -80
- package/src/planets/chain-artifact.js +2 -2
- package/src/planets/display-names.cjs +30 -0
- package/src/planets/geometry.cjs +79 -29
- package/src/planets/model.cjs +12 -11
- package/src/planets/spin-channel.cjs +46 -2
- package/types/chain-cycles/index.d.cts +9 -4
- package/types/climate/l1-orbital.d.cts +3 -1
- package/types/constants/coefficients.d.ts +17 -93
- package/types/constants/generated.d.ts +18 -156
- package/types/deltat/deep-time.d.cts +3 -16
- package/types/earth/frame-of-date.d.cts +9 -0
- package/types/earth/year-lengths.d.cts +12 -0
- package/types/eclipse/sun-planetary-completion.d.cts +0 -9
- package/types/index.d.ts +4 -13
- package/types/layer0/derive-params.d.ts +7 -4
- package/types/layer0/index.d.ts +6 -13
- package/types/layer1/index.d.ts +0 -2
- package/types/model.d.ts +8 -6
- package/types/moon/arguments.d.cts +23 -22
- package/types/moon/deep-modes-artifact.d.cts +3 -3
- package/types/moon/month-chain.d.cts +7 -16
- package/types/moon/series.d.cts +2 -4
- package/types/phase/deep-calendar.d.cts +14 -50
- package/types/planets/display-names.d.cts +2 -0
- package/types/planets/geometry.d.cts +36 -13
- package/types/planets/model.d.cts +7 -6
- package/types/planets/spin-channel.d.cts +4 -0
- package/src/cardinal/index.cjs +0 -324
- package/src/moon/ecc-channel.cjs +0 -141
- package/src/phase/index.cjs +0 -186
- package/src/planets/ecc-channel.cjs +0 -59
- package/src/sun/longitude-correction.cjs +0 -68
- package/types/cardinal/index.d.cts +0 -80
- package/types/moon/ecc-channel.d.cts +0 -30
- package/types/phase/index.d.cts +0 -38
- package/types/planets/ecc-channel.d.cts +0 -20
- package/types/sun/longitude-correction.d.cts +0 -41
package/src/moon/ecc-channel.cjs
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Moon-channel eccentricity line — THE shared implementation (Phase 8.2-2).
|
|
3
|
-
*
|
|
4
|
-
* ONE movement, FULLY DERIVED, zero solved values (doc 66 §"Framework-native
|
|
5
|
-
* e_E"): e(t) = eccentricityBase · (1 + cos θ(t) / 2), where θ rides the H/3
|
|
6
|
-
* wobble cycle that drives Earth's inclination. Mean = base (Law 5),
|
|
7
|
-
* amplitude = base/2, phase anchor θ₀ = ϖ_ICRF(J2000) − 21.77° = 81.18° past
|
|
8
|
-
* max. The observed J2000 e (−0.86%), ė (+1.7%) and the sign of ë are
|
|
9
|
-
* PREDICTIONS of this line, not inputs.
|
|
10
|
-
*
|
|
11
|
-
* DOMAIN (engine-switch decision (ii) restatement, plan 02 §8): this H/3
|
|
12
|
-
* line is the CLOCK-side e — the eclipse Sun's equation of centre (FQ-7-Sun
|
|
13
|
-
* option C-small, doc 66 §5), the besselian Sun distance, the cardinal
|
|
14
|
-
* braid and the scene machinery ride it. The LUNAR chain (E-factor,
|
|
15
|
-
* modulation, channelIntegral, argument Δe²) rides the ONE deep e
|
|
16
|
-
* (deep-ecc-channel.cjs — the engine's own ±10-Myr z-vector); the two
|
|
17
|
-
* agree within 4.2e-5 across the historical era, and this line keeps its
|
|
18
|
-
* E18 role as the epoch-local tangent. Eccentricity remains
|
|
19
|
-
* frame-invariant (fixed-frame periods only); the H/16 perihelion cycle
|
|
20
|
-
* (the H/3 rotation seen from the H/13 equinox, 13 + 3 = 16) belongs to
|
|
21
|
-
* ϖ, not e (doc 108).
|
|
22
|
-
*
|
|
23
|
-
* Extracted VERBATIM from src/script.js (_FW_ECC, _fwEarthEcc,
|
|
24
|
-
* _eCompModulation, _fwChannelIntegral, the framework branch of _fwEFactor),
|
|
25
|
-
* which tools/lib mirrored; this file replaces both copies. The 8.2-1
|
|
26
|
-
* alignment made the two engines bit-exact first, so this move is provably
|
|
27
|
-
* behaviour-preserving against the lunar golden masters.
|
|
28
|
-
*
|
|
29
|
-
* LOAD-BEARING conventions:
|
|
30
|
-
* - The injected `cyclesBetween` is the ENGINE'S OWN integrated-phase
|
|
31
|
-
* function (divisor 3 on the H lattice). Each engine's deep-time/snapshot
|
|
32
|
-
* toggle semantics ride along with it.
|
|
33
|
-
* - `e0`/`g0` are ANCHOR CONSTS by construction, never eccAt(0): under
|
|
34
|
-
* integrated phase, cycles(2000→2000) carries the R3 drift correction and
|
|
35
|
-
* is not exactly zero. The tools mirror once recomputed g0 from
|
|
36
|
-
* _fwEarthEcc(0) — unified here to the const.
|
|
37
|
-
* - channelIntegral uses composite Simpson with step ≤ ~4,000 yr (N ≥ 2,
|
|
38
|
-
* even) — the discretization the certified numbers were produced with.
|
|
39
|
-
* - Past the tidal-lock asymptote (cyclesBetween → null) eccAt returns the
|
|
40
|
-
* mean — the bounded continuation, not an error.
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
'use strict';
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @param {{
|
|
47
|
-
* cyclesBetween: (yearA: number, yearB: number, divisorN: number) => (number | null),
|
|
48
|
-
* eccentricityBase: number,
|
|
49
|
-
* eccentricityJ2000?: number,
|
|
50
|
-
* perihelionLongitudeJ2000Deg: number,
|
|
51
|
-
* inclinationCycleAnchorDeg: number,
|
|
52
|
-
* }} deps — cyclesBetween MUST be the engine's own H-lattice phase counter
|
|
53
|
-
* (integrated under deep time); perihelionLongitudeJ2000Deg is ϖ_ICRF at
|
|
54
|
-
* J2000 (102.94719°, the FULL value — a truncated copy once cost 0.684″);
|
|
55
|
-
* inclinationCycleAnchorDeg is the H/3 inclination anchor (21.77°).
|
|
56
|
-
*/
|
|
57
|
-
function createMoonEccChannel({
|
|
58
|
-
cyclesBetween,
|
|
59
|
-
eccentricityBase,
|
|
60
|
-
perihelionLongitudeJ2000Deg,
|
|
61
|
-
inclinationCycleAnchorDeg,
|
|
62
|
-
eccentricityJ2000,
|
|
63
|
-
}) {
|
|
64
|
-
const th0 = (perihelionLongitudeJ2000Deg - inclinationCycleAnchorDeg) * Math.PI / 180;
|
|
65
|
-
// ECCENTRICITY UNIFICATION (plan IP-eccentricity-unification, D1 = form
|
|
66
|
-
// (e)): this line is the model's ONE eccentricity law for every consumer
|
|
67
|
-
// (eclipse Sun, Sun distance, Moon E-factor and T² channel, cardinal
|
|
68
|
-
// braid, scene). When the observed J2000 eccentricity is supplied the
|
|
69
|
-
// mean is DERIVED from it and the shared anchor — base' = e0 / (1 +
|
|
70
|
-
// cos θ₀ / 2) = 0.015520 — so e(J2000) is exact by construction; the
|
|
71
|
-
// legacy form (mean = the Law-5 base, e(J2000) a −0.86% prediction) is
|
|
72
|
-
// kept for callers that do not supply it.
|
|
73
|
-
const mean = eccentricityJ2000 !== undefined
|
|
74
|
-
? eccentricityJ2000 / (1 + Math.cos(th0) / 2)
|
|
75
|
-
: eccentricityBase;
|
|
76
|
-
const amplitude = mean / 2;
|
|
77
|
-
const e0 = mean + amplitude * Math.cos(th0); // J2000 anchor, exact by construction
|
|
78
|
-
const g0 = Math.pow(1 - e0 * e0, -1.5); // (1−e²)^(−3/2) at the anchor
|
|
79
|
-
|
|
80
|
-
/** e_E on the H/3 line at tYr years from J2000 (negative = past).
|
|
81
|
-
* Returns the mean past the tidal-lock asymptote.
|
|
82
|
-
* @param {number} tYr @returns {number} */
|
|
83
|
-
function eccAt(tYr) {
|
|
84
|
-
const cycles = cyclesBetween(2000, 2000 + tYr, 3);
|
|
85
|
-
if (cycles === null) return mean;
|
|
86
|
-
return mean + amplitude * Math.cos(th0 + 2 * Math.PI * cycles);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/** [g(e(t))/g₀]^s — the perigee/node rate modulation, ≡ 1 at J2000.
|
|
90
|
-
* tMa is age in Myr (positive = past, the deep-time chain convention).
|
|
91
|
-
* @param {number} tMa @param {number} s @returns {number} */
|
|
92
|
-
function modulation(tMa, s) {
|
|
93
|
-
if (tMa === 0) return 1;
|
|
94
|
-
const e = eccAt(-tMa * 1e6);
|
|
95
|
-
return Math.pow(Math.pow(1 - e * e, -1.5) / g0, s);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** ∫₀ᵀ [(g(e(t′))/g₀)^s − 1] dt′ in Julian centuries — the phase-aware
|
|
99
|
-
* channel-rate integral (the old frozen-κ T²/T³ Taylor coefficients were
|
|
100
|
-
* this integral's J2000 truncation). Composite Simpson, step ≤ ~4 kyr.
|
|
101
|
-
* @param {number} T @param {number} s @returns {number} */
|
|
102
|
-
function channelIntegral(T, s) {
|
|
103
|
-
if (T === 0) return 0;
|
|
104
|
-
/** @param {number} t */
|
|
105
|
-
const f = (t) => {
|
|
106
|
-
const e = eccAt(t * 100); // t in cy → years
|
|
107
|
-
return Math.pow(Math.pow(1 - e * e, -1.5) / g0, s) - 1;
|
|
108
|
-
};
|
|
109
|
-
const N = Math.max(2, 2 * Math.ceil(Math.abs(T) * 100 / 8000));
|
|
110
|
-
const h = T / N;
|
|
111
|
-
let sum = f(0) + f(T);
|
|
112
|
-
for (let i = 1; i < N; i++) sum += f(i * h) * (i % 2 ? 4 : 2);
|
|
113
|
-
return sum * h / 3;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Bounded Meeus E-factor: E ≡ e_E(t)/e_E(J2000), value 1 at J2000 by
|
|
117
|
-
* construction. The caller supplies tYr = days-from-J2000 / mean solar
|
|
118
|
-
* year; the pure-Meeus A/B polynomial branch stays ENGINE-LOCAL with its
|
|
119
|
-
* mode toggle. @param {number} tYr @returns {number} */
|
|
120
|
-
function eFactorAt(tYr) {
|
|
121
|
-
return eccAt(tYr) / e0;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** de/dyear of the line at tYr years from J2000 (the cardinal braid's
|
|
125
|
-
* equation-of-centre derivative): −amplitude·sin(θ)·dθ/dt, with dθ/dt
|
|
126
|
-
* from the phase counter's two-point difference over ±1 yr (exact for a
|
|
127
|
-
* linear phase, ppm-class under the integrated one). Returns 0 past the
|
|
128
|
-
* tidal-lock asymptote, where eccAt returns the mean.
|
|
129
|
-
* @param {number} tYr @returns {number} */
|
|
130
|
-
function eccRateAt(tYr) {
|
|
131
|
-
const c = cyclesBetween(2000, 2000 + tYr, 3);
|
|
132
|
-
if (c === null) return 0;
|
|
133
|
-
const cp = cyclesBetween(2000, 2000 + tYr + 1, 3), cm = cyclesBetween(2000, 2000 + tYr - 1, 3);
|
|
134
|
-
const dth = 2 * Math.PI * ((cp === null || cm === null) ? 0 : (cp - cm) / 2);
|
|
135
|
-
return -amplitude * Math.sin(th0 + 2 * Math.PI * c) * dth;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return { eccAt, eccRateAt, modulation, channelIntegral, eFactorAt, th0, amplitude, mean, e0, g0 };
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
module.exports = { createMoonEccChannel };
|
package/src/phase/index.cjs
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integrated-phase machinery — THE shared implementation (Phase 7.1).
|
|
3
|
-
*
|
|
4
|
-
* The cumulative ∫1/H(t)dt table and everything derived from it: cycle counts,
|
|
5
|
-
* the J2000 drift correction, and the inverse lookup. Extracted VERBATIM from
|
|
6
|
-
* tools/lib/deep-time.js, which was itself the port of src/script.js — this
|
|
7
|
-
* file replaces both copies (and is the reference the website's deepTime.ts
|
|
8
|
-
* must match; Phase E measured what happens when it doesn't).
|
|
9
|
-
*
|
|
10
|
-
* CommonJS on purpose: `tools/lib` is CJS and cannot require an ESM module
|
|
11
|
-
* synchronously; ESM (`src/script.js`, bundlers) imports CJS natively. One
|
|
12
|
-
* file, every engine.
|
|
13
|
-
*
|
|
14
|
-
* THE CONVENTIONS ARE LOAD-BEARING — the fitted coefficients were produced
|
|
15
|
-
* against THIS discretization, so the numerics ship with the coefficients:
|
|
16
|
-
*
|
|
17
|
-
* - TRAPEZOID rule on 10-kyr cells with LINEAR interpolation between cells.
|
|
18
|
-
* An analytically better integrator is WRONG here: the website's adaptive
|
|
19
|
-
* Simpson disagreed by ~1e-6 cycles at −280 kyr = ~18 s of cardinal-point
|
|
20
|
-
* JD through the ×16 braid phase (Gate E measured 24.7 s before the fix).
|
|
21
|
-
* - R2: the table must be built under the LATTICE α — the CONSTANT moment of
|
|
22
|
-
* inertia, not the climate-modulated α(t). The `holisticHAtAgeMa` the
|
|
23
|
-
* caller injects must already be pinned (see each engine's construction
|
|
24
|
-
* site). The always-on climate modulation integrates into a linear phase
|
|
25
|
-
* drift (the same ~18 s class — the dominant Phase E bug).
|
|
26
|
-
* - R3: the drift-correction anchor is identified by CALL SHAPE, never by
|
|
27
|
-
* distance from J2000 — the old distance heuristic put a 2·drift
|
|
28
|
-
* = 6.80e-5-cycle STEP DISCONTINUITY at yearB == yearA, worth 0.393 d of
|
|
29
|
-
* apsis displacement and 100% of 6d's anomalistic residual.
|
|
30
|
-
* - The table zero sits at the cell nearest `tableAnchorYear` (2000.5,
|
|
31
|
-
* startmodelYear); the drift reference is `driftRefYear`
|
|
32
|
-
* (startModelYearWithCorrection ≈ 2000.4977) — TWO different constants,
|
|
33
|
-
* half a day apart. Do not "unify" them.
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
'use strict';
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @param {{
|
|
40
|
-
* holisticHAtAgeMa: (tMa: number) => (number | null),
|
|
41
|
-
* tableAnchorYear: number,
|
|
42
|
-
* driftRefYear: number,
|
|
43
|
-
* hJ2000: number,
|
|
44
|
-
* yearMin?: number,
|
|
45
|
-
* yearMax?: number,
|
|
46
|
-
* stepYears?: number,
|
|
47
|
-
* }} cfg — holisticHAtAgeMa MUST be the lattice-α form; tableAnchorYear is
|
|
48
|
-
* startmodelYear (2000.5, table zero + t_Ma convention); driftRefYear is
|
|
49
|
-
* startModelYearWithCorrection (the R3 drift anchor); hJ2000 the snapshot
|
|
50
|
-
* rate the drift compares against; 10-kyr cells match both engines'
|
|
51
|
-
* historic tables.
|
|
52
|
-
*/
|
|
53
|
-
function createPhaseMachinery({
|
|
54
|
-
holisticHAtAgeMa,
|
|
55
|
-
tableAnchorYear,
|
|
56
|
-
driftRefYear,
|
|
57
|
-
hJ2000,
|
|
58
|
-
yearMin = -500e6,
|
|
59
|
-
yearMax = 500e6,
|
|
60
|
-
stepYears = 10000,
|
|
61
|
-
}) {
|
|
62
|
-
/** @type {Float64Array | null} */
|
|
63
|
-
let table = null;
|
|
64
|
-
let j2000Idx = -1;
|
|
65
|
-
|
|
66
|
-
function ensureTable() {
|
|
67
|
-
if (table !== null) return;
|
|
68
|
-
const N = Math.ceil((yearMax - yearMin) / stepYears) + 1;
|
|
69
|
-
const t = new Float64Array(N);
|
|
70
|
-
j2000Idx = Math.round((tableAnchorYear - yearMin) / stepYears);
|
|
71
|
-
|
|
72
|
-
/** @param {number} year */
|
|
73
|
-
const invH = (year) => {
|
|
74
|
-
const t_Ma = (tableAnchorYear - year) / 1e6;
|
|
75
|
-
const H = holisticHAtAgeMa(t_Ma);
|
|
76
|
-
return H === null ? null : 1 / H;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
t[j2000Idx] = 0;
|
|
80
|
-
let prev = invH(yearMin + j2000Idx * stepYears);
|
|
81
|
-
for (let i = j2000Idx + 1; i < N; i++) {
|
|
82
|
-
const year_i = yearMin + i * stepYears;
|
|
83
|
-
const curr = invH(year_i);
|
|
84
|
-
t[i] = (prev !== null && curr !== null)
|
|
85
|
-
? t[i - 1] + 0.5 * (prev + curr) * stepYears
|
|
86
|
-
: NaN;
|
|
87
|
-
prev = curr;
|
|
88
|
-
}
|
|
89
|
-
prev = invH(yearMin + j2000Idx * stepYears);
|
|
90
|
-
for (let i = j2000Idx - 1; i >= 0; i--) {
|
|
91
|
-
const year_i = yearMin + i * stepYears;
|
|
92
|
-
const curr = invH(year_i);
|
|
93
|
-
t[i] = (prev !== null && curr !== null)
|
|
94
|
-
? t[i + 1] - 0.5 * (prev + curr) * stepYears
|
|
95
|
-
: NaN;
|
|
96
|
-
prev = curr;
|
|
97
|
-
}
|
|
98
|
-
table = t;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** Cumulative ∫1/H at a year (linear interpolation). null outside the range
|
|
102
|
-
* or where the physics is undefined (past the tidal-lock asymptote).
|
|
103
|
-
* @param {number} year @returns {number | null} */
|
|
104
|
-
function cumulAtYear(year) {
|
|
105
|
-
ensureTable();
|
|
106
|
-
if (year < yearMin || year > yearMax) return null;
|
|
107
|
-
const t = /** @type {Float64Array} */ (table);
|
|
108
|
-
const idx_f = (year - yearMin) / stepYears;
|
|
109
|
-
const idx_lo = Math.floor(idx_f);
|
|
110
|
-
const idx_hi = Math.min(idx_lo + 1, t.length - 1);
|
|
111
|
-
const v_lo = t[idx_lo];
|
|
112
|
-
const v_hi = t[idx_hi];
|
|
113
|
-
if (Number.isNaN(v_lo) || Number.isNaN(v_hi)) return null;
|
|
114
|
-
return v_lo + (idx_f - idx_lo) * (v_hi - v_lo);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** ∫_{yearA}^{yearB} 1/H(t') dt'. null if either endpoint is out of domain.
|
|
118
|
-
* @param {number} yearA @param {number} yearB @returns {number | null} */
|
|
119
|
-
function integralBetween(yearA, yearB) {
|
|
120
|
-
if (yearA === yearB) return 0;
|
|
121
|
-
const cA = cumulAtYear(yearA);
|
|
122
|
-
const cB = cumulAtYear(yearB);
|
|
123
|
-
if (cA === null || cB === null) return null;
|
|
124
|
-
return cB - cA;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** How far the integrated form has drifted from the J2000-snapshot form over
|
|
128
|
-
* (yearA → driftRefYear). Subtracting it at the anchor restores the
|
|
129
|
-
* snapshot-fitted harmonic calibration at J2000 without changing the
|
|
130
|
-
* integrated form's shape at deep time.
|
|
131
|
-
* @param {number} yearA @returns {number} */
|
|
132
|
-
function j2000Drift(yearA) {
|
|
133
|
-
const integral = integralBetween(yearA, driftRefYear);
|
|
134
|
-
if (integral === null) return 0;
|
|
135
|
-
const snapshot = (driftRefYear - yearA) / hJ2000;
|
|
136
|
-
return integral - snapshot;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** Total cycles between two years for a cycle of period H/divisorN.
|
|
140
|
-
* R3: the anchor is identified from the CALL SHAPE — two shapes exist,
|
|
141
|
-
* (anchor, movingYear, N) and (J2000, anchor, N) where yearA IS the J2000
|
|
142
|
-
* reference itself. The correction depends only on a FIXED endpoint, so it
|
|
143
|
-
* is constant across any scan. Returns null past the tidal-lock asymptote.
|
|
144
|
-
* @param {number} yearA @param {number} yearB @param {number} divisorN
|
|
145
|
-
* @returns {number | null} */
|
|
146
|
-
function cyclesBetween(yearA, yearB, divisorN) {
|
|
147
|
-
const integral = integralBetween(yearA, yearB);
|
|
148
|
-
if (integral === null) return null;
|
|
149
|
-
const anchorIsA = (yearA !== driftRefYear);
|
|
150
|
-
const correction = anchorIsA ? j2000Drift(yearA) : -j2000Drift(yearB);
|
|
151
|
-
return divisorN * (integral - correction);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/** Inverse of cumulAtYear — the year at a given cumulative ∫1/H (binary
|
|
155
|
-
* search over the monotone table). null outside the table domain.
|
|
156
|
-
* @param {number} targetCumul @returns {number | null} */
|
|
157
|
-
function yearAtCumul(targetCumul) {
|
|
158
|
-
ensureTable();
|
|
159
|
-
const t = /** @type {Float64Array} */ (table);
|
|
160
|
-
const N = t.length;
|
|
161
|
-
let lo = 0, hi = N - 1;
|
|
162
|
-
while (lo < N && Number.isNaN(t[lo])) lo++;
|
|
163
|
-
while (hi >= 0 && Number.isNaN(t[hi])) hi--;
|
|
164
|
-
if (lo >= hi) return null;
|
|
165
|
-
if (targetCumul < t[lo] || targetCumul > t[hi]) return null;
|
|
166
|
-
while (lo < hi - 1) {
|
|
167
|
-
const mid = (lo + hi) >> 1;
|
|
168
|
-
if (t[mid] <= targetCumul) lo = mid; else hi = mid;
|
|
169
|
-
}
|
|
170
|
-
const v_lo = t[lo], v_hi = t[hi];
|
|
171
|
-
const frac = (v_lo === v_hi) ? 0 : (targetCumul - v_lo) / (v_hi - v_lo);
|
|
172
|
-
return yearMin + (lo + frac) * stepYears;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/** Grid geometry — consumed by the engines' days/pos tables, which share
|
|
176
|
-
* this grid but keep their own integrands (they move at Phase 8). */
|
|
177
|
-
function grid() {
|
|
178
|
-
ensureTable();
|
|
179
|
-
const t = /** @type {Float64Array} */ (table);
|
|
180
|
-
return { yearMin, yearMax, stepYears, j2000Idx, length: t.length };
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return { ensureTable, cumulAtYear, integralBetween, j2000Drift, cyclesBetween, yearAtCumul, grid };
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
module.exports = { createPhaseMachinery };
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Planet eccentricity channel — THE shared implementation (Phase 8.3, L3).
|
|
3
|
-
* The law-of-cosines oscillation every body's runtime eccentricity rides
|
|
4
|
-
* (Earth on H/16, each planet on its OWN wobble period — S-P1):
|
|
5
|
-
*
|
|
6
|
-
* e(t) = √(base² + amp² − 2·base·amp·cos θ), θ = 2π·N·∫1/H dt
|
|
7
|
-
*
|
|
8
|
-
* — the distance between two circular orbits (body orbits the wobble
|
|
9
|
-
* centre at radius amp; the centre orbits the Sun at radius base).
|
|
10
|
-
*
|
|
11
|
-
* Extracted from src/script.js computeEccentricityEarth (the browser's
|
|
12
|
-
* 5-arg generic form) and tools/lib/orbital-engine.js computeEccentricity
|
|
13
|
-
* (identical law; R6 aligned its phase to integrated). The structural twin
|
|
14
|
-
* of moon/ecc-channel — but a DIFFERENT law (H/16 orbit law vs the Moon
|
|
15
|
-
* channel's H/3 line; doc 66 keeps the two deliberately distinct).
|
|
16
|
-
*
|
|
17
|
-
* Engine null/toggle semantics stay ENGINE-SIDE, deliberately:
|
|
18
|
-
* - the browser's cyclesBetween carries its DEEP_TIME_MODE toggle and maps
|
|
19
|
-
* null (past tidal lock) → the MEAN eccentricity;
|
|
20
|
-
* - the Node engine pre-computes its snapshot cycles and keeps them when
|
|
21
|
-
* the integrated phase is null (its documented R6 flag polarity).
|
|
22
|
-
* Both call the same law; the dispatch difference is recorded here so
|
|
23
|
-
* nobody "unifies" it without measuring.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
'use strict';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* The law of cosines over resolved cycles. null cycles → the MEAN
|
|
30
|
-
* eccentricity √(base² + amp²) (past the tidal-lock asymptote).
|
|
31
|
-
* @param {number | null} cycles @param {number} base @param {number} amplitude
|
|
32
|
-
* @returns {number} */
|
|
33
|
-
function eccentricityFromCycles(cycles, base, amplitude) {
|
|
34
|
-
if (cycles === null) {
|
|
35
|
-
return Math.sqrt(base * base + amplitude * amplitude);
|
|
36
|
-
}
|
|
37
|
-
const phase = cycles * 2 * Math.PI;
|
|
38
|
-
return Math.sqrt(
|
|
39
|
-
base * base + amplitude * amplitude - 2 * base * amplitude * Math.cos(phase)
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Browser-convention evaluator: J2000-FIXED anchor + cycle length, divisor
|
|
45
|
-
* N = H_J2000/cycleLength, integrated phase via the injected engine
|
|
46
|
-
* cyclesBetween (toggle semantics ride along), null → mean.
|
|
47
|
-
* @param {number} currentYear @param {number} anchorYearJ2000
|
|
48
|
-
* @param {number} cycleLengthYearsJ2000 @param {number} base
|
|
49
|
-
* @param {number} amplitude
|
|
50
|
-
* @param {{ holisticYearJ2000: number,
|
|
51
|
-
* cyclesBetween: (yearA: number, yearB: number, divisorN: number) => (number | null) }} env
|
|
52
|
-
* @returns {number} */
|
|
53
|
-
function computeEccentricityIntegrated(currentYear, anchorYearJ2000, cycleLengthYearsJ2000, base, amplitude, env) {
|
|
54
|
-
const divisorN = env.holisticYearJ2000 / cycleLengthYearsJ2000;
|
|
55
|
-
const cycles = env.cyclesBetween(anchorYearJ2000, currentYear, divisorN);
|
|
56
|
-
return eccentricityFromCycles(cycles, base, amplitude);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
module.exports = { eccentricityFromCycles, computeEccentricityIntegrated };
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sun longitude correction — the fitted H-lattice harmonic stack
|
|
3
|
-
* (Phase 9, S-P8). THE shared evaluator behind what were THREE verbatim
|
|
4
|
-
* copies: the browser's sunLongitudeCorrection and two inline blocks in
|
|
5
|
-
* tools/lib/scene-graph (moveModel and the fast animator).
|
|
6
|
-
*
|
|
7
|
-
* The ~200″→~7″ RMS Sun-only correction (Phase Z-B): a fitted harmonic
|
|
8
|
-
* table on H-lattice divisors, with the H-LATTICE FILTER applied at
|
|
9
|
-
* evaluation — a divisor is structurally on-lattice iff EITHER
|
|
10
|
-
* (a) it is a year-multiple of H (integer year period), OR
|
|
11
|
-
* (b) it is a small precession divisor (1..20 — Earth's Fibonacci
|
|
12
|
-
* named cycles H/3, H/5, H/8, H/13, H/16, …), OR
|
|
13
|
-
* (c) it is one of the two lunar precession divisors (auto-tracked
|
|
14
|
-
* from the Meeus anchors).
|
|
15
|
-
* Divisors failing all three are design-rule violating and silently
|
|
16
|
-
* skipped. (Clause (d) "sharesFactorWithH" was removed 2026-07-15 — it
|
|
17
|
-
* admitted mid-range fit artifacts, divisors 84/92/115/122, that are
|
|
18
|
-
* not physically motivated. See tools/fit/sun-longitude-harmonics.js.)
|
|
19
|
-
*
|
|
20
|
-
* MATCHED PAIR: every dep is the J2000-FIXED value — the table was
|
|
21
|
-
* fitted against J2000 H and mSY (the Node engines' documented
|
|
22
|
-
* convention). The browser copy historically read the MUTABLE
|
|
23
|
-
* holisticyearLength/balancedYear globals; measured divergence under
|
|
24
|
-
* epoch shift was 8.2e-10 deg (~3 µas) — aligned onto the fitted
|
|
25
|
-
* convention at extraction (9-1), zero fixture drift.
|
|
26
|
-
*
|
|
27
|
-
* The engines own the application (θ −= corr·d2r on the Sun node only)
|
|
28
|
-
* and their enable flags.
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
'use strict';
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @typedef {Object} SunLongitudeCorrectionDeps
|
|
35
|
-
* @property {number} hYears - H, J2000-fixed (the fitted axis)
|
|
36
|
-
* @property {number} balancedYear - J2000-fixed
|
|
37
|
-
* @property {number} j2000JD
|
|
38
|
-
* @property {number} meanDeg - the fitted mean offset
|
|
39
|
-
* @property {Array<[number, number, number]>} harmonics - [divisor, sinC, cosC]
|
|
40
|
-
* @property {number} nNodalJ2000 - lunar nodal divisor (per 8H convention)
|
|
41
|
-
* @property {number} nApsidalJ2000 - lunar apsidal divisor
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
|
-
/** @param {SunLongitudeCorrectionDeps} deps */
|
|
45
|
-
function createSunLongitudeCorrection(deps) {
|
|
46
|
-
/** Correction in DEGREES at JD (subtract from the raw Sun longitude).
|
|
47
|
-
* @param {number} jd @returns {number} */
|
|
48
|
-
function correctionDegAt(jd) {
|
|
49
|
-
const year = 2000 + (jd - deps.j2000JD) / 365.25;
|
|
50
|
-
const t = year - deps.balancedYear;
|
|
51
|
-
let corr = deps.meanDeg;
|
|
52
|
-
const H_round = Math.round(deps.hYears);
|
|
53
|
-
for (const h of deps.harmonics) {
|
|
54
|
-
const divisor = h[0];
|
|
55
|
-
const isYearMultiple = divisor >= H_round && divisor % H_round === 0;
|
|
56
|
-
const isPrecessionDivisor = divisor > 0 && divisor <= 20;
|
|
57
|
-
const isLunarPrecession = divisor === deps.nNodalJ2000 || divisor === deps.nApsidalJ2000;
|
|
58
|
-
if (!isYearMultiple && !isPrecessionDivisor && !isLunarPrecession) continue;
|
|
59
|
-
const phase = 2 * Math.PI * t / (deps.hYears / divisor);
|
|
60
|
-
corr += h[1] * Math.sin(phase) + h[2] * Math.cos(phase);
|
|
61
|
-
}
|
|
62
|
-
return corr;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return { correctionDegAt };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
module.exports = { createSunLongitudeCorrection };
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
export type DerivedCoefs = {
|
|
2
|
-
lincoef: number;
|
|
3
|
-
h0: number;
|
|
4
|
-
h1: number;
|
|
5
|
-
};
|
|
6
|
-
export type EccTerm = {
|
|
7
|
-
order: number;
|
|
8
|
-
sin: number;
|
|
9
|
-
cos: number;
|
|
10
|
-
};
|
|
11
|
-
export type JointTerm = {
|
|
12
|
-
order: number;
|
|
13
|
-
div: number;
|
|
14
|
-
sin: number;
|
|
15
|
-
cos: number;
|
|
16
|
-
};
|
|
17
|
-
/** @typedef {{ lincoef: number, h0: number, h1: number }} DerivedCoefs */
|
|
18
|
-
/** @typedef {{ order: number, sin: number, cos: number }} EccTerm */
|
|
19
|
-
/** @typedef {{ order: number, div: number, sin: number, cos: number }} JointTerm */
|
|
20
|
-
/**
|
|
21
|
-
* @param {{
|
|
22
|
-
* isDeepTime: () => boolean,
|
|
23
|
-
* constants: {
|
|
24
|
-
* anchors: Record<string, number>,
|
|
25
|
-
* harmonics: Record<string, Array<[number, number, number]>>,
|
|
26
|
-
* eccTerms: (Record<string, EccTerm[]> | null),
|
|
27
|
-
* jointTerms: ({ terms: JointTerm[] } | null),
|
|
28
|
-
* derived: (DerivedCoefs | null),
|
|
29
|
-
* tropicalHarmonics: Array<[number, number, number]>,
|
|
30
|
-
* balancedYear: number,
|
|
31
|
-
* meanSolarYearDays: number,
|
|
32
|
-
* hJ2000: number,
|
|
33
|
-
* tiltMeanDeg: number,
|
|
34
|
-
* raAngleDeg: number,
|
|
35
|
-
* inclAmplitudeDeg: number,
|
|
36
|
-
* },
|
|
37
|
-
* fns: {
|
|
38
|
-
* cyclesBetween: (yearA: number, yearB: number, divisorN: number) => (number | null),
|
|
39
|
-
* analyticTropicalDays: (year: number) => (number | null),
|
|
40
|
-
* meanHAtAgeMa: (tMa: number) => (number | null),
|
|
41
|
-
* meanYearRealLodDays: (tMa: number) => (number | null),
|
|
42
|
-
* eccentricityAt: (year: number) => number,
|
|
43
|
-
* eccentricityRateAt: (year: number) => number,
|
|
44
|
-
* },
|
|
45
|
-
* }} deps
|
|
46
|
-
*/
|
|
47
|
-
export function createCardinalModel({ isDeepTime, constants, fns }: {
|
|
48
|
-
isDeepTime: () => boolean;
|
|
49
|
-
constants: {
|
|
50
|
-
anchors: Record<string, number>;
|
|
51
|
-
harmonics: Record<string, Array<[number, number, number]>>;
|
|
52
|
-
eccTerms: (Record<string, EccTerm[]> | null);
|
|
53
|
-
jointTerms: ({
|
|
54
|
-
terms: JointTerm[];
|
|
55
|
-
} | null);
|
|
56
|
-
derived: (DerivedCoefs | null);
|
|
57
|
-
tropicalHarmonics: Array<[number, number, number]>;
|
|
58
|
-
balancedYear: number;
|
|
59
|
-
meanSolarYearDays: number;
|
|
60
|
-
hJ2000: number;
|
|
61
|
-
tiltMeanDeg: number;
|
|
62
|
-
raAngleDeg: number;
|
|
63
|
-
inclAmplitudeDeg: number;
|
|
64
|
-
};
|
|
65
|
-
fns: {
|
|
66
|
-
cyclesBetween: (yearA: number, yearB: number, divisorN: number) => (number | null);
|
|
67
|
-
analyticTropicalDays: (year: number) => (number | null);
|
|
68
|
-
meanHAtAgeMa: (tMa: number) => (number | null);
|
|
69
|
-
meanYearRealLodDays: (tMa: number) => (number | null);
|
|
70
|
-
eccentricityAt: (year: number) => number;
|
|
71
|
-
eccentricityRateAt: (year: number) => number;
|
|
72
|
-
};
|
|
73
|
-
}): {
|
|
74
|
-
computeSolsticeJD: (year: number, type?: string) => number;
|
|
75
|
-
computeSolsticeYearLength: (year: number, type?: string) => number;
|
|
76
|
-
computeSolsticeRA: (year: number, type?: string) => number;
|
|
77
|
-
computeTropicalYearLength: (year: number) => number;
|
|
78
|
-
};
|
|
79
|
-
/** @type {Record<string, number>} */
|
|
80
|
-
export const JOINT_LAMBDA: Record<string, number>;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param {{
|
|
3
|
-
* cyclesBetween: (yearA: number, yearB: number, divisorN: number) => (number | null),
|
|
4
|
-
* eccentricityBase: number,
|
|
5
|
-
* eccentricityJ2000?: number,
|
|
6
|
-
* perihelionLongitudeJ2000Deg: number,
|
|
7
|
-
* inclinationCycleAnchorDeg: number,
|
|
8
|
-
* }} deps — cyclesBetween MUST be the engine's own H-lattice phase counter
|
|
9
|
-
* (integrated under deep time); perihelionLongitudeJ2000Deg is ϖ_ICRF at
|
|
10
|
-
* J2000 (102.94719°, the FULL value — a truncated copy once cost 0.684″);
|
|
11
|
-
* inclinationCycleAnchorDeg is the H/3 inclination anchor (21.77°).
|
|
12
|
-
*/
|
|
13
|
-
export function createMoonEccChannel({ cyclesBetween, eccentricityBase, perihelionLongitudeJ2000Deg, inclinationCycleAnchorDeg, eccentricityJ2000, }: {
|
|
14
|
-
cyclesBetween: (yearA: number, yearB: number, divisorN: number) => (number | null);
|
|
15
|
-
eccentricityBase: number;
|
|
16
|
-
eccentricityJ2000?: number;
|
|
17
|
-
perihelionLongitudeJ2000Deg: number;
|
|
18
|
-
inclinationCycleAnchorDeg: number;
|
|
19
|
-
}): {
|
|
20
|
-
eccAt: (tYr: number) => number;
|
|
21
|
-
eccRateAt: (tYr: number) => number;
|
|
22
|
-
modulation: (tMa: number, s: number) => number;
|
|
23
|
-
channelIntegral: (T: number, s: number) => number;
|
|
24
|
-
eFactorAt: (tYr: number) => number;
|
|
25
|
-
th0: number;
|
|
26
|
-
amplitude: number;
|
|
27
|
-
mean: number;
|
|
28
|
-
e0: number;
|
|
29
|
-
g0: number;
|
|
30
|
-
};
|
package/types/phase/index.d.cts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param {{
|
|
3
|
-
* holisticHAtAgeMa: (tMa: number) => (number | null),
|
|
4
|
-
* tableAnchorYear: number,
|
|
5
|
-
* driftRefYear: number,
|
|
6
|
-
* hJ2000: number,
|
|
7
|
-
* yearMin?: number,
|
|
8
|
-
* yearMax?: number,
|
|
9
|
-
* stepYears?: number,
|
|
10
|
-
* }} cfg — holisticHAtAgeMa MUST be the lattice-α form; tableAnchorYear is
|
|
11
|
-
* startmodelYear (2000.5, table zero + t_Ma convention); driftRefYear is
|
|
12
|
-
* startModelYearWithCorrection (the R3 drift anchor); hJ2000 the snapshot
|
|
13
|
-
* rate the drift compares against; 10-kyr cells match both engines'
|
|
14
|
-
* historic tables.
|
|
15
|
-
*/
|
|
16
|
-
export function createPhaseMachinery({ holisticHAtAgeMa, tableAnchorYear, driftRefYear, hJ2000, yearMin, yearMax, stepYears, }: {
|
|
17
|
-
holisticHAtAgeMa: (tMa: number) => (number | null);
|
|
18
|
-
tableAnchorYear: number;
|
|
19
|
-
driftRefYear: number;
|
|
20
|
-
hJ2000: number;
|
|
21
|
-
yearMin?: number;
|
|
22
|
-
yearMax?: number;
|
|
23
|
-
stepYears?: number;
|
|
24
|
-
}): {
|
|
25
|
-
ensureTable: () => void;
|
|
26
|
-
cumulAtYear: (year: number) => number | null;
|
|
27
|
-
integralBetween: (yearA: number, yearB: number) => number | null;
|
|
28
|
-
j2000Drift: (yearA: number) => number;
|
|
29
|
-
cyclesBetween: (yearA: number, yearB: number, divisorN: number) => number | null;
|
|
30
|
-
yearAtCumul: (targetCumul: number) => number | null;
|
|
31
|
-
grid: () => {
|
|
32
|
-
yearMin: number;
|
|
33
|
-
yearMax: number;
|
|
34
|
-
stepYears: number;
|
|
35
|
-
j2000Idx: number;
|
|
36
|
-
length: number;
|
|
37
|
-
};
|
|
38
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The law of cosines over resolved cycles. null cycles → the MEAN
|
|
3
|
-
* eccentricity √(base² + amp²) (past the tidal-lock asymptote).
|
|
4
|
-
* @param {number | null} cycles @param {number} base @param {number} amplitude
|
|
5
|
-
* @returns {number} */
|
|
6
|
-
export function eccentricityFromCycles(cycles: number | null, base: number, amplitude: number): number;
|
|
7
|
-
/**
|
|
8
|
-
* Browser-convention evaluator: J2000-FIXED anchor + cycle length, divisor
|
|
9
|
-
* N = H_J2000/cycleLength, integrated phase via the injected engine
|
|
10
|
-
* cyclesBetween (toggle semantics ride along), null → mean.
|
|
11
|
-
* @param {number} currentYear @param {number} anchorYearJ2000
|
|
12
|
-
* @param {number} cycleLengthYearsJ2000 @param {number} base
|
|
13
|
-
* @param {number} amplitude
|
|
14
|
-
* @param {{ holisticYearJ2000: number,
|
|
15
|
-
* cyclesBetween: (yearA: number, yearB: number, divisorN: number) => (number | null) }} env
|
|
16
|
-
* @returns {number} */
|
|
17
|
-
export function computeEccentricityIntegrated(currentYear: number, anchorYearJ2000: number, cycleLengthYearsJ2000: number, base: number, amplitude: number, env: {
|
|
18
|
-
holisticYearJ2000: number;
|
|
19
|
-
cyclesBetween: (yearA: number, yearB: number, divisorN: number) => (number | null);
|
|
20
|
-
}): number;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export type SunLongitudeCorrectionDeps = {
|
|
2
|
-
/**
|
|
3
|
-
* - H, J2000-fixed (the fitted axis)
|
|
4
|
-
*/
|
|
5
|
-
hYears: number;
|
|
6
|
-
/**
|
|
7
|
-
* - J2000-fixed
|
|
8
|
-
*/
|
|
9
|
-
balancedYear: number;
|
|
10
|
-
j2000JD: number;
|
|
11
|
-
/**
|
|
12
|
-
* - the fitted mean offset
|
|
13
|
-
*/
|
|
14
|
-
meanDeg: number;
|
|
15
|
-
/**
|
|
16
|
-
* - [divisor, sinC, cosC]
|
|
17
|
-
*/
|
|
18
|
-
harmonics: Array<[number, number, number]>;
|
|
19
|
-
/**
|
|
20
|
-
* - lunar nodal divisor (per 8H convention)
|
|
21
|
-
*/
|
|
22
|
-
nNodalJ2000: number;
|
|
23
|
-
/**
|
|
24
|
-
* - lunar apsidal divisor
|
|
25
|
-
*/
|
|
26
|
-
nApsidalJ2000: number;
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* @typedef {Object} SunLongitudeCorrectionDeps
|
|
30
|
-
* @property {number} hYears - H, J2000-fixed (the fitted axis)
|
|
31
|
-
* @property {number} balancedYear - J2000-fixed
|
|
32
|
-
* @property {number} j2000JD
|
|
33
|
-
* @property {number} meanDeg - the fitted mean offset
|
|
34
|
-
* @property {Array<[number, number, number]>} harmonics - [divisor, sinC, cosC]
|
|
35
|
-
* @property {number} nNodalJ2000 - lunar nodal divisor (per 8H convention)
|
|
36
|
-
* @property {number} nApsidalJ2000 - lunar apsidal divisor
|
|
37
|
-
*/
|
|
38
|
-
/** @param {SunLongitudeCorrectionDeps} deps */
|
|
39
|
-
export function createSunLongitudeCorrection(deps: SunLongitudeCorrectionDeps): {
|
|
40
|
-
correctionDegAt: (jd: number) => number;
|
|
41
|
-
};
|