@essrt/physics 23.3.2 → 23.6.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 -1
- package/package.json +2 -2
- package/src/constants/coefficients.d.ts +5 -1
- package/src/constants/coefficients.js +3 -2
- package/src/constants/generated.d.ts +2 -3
- package/src/constants/generated.js +3 -4
- package/src/constants/units.cjs +4 -1
- package/src/deltat/deep-time.cjs +37 -72
- package/src/index.js +35 -48
- package/src/model/cardinal-instants.js +101 -0
- package/src/model/context.js +54 -0
- package/src/model/deep-time-chain.js +79 -0
- package/src/model/delta-t.js +38 -0
- package/src/model/derived-constants.js +58 -0
- package/src/model/earth-scalars.js +47 -0
- package/src/model/inv-plane-elements.js +56 -0
- package/src/model/lunar-theory.js +216 -0
- package/src/model/moon-epoch.js +28 -0
- package/src/model/one-source-movement.js +192 -0
- package/src/model/planet-elements-of-date.js +61 -0
- package/src/model/planet-records.js +63 -0
- package/src/model/planet-spin-channel.js +41 -0
- package/src/model/published-periods.js +38 -0
- package/src/model/sun-and-eclipses.js +199 -0
- package/src/model/surface.js +330 -0
- package/src/model/time-axis.js +24 -0
- package/src/model/year-day-lengths.js +42 -0
- package/src/model.js +62 -1612
- package/src/moon/arguments.cjs +27 -43
- package/src/planets/chain-artifact.js +2 -2
- package/src/planets/keplerian-chain.cjs +1 -1
- package/types/constants/coefficients.d.ts +5 -1
- package/types/constants/generated.d.ts +2 -3
- package/types/constants/units.d.cts +3 -0
- package/types/deltat/deep-time.d.cts +18 -24
- package/types/index.d.ts +1 -1
- package/types/model/cardinal-instants.d.ts +14 -0
- package/types/model/context.d.ts +87 -0
- package/types/model/deep-time-chain.d.ts +288 -0
- package/types/model/delta-t.d.ts +11 -0
- package/types/model/derived-constants.d.ts +25 -0
- package/types/model/earth-scalars.d.ts +14 -0
- package/types/model/inv-plane-elements.d.ts +6 -0
- package/types/model/lunar-theory.d.ts +72 -0
- package/types/model/moon-epoch.d.ts +10 -0
- package/types/model/one-source-movement.d.ts +74 -0
- package/types/model/planet-elements-of-date.d.ts +9 -0
- package/types/model/planet-records.d.ts +7 -0
- package/types/model/planet-spin-channel.d.ts +29 -0
- package/types/model/published-periods.d.ts +7 -0
- package/types/model/sun-and-eclipses.d.ts +52 -0
- package/types/model/surface.d.ts +279 -0
- package/types/model/time-axis.d.ts +12 -0
- package/types/model/year-day-lengths.d.ts +8 -0
- package/types/model.d.ts +9 -81
- package/types/moon/arguments.d.cts +5 -11
- package/types/planets/keplerian-chain.d.cts +3 -1
package/src/model.js
CHANGED
|
@@ -8,6 +8,16 @@
|
|
|
8
8
|
* eventual tools/lib adapter collapse swaps onto it instead of keeping a
|
|
9
9
|
* private twin.
|
|
10
10
|
*
|
|
11
|
+
* The wiring is COMPOSED here from named slices (./model/): each slice file
|
|
12
|
+
* assembles one family of quantities from the context the earlier slices
|
|
13
|
+
* built and returns the bindings the later ones read — a reader finds the
|
|
14
|
+
* obliquity of date in model/one-source-movement.js, the eclipse finders in
|
|
15
|
+
* model/sun-and-eclipses.js, the published object in model/surface.js. The
|
|
16
|
+
* slices run in dependency order on ONE shared context object, so every memo
|
|
17
|
+
* and sampler exists once; the few bindings a slice reads at call time from a
|
|
18
|
+
* later slice are the `late` set (model/context.js), filled below as each
|
|
19
|
+
* owner returns.
|
|
20
|
+
*
|
|
11
21
|
* Counterfactuals are first-class (§2d): the context validation and the
|
|
12
22
|
* counterfactual hashing live in index.js's `createModel`, which composes
|
|
13
23
|
* this assembly with the resolved, frozen context. This module stays pure
|
|
@@ -17,40 +27,23 @@
|
|
|
17
27
|
* src/lib/essrt.ts) operation-for-operation where FP association matters,
|
|
18
28
|
* which itself mirrors tools/lib/constants.js §9.
|
|
19
29
|
*/
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import { createEclipseFinders } from './eclipse/finders.cjs';
|
|
38
|
-
import { createBesselian } from './eclipse/besselian.cjs';
|
|
39
|
-
import { driver2PeriodSecondsAtAge } from './planets/orbit-chain.cjs';
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* RA-day-offset Fourier amplitudes (ms). KNOWN EXCEPTION carried over from
|
|
43
|
-
* the reference adapters: these are fit results that live as literals in the
|
|
44
|
-
* engine too — packaging them into FITTED_COEFFICIENTS is the remaining
|
|
45
|
-
* §7a-step-1b move; until then this is their single packaged home.
|
|
46
|
-
*/
|
|
47
|
-
// (Plan 07 R10 moved the RA day offset's two cosine amplitudes from literals
|
|
48
|
-
// here into F.RA_DAY_OFFSET_MS; plan 09 step 5b deleted that family — it was
|
|
49
|
-
// the equation of time's window term of an instrument, not a motion.)
|
|
50
|
-
|
|
51
|
-
// (The Moon-channel eccentricity sensitivities s_ϖ/s_Ω — the [g/g₀]^s exponents of
|
|
52
|
-
// the factored deep-time law — have ONE home since plan 13 B2:
|
|
53
|
-
// deltat/deep-time-chain.js MOON_ECC_SENSITIVITY_PERIGEE / _NODE.)
|
|
30
|
+
import { assembleDerivedConstants } from './model/derived-constants.js';
|
|
31
|
+
import { assembleDeepTimeChain } from './model/deep-time-chain.js';
|
|
32
|
+
import { assembleEarthScalars } from './model/earth-scalars.js';
|
|
33
|
+
import { assembleYearDayLengths } from './model/year-day-lengths.js';
|
|
34
|
+
import { assembleOneSourceMovement } from './model/one-source-movement.js';
|
|
35
|
+
import { assembleMoonEpoch } from './model/moon-epoch.js';
|
|
36
|
+
import { assembleDeltaT } from './model/delta-t.js';
|
|
37
|
+
import { assemblePlanetRecords } from './model/planet-records.js';
|
|
38
|
+
import { assemblePlanetSpinChannel } from './model/planet-spin-channel.js';
|
|
39
|
+
import { assemblePlanetElementsOfDate } from './model/planet-elements-of-date.js';
|
|
40
|
+
import { assembleInvPlaneElements } from './model/inv-plane-elements.js';
|
|
41
|
+
import { assembleTimeAxis } from './model/time-axis.js';
|
|
42
|
+
import { assembleLunarTheory } from './model/lunar-theory.js';
|
|
43
|
+
import { assembleSunAndEclipses } from './model/sun-and-eclipses.js';
|
|
44
|
+
import { assemblePublishedPeriods } from './model/published-periods.js';
|
|
45
|
+
import { assembleCardinalInstants } from './model/cardinal-instants.js';
|
|
46
|
+
import { assembleSurface } from './model/surface.js';
|
|
54
47
|
|
|
55
48
|
/**
|
|
56
49
|
* Assemble the model surfaces from a resolved constants context + fitted
|
|
@@ -59,1584 +52,41 @@ import { driver2PeriodSecondsAtAge } from './planets/orbit-chain.cjs';
|
|
|
59
52
|
*
|
|
60
53
|
* @param {Readonly<Record<string, any>>} C the frozen constants context
|
|
61
54
|
* @param {Readonly<Record<string, any>>} F the fitted coefficients
|
|
62
|
-
* @param {
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* @param {{ giaEllipticityOfDate?: boolean }} [options]
|
|
70
|
-
* `giaEllipticityOfDate: false` builds the one-source history WITHOUT the J₂(t)/J₂₀ factor of date
|
|
71
|
-
* (the ice-driven GIA channel, which rides the climate formula's own post-MPT layer): the orbital
|
|
72
|
-
* FORCING alone. The T1 exporter derives the climate lines' obliquity rate on it, so the lines
|
|
73
|
-
* cannot depend on their own fit (v23.0; measured 3e-5 of the rate, 2–3 yr of period). Default true =
|
|
74
|
-
* the shipped physics (v15.0), bit-identical to before this parameter existed.
|
|
75
|
-
* @returns the assembled surfaces (epoch, earth, lengths, cardinal, moon) — type inferred so ReturnType stays precise
|
|
55
|
+
* @param {import('./model/context.js').Laws} [laws] research overrides for Earth's orbit laws
|
|
56
|
+
* (model/context.js); default {} = the shipped laws, bit-identical to before this parameter existed
|
|
57
|
+
* @param {any} [secularSeriesArtifact] the governed N-body secular series (the API/Node path; the
|
|
58
|
+
* npm package alone has no 8 MB series)
|
|
59
|
+
* @param {import('./model/context.js').Options} [options] `giaEllipticityOfDate: false` = the orbital
|
|
60
|
+
* forcing alone (model/context.js); default true = the shipped physics, bit-identical to before
|
|
61
|
+
* @returns the assembled surfaces (epoch, earth, lengths, cardinal, moon, …) — type inferred so ReturnType stays precise
|
|
76
62
|
*/
|
|
77
63
|
export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type {any} */ (null), options = {}) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// Plan 09: THE J2000 precession anchor p₀ in days (Julian years) — the IAU
|
|
107
|
-
// 2006 general precession; the Moon's star-referenced periods read it.
|
|
108
|
-
const axialPrecessionJ2000Days = (1296000 / C.earthOrbital.generalPrecessionJ2000_arcsecPerYr) * 365.25;
|
|
109
|
-
|
|
110
|
-
// Plan 07 R5/R6/R9: `earthtiltMean`, `earthInvPlaneInclinationAmplitude`
|
|
111
|
-
// and `eccentricityAmplitude` were read here only to invert the K and ψ
|
|
112
|
-
// constants from Earth's calibration and to build the H/3 inclination
|
|
113
|
-
// device. With both laws retired nothing in this module reads them — they
|
|
114
|
-
// remain on C.earth as the K device's J2000 pose inputs (the scene's wheel
|
|
115
|
-
// geometry at the chain anchor epoch) and for the registry's record keys.
|
|
116
|
-
// (Plan 09: the 16-harmonic solstice-obliquity comb — SOLSTICE_OBLIQUITY_
|
|
117
|
-
// MEAN_FITTED / _HARMONICS, the frozen era record — is deleted; the model's
|
|
118
|
-
// ONE obliquity of date is the one-source hybrid, `oneSourceM.epsAt`.)
|
|
119
|
-
|
|
120
|
-
const G_CONSTANT = C.physicalConstants.G_CONSTANT;
|
|
121
|
-
const MASS_RATIO_EARTH_MOON = C.physicalConstants.MASS_RATIO_EARTH_MOON;
|
|
122
|
-
const currentAUDistance = C.physicalConstants.currentAUDistance;
|
|
123
|
-
const moonDistanceKm = C.moonReference.moonDistance;
|
|
124
|
-
const moonSiderealMonthInput = C.moonReference.moonSiderealMonthInput;
|
|
125
|
-
|
|
126
|
-
// Plan 09: the Moon's sidereal month is the IAU input itself (the device's
|
|
127
|
-
// eighth-integer-per-8H count read it back 7.8 ms long; deleted).
|
|
128
|
-
const moonSiderealMonth = moonSiderealMonthInput;
|
|
129
|
-
|
|
130
|
-
// The mass chain (Moon Kepler → GM_EM → the Earth/Moon split → the Sun, §9
|
|
131
|
-
// order) — ONE home since plan 13 B3: earth/mass-chain.cjs (the deep-time
|
|
132
|
-
// chain below computes the same scalars from the same context).
|
|
133
|
-
const mass = computeMassChainJ2000({
|
|
134
|
-
moonDistanceKm, moonSiderealMonthDays: moonSiderealMonth, meanSiderealYearDays,
|
|
135
|
-
meanLengthOfDaySeconds: meanLengthOfDay, massRatioEarthMoon: MASS_RATIO_EARTH_MOON,
|
|
136
|
-
currentAUDistanceKm: currentAUDistance, gravitationalConstantKm3KgS2: G_CONSTANT,
|
|
137
|
-
});
|
|
138
|
-
const moonOrbitalShift = mass.moonOrbitalShiftKm;
|
|
139
|
-
const moonDistanceCorrected = mass.moonDistanceCorrectedKm;
|
|
140
|
-
const GM_EARTH_MOON_SYSTEM = mass.gmEarthMoonSystemKm3S2;
|
|
141
|
-
const GM_EARTH_ALONE = mass.gmEarthAloneKm3S2;
|
|
142
|
-
const GM_MOON_ALONE = mass.gmMoonAloneKm3S2;
|
|
143
|
-
const GM_SUN_PLUS_EARTH = mass.gmSunPlusEarthKm3S2;
|
|
144
|
-
const GM_SUN = mass.gmSunKm3S2;
|
|
145
|
-
const M_SUN = mass.sunMassKg;
|
|
146
|
-
|
|
147
|
-
// ── THE DEEP-TIME CHAIN — ONE assembly (plan 13 B2) ──────────────────────
|
|
148
|
-
// The GIA α channel (the lagged response to the L1 ice history, with the R2
|
|
149
|
-
// lattice pin and the exact-argument memo), the Layer-0 bundle, the cited
|
|
150
|
-
// Earth–Moon distance history (plan 12 option A), the ΔT cycle stack (all
|
|
151
|
-
// channels ON here), |s₃|, the LOD/ΔT core and the lunar month chain are
|
|
152
|
-
// assembled once in deltat/deep-time-chain.js from this context's constants
|
|
153
|
-
// and fitted coefficients (so a counterfactual context flows through them);
|
|
154
|
-
// the Node twin and the browser destructure the same module.
|
|
155
|
-
const chain = createDeepTimeChain({
|
|
156
|
-
constants: C, fitted: F, deepModes: DEEP_MODES_ARTIFACT, moonDistanceArtifact: MOON_DISTANCE_ARTIFACT,
|
|
157
|
-
ageAnchorYear: startmodelYear,
|
|
158
|
-
});
|
|
159
|
-
const { alphaGia, earthMoiFactorAtAge, EPOCH_PARAMS, recession, dtCycles, dtCycleLodCorrectionSum, s3ArcsecPerYr, deepLod, deepEcc, moonChain } = chain;
|
|
160
|
-
const CLIMATE_REGIME = F.CLIMATE_FORMULA_COEFFS.regimes['lr04-post-mpt'];
|
|
161
|
-
/** The climate formula's L1 (unlagged) — the orbital δ¹⁸O layer itself. @param {number} year @returns {number} */
|
|
162
|
-
const evalClimateL1 = (year) => evalClimateL1OrbitalPermil(year, {
|
|
163
|
-
l1Terms: CLIMATE_REGIME.L1,
|
|
164
|
-
yStdDenormalization: CLIMATE_REGIME.denormalization.y_std,
|
|
165
|
-
});
|
|
166
|
-
const moonDistanceMetresAtAge = recession.distanceMetresAtAge;
|
|
167
|
-
/** The published surfaces' km reading — NaN beyond the cited history's span (the API's
|
|
168
|
-
* validity span lies inside it; the deep charts stop where the input stops).
|
|
169
|
-
* @param {number} year @returns {number} */
|
|
170
|
-
const moonDistanceKmAtYearOrNaN = (year) => { const m = moonDistanceMetresAtAge(yearToTMa(year)); return m === null ? NaN : m / 1000; };
|
|
171
|
-
|
|
172
|
-
/** THE REALIZED POLE RATE OVER A WINDOW, ″/yr — the mean over [yearFrom, yearTo] of the rate the spin
|
|
173
|
-
* integration actually turns the pole at: the inertial secular rate of date × the solar-torque factor at
|
|
174
|
-
* e(t) × J₂(t)/J₂₀ × cos ε(t)/cos ε₀ (ds/dt = α (ŝ·n̂)(ŝ×n̂): the azimuthal rate about n̂ is α cos ε).
|
|
175
|
-
* The secular rate here is the CONSTANT's scaling (lunisolarTorqueRate…), not the published rate of
|
|
176
|
-
* date: the hybrid's own ε(t) carries the ONE cosine, so the cited mean obliquity's factor (plan 12 §8)
|
|
177
|
-
* does not enter twice — inside the ζ-series span the hybrid IS the model's obliquity of date.
|
|
178
|
-
* Measured (2026-10): the dominant obliquity line of the model's own ε(t) over the last 5 Myr sits at
|
|
179
|
-
* this mean minus |s₃| (40,938 fitted vs 40,936 predicted), NOT at the J2000 beat (41,098) — the pole
|
|
180
|
-
* turned faster in the past (spin +0.06 ″/yr over 5 Myr, lower mean obliquity +0.05, higher mean
|
|
181
|
-
* eccentricity +0.015); La2004's own series reads the same (40,917). The climate records' preferred
|
|
182
|
-
* "+0.12…+0.20 ″/yr on the obliquity lines" is this window mean (50.515 over the LR04 record).
|
|
183
|
-
* Calls the one-source history and the deep-time LOD declared below (evaluated at call time).
|
|
184
|
-
* `ellipticity: false` leaves the J₂(t)/J₂₀ factor out: that factor is the ice-driven GIA channel, which
|
|
185
|
-
* rides the climate formula's own post-MPT layer — the one piece that would make the climate LINES
|
|
186
|
-
* depend on their own fit (measured: its LR04-window mean moved 1 − 3e-5 → 1 across one refit,
|
|
187
|
-
* 1.4e-3 ″/yr, 1 yr of period). The line derivation (the T1 exporter) excludes it; the published
|
|
188
|
-
* realized period and the hybrid verdict's gate keep the full rate.
|
|
189
|
-
* @param {number} yearFrom @param {number} yearTo @param {number} [stepYears=500]
|
|
190
|
-
* @param {{ellipticity?: boolean}} [opts] @returns {number} */
|
|
191
|
-
const spinAxisInertialRateMeanArcsecPerYr = (yearFrom, yearTo, stepYears = 500, opts = {}) => {
|
|
192
|
-
const useEllipticity = opts.ellipticity !== false;
|
|
193
|
-
const lo = Math.min(yearFrom, yearTo), hi = Math.max(yearFrom, yearTo);
|
|
194
|
-
const cosEps0 = Math.cos(oneSourceM.epsAt(2000) * Math.PI / 180);
|
|
195
|
-
const kInertial = certifiedAxialPrecessionJ2000Years() / oneSourceM.axialPrecessionYearsLunisolarJ2000;
|
|
196
|
-
let sum = 0, n = 0;
|
|
197
|
-
for (let y = lo; y <= hi; y += stepYears) {
|
|
198
|
-
const r = deepLod.lunisolarTorqueRateArcsecPerYrAtAge(yearToTMa(y));
|
|
199
|
-
const psiDot = (r === null ? 1296000 / certifiedAxialPrecessionJ2000Years() : r) * kInertial;
|
|
200
|
-
const f = oneSourceM.precessionOfDateFactorsAt(y);
|
|
201
|
-
sum += psiDot * f.solarTorque * (useEllipticity ? f.ellipticity : 1) * Math.cos(oneSourceM.epsAt(y) * Math.PI / 180) / cosEps0;
|
|
202
|
-
n++;
|
|
203
|
-
}
|
|
204
|
-
return sum / n;
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
// (Plan 09 step 7a: the integrated ∫dt/H_era phase table and its counter
|
|
208
|
-
// `cyclesBetween` — the frozen era clock's own convention H_era =
|
|
209
|
-
// H₀·LOD/LOD₀, plan 06 D8's second named counter, which every FROZEN comb
|
|
210
|
-
// read — are DELETED with the last comb; `epoch.cyclesBetween` left the
|
|
211
|
-
// surface with them, no reader remained. Step 5b: `phaseRadians` left with
|
|
212
|
-
// the RA day offset comb.)
|
|
213
|
-
|
|
214
|
-
/** @param {number} year @returns {number} */
|
|
215
|
-
const yearToTMa = (year) => (2000 - year) / 1e6;
|
|
216
|
-
|
|
217
|
-
// ── Earth scalars (integrated-phase display semantics) ────────────────────
|
|
218
|
-
/** @param {number} year @returns {number} */
|
|
219
|
-
// Plan 06 layer B — the eclipse Sun onto the series. The PUBLISHED Earth
|
|
220
|
-
// ϖ of date is the one-source series (the secular orbit; its J2000 element
|
|
221
|
-
// ≡ La2004's — the same field the D4c apsidal wheel renders). The SUN's
|
|
222
|
-
// equation of centre needs the MEAN elements of the era: the series plus the
|
|
223
|
-
// derived mean offset of the osculating channel (F.EARTH_OSCULATING_MEAN_
|
|
224
|
-
// OFFSET, tools/verify/earth-osculating-offset.js — the 1890–2110 mean of
|
|
225
|
-
// osculating − secular from the Horizons-seeded nine-body run). Measured:
|
|
226
|
-
// the fast osculating wobble is carried by the completion's direct terms and
|
|
227
|
-
// double-counts if added; the window mean is what the Sun residual holds
|
|
228
|
-
// (all-phase JPL sd 3.23″ → 1.59″; the former K law's Standish anchor
|
|
229
|
-
// 1.58″). The former K perihelion Fourier law (H divisors) is retired here.
|
|
230
|
-
const earthPerihelionDeg = (year) => oneSourceM.periOfDateDegAt(year);
|
|
231
|
-
const SUN_OFF = F.EARTH_OSCULATING_MEAN_OFFSET;
|
|
232
|
-
/** The eclipse Sun's ϖ of date (mean elements). @param {number} year @returns {number} */
|
|
233
|
-
const sunPerihelionDegAt = laws.perihelionLongitudeDegAt ?? ((year) => oneSourceM.periOfDateDegAt(year) + SUN_OFF.dPomArcsec / 3600);
|
|
234
|
-
// Plan 09: the obliquity of date is the one-source hybrid everywhere — the
|
|
235
|
-
// eclipse tier (besselian deps) read the retired 16-harmonic comb here.
|
|
236
|
-
/** @param {number} year @returns {number} */
|
|
237
|
-
const obliquityDeg = (year) => oneSourceM.epsAt(year);
|
|
238
|
-
// ECCENTRICITY UNIFICATION — ONE law for the whole model (plan
|
|
239
|
-
// IP-eccentricity-unification, decision D1 = form (e)). Earth's orbital
|
|
240
|
-
// eccentricity is the magnitude of a vector sum, e = |v₁ + v₂|: v₁ of
|
|
241
|
-
// length base' along the ICRF perihelion (rotating once per H/3), v₂ of
|
|
242
|
-
// length base'/2 FIXED in space along the inclination-cycle anchor
|
|
243
|
-
// direction. Their relative angle θ rides the System-Reset lattice phase
|
|
244
|
-
// (θ(t) = 3(t − balancedYear)/H·360° − 180°, θ(J2000) = 81.178°) — the
|
|
245
|
-
// SAME anchor the inclination law and the Moon channel ride (their
|
|
246
|
-
// extremes coincide: max −23,200, min −79,100). Then
|
|
247
|
-
// e(t) = base' · (1 + cos θ(t) / 2), base' = e(J2000) / (1 + cos θ(J2000) / 2)
|
|
248
|
-
// base' is DERIVED from the observed J2000 eccentricity and the anchor
|
|
249
|
-
// (0.015520; the Law-5 balance moves 99.8636 → 99.8645%, Earth's weight
|
|
250
|
-
// there being 0.05%). No new constants. Why H/3 and not the former H/16
|
|
251
|
-
// beat law: eccentricity is frame-invariant and may carry only fixed-frame
|
|
252
|
-
// lattice periods; H/16 is the OF-DATE perihelion period (13 + 3 = 16 —
|
|
253
|
-
// the H/3 rotation seen from the H/13 equinox) and belongs to ϖ_of-date;
|
|
254
|
-
// measured, the H/16 law's present ė (−0.84e-5/cy) is 5× below the
|
|
255
|
-
// observed −4.20e-5 while this law reads −4.31e-5 (Phase-0 record: the
|
|
256
|
-
// H/3-law candidate instrument, deleted at plan 09 step 7e — docs/109 §22;
|
|
257
|
-
// JPL Sun 1.49″, registry 0.80″, syzygy 3.72″). Consumers (engine-switch decision (ii) restatement,
|
|
258
|
-
// plan 02 §8): the eclipse Sun (equation of centre), the besselian Sun
|
|
259
|
-
// distance and the cardinal-point braid — the CLOCK-side machinery. The
|
|
260
|
-
// LUNAR chain (E-factor, perigee/node modulation/T², argument Δe² and
|
|
261
|
-
// of-date rates) rides the ONE deep e (deep-ecc-channel.cjs — the
|
|
262
|
-
// engine's own ±10-Myr z-vector); this H/3 line is its epoch-local
|
|
263
|
-
// tangent (E18), agreeing within 4.2e-5 across the historical era.
|
|
264
|
-
// ONE implementation for all three runtimes: moon/ecc-channel.cjs (the
|
|
265
|
-
// Node engine's deep-time.js and the browser's script.js instantiate the
|
|
266
|
-
// same channel with the same inputs). Its phase counter runs from J2000
|
|
267
|
-
// (θ₀ = ϖ_ICRF(J2000) − 21.77° = 81.178°, the System-Reset anchor in
|
|
268
|
-
// anchor form — doc 66 §1); base' is derived inside from the observed
|
|
269
|
-
// J2000 eccentricity.
|
|
270
|
-
// (The H/3 eccentricity-law channel — createMoonEccChannel — left this
|
|
271
|
-
// package with plan 06 layer B: the Sun's e is the one-source series plus
|
|
272
|
-
// the derived mean offset above; the browser's scene Sun still reads the
|
|
273
|
-
// law through its own _moonEcc until the cardinal points move.)
|
|
274
|
-
// Engine-switch decision (ii) (plan 02 §8): the ONE deep e — the engine's
|
|
275
|
-
// own ±10-Myr mode table, anchored form — feeds the ENTIRE lunar chain
|
|
276
|
-
// (modulation, cycle counts, arguments eccAt/channelIntegral, E-factor).
|
|
277
|
-
// The Sun/clock machinery (eclipse Sun EoC, besselian Sun distance,
|
|
278
|
-
// cardinal braid) reads the one-source series below (plan 06 layer B —
|
|
279
|
-
// the two agree within 4.2e-5 in-era). The laws hook deliberately does
|
|
280
|
-
// NOT reach this channel.
|
|
281
|
-
// (`deepEcc` is the deep-time chain's, destructured above.)
|
|
282
|
-
/** @param {number} year @returns {number} */
|
|
283
|
-
// Plan 06 layer B: the PUBLISHED Earth eccentricity is the one-source series
|
|
284
|
-
// (|z|, the secular orbit); the SUN's e adds the derived mean offset (see
|
|
285
|
-
// sunPerihelionDegAt). The former H/3 eccentricity law is retired here.
|
|
286
|
-
const eccentricityAt = (year) => oneSourceM.eAt(year);
|
|
287
|
-
/** The eclipse Sun's e (mean elements). @param {number} year @returns {number} */
|
|
288
|
-
const sunEccentricityAt = laws.eccentricityAt ?? ((year) => oneSourceM.eAt(year) + SUN_OFF.dE);
|
|
289
|
-
/** de/dyear of the Sun's e — the cardinal braid's equation-of-centre
|
|
290
|
-
* derivative rides it (±0.5-yr central difference; the constant offset
|
|
291
|
-
* cancels). @param {number} year @returns {number} */
|
|
292
|
-
// (Plan 07 R5/R9: Earth's H/3 inclination cosine and −H/5 linear node — the
|
|
293
|
-
// K device — stood here; `inclinationDeg`/`ascendingNodeDeg` are now the
|
|
294
|
-
// one-source construction defined with the planets' chain evaluators below.)
|
|
295
|
-
|
|
296
|
-
// ── Year/day lengths ──────────────────────────────────────────────────────
|
|
297
|
-
// Plan 09: the three year-length combs (TROPICAL/SIDEREAL/ANOMALISTIC_
|
|
298
|
-
// YEAR_HARMONICS on the frozen era clock's bases) and their evaluators
|
|
299
|
-
// are deleted. The year lengths of date in DAYS are the published SI year
|
|
300
|
-
// lengths over the kinematic day of date; the kinematic day of date is the
|
|
301
|
-
// Layer-0 tidal mean LOD, exactly ω₀ (the SI day) at J2000 — the former
|
|
302
|
-
// "sidereal seconds over comb days" carried the λ̇ ripple of the sidereal
|
|
303
|
-
// year as a day-length ripple (≤ 0.1 ms in the era, 0.66 ms at ±26 kyr).
|
|
304
|
-
/** THE J2000 precession anchor p₀ (plan 09): the IAU 2006 general
|
|
305
|
-
* precession in longitude at J2000 (astro-reference.json
|
|
306
|
-
* earthOrbital.generalPrecessionJ2000_arcsecPerYr = 50.28796195 ″/yr),
|
|
307
|
-
* stated as the period 1,296,000/p_A = 25,771.575 Julian years. ONE home:
|
|
308
|
-
* the composed clock's p₀, the hybrid's self-anchor and the lunisolar
|
|
309
|
-
* surface all read it. Before plan 09 it was the retired year combs' beat
|
|
310
|
-
* at 2000 (plan 06 S5: 25,771.395 yr, 8 ppm faster); the H/13 reading
|
|
311
|
-
* (25,793.6) was the fit anchor's, not a period. The identifier keeps its
|
|
312
|
-
* name. @returns {number} */
|
|
313
|
-
function certifiedAxialPrecessionJ2000Years() {
|
|
314
|
-
return 1296000 / C.earthOrbital.generalPrecessionJ2000_arcsecPerYr;
|
|
315
|
-
}
|
|
316
|
-
/** Kinematic day of date (Layer 0 tidal mean LOD; ω₀ at J2000). Past the
|
|
317
|
-
* tidal-lock asymptote the chain is null — the J2000 day stands in, as
|
|
318
|
-
* the retired comb base did. @param {number} year @returns {number} */
|
|
319
|
-
const dayLengthSeconds = (year) => deepLod.lodSecondsAtAge(yearToTMa(year)) ?? meanLengthOfDay;
|
|
320
|
-
/** Sidereal year of date in days of the epoch — the published SI sidereal
|
|
321
|
-
* year (the λ̇ channel inside the one-family window, the mass-loss law
|
|
322
|
-
* beyond) over the kinematic day of date. @param {number} year @returns {number} */
|
|
323
|
-
const siderealYearDays = (year) => publishedSiderealYearSecondsAtYear(year) / dayLengthSeconds(year);
|
|
324
|
-
/** Anomalistic year of date in days of the epoch — the published SI
|
|
325
|
-
* anomalistic year (one-family inside its window; NaN beyond, where the
|
|
326
|
-
* movement's apsidal line is not resolved). @param {number} year @returns {number} */
|
|
327
|
-
const anomalisticYearDays = (year) => {
|
|
328
|
-
const s = Math.abs(year - 2000) <= ONE_FAMILY_WINDOW_YEARS ? yearLengthsM.anomalisticYearSecondsAtYear(year) : NaN;
|
|
329
|
-
return s / dayLengthSeconds(year);
|
|
330
|
-
};
|
|
331
|
-
// (Plan 09 step 5b: raDayOffsetMs — the fitted RA_DAY_OFFSET_MS comb, a −14.194 ms
|
|
332
|
-
// mean + lines on H/16 and H/8 — and measuredSolarDaySeconds = dayLength + that
|
|
333
|
-
// offset are deleted. The quantity was the equation of time's window term of the
|
|
334
|
-
// Framework-Verification instrument: 365 solar noons counted from the June
|
|
335
|
-
// solstice end 0.2422 d short of the tropical year, so the mean noon-to-noon
|
|
336
|
-
// interval differs from the mean solar day by −(0.2422/365)·dEoT/dt at the
|
|
337
|
-
// solstice — the e·cos(90° − ϖ) term on the perihelion-of-date cycle (the comb's
|
|
338
|
-
// "H/16" line, 5.6 ms vs 5.2 first-order) and the tan²(ε/2) term on the obliquity
|
|
339
|
-
// cycle (the "H/8" line, 1.7 vs 1.4). A property of the window, not of the sky:
|
|
340
|
-
// the physical day of date is dayLengthSeconds; the equation of time is the
|
|
341
|
-
// certified Sun's. docs/11 § "The retired RA day offset".)
|
|
342
|
-
|
|
343
|
-
// ── Cardinal points (the fitted model retired, R1)──────────────────────────────────────────────────
|
|
344
|
-
// Plan 06 R1: the fitted cardinal-point model (CARDINAL_POINT_* — the §10
|
|
345
|
-
// derived form on the frozen era clock, fitted to the retired K scene's
|
|
346
|
-
// events; measured 60–140 min from Meeus ch. 27 at 0..−1000 and 6–25 min
|
|
347
|
-
// in 1500–2900) left this package. The instants are the CROSSINGS of the
|
|
348
|
-
// one Sun the scene renders and the eclipse chain certifies — see
|
|
349
|
-
// `cardinalCrossingJdUT` below the finders.
|
|
350
|
-
// ── One-source cardinal structure (D4b) ───────────────────────────────────
|
|
351
|
-
// The EoC layer (year lengths, crossing offsets, the e(t)-proportional
|
|
352
|
-
// spread) on the one-source movement's own e(t)/ϖ(t) — the MODE tier (the
|
|
353
|
-
// package's embedded deep-modes artifact; the banked-series tier is the
|
|
354
|
-
// repo-data-bound instrument). Absolute dates deliberately absent — see
|
|
355
|
-
// cardinal/one-source-structure.cjs. The mean year is SI SECONDS: the
|
|
356
|
-
// sidereal year of date reduced by the SECULAR equinox precession
|
|
357
|
-
// (axial0·H(t)/H₀ with H(t) the UNIT = 13·T_p,composed — plan 06 D6/Phase
|
|
358
|
-
// 3, the movement's leg-1 convention, NOT the H/13 kinematic identity at
|
|
359
|
-
// J2000; the two are a recorded 0.09% relation tension there).
|
|
360
|
-
// THE ONE of-date year-length family (owner: "move to 1 implementation")
|
|
361
|
-
// — createYearLengths owns tropical (equinox-rate mean, wobble included),
|
|
362
|
-
// sidereal (the D6 λ̇ channel), anomalistic (the cardinal structure on
|
|
363
|
-
// the SAME mean), all λ̇-corrected coherently, SI seconds, and the beats
|
|
364
|
-
// of that pair. The internal laws, the kinematic beat constructions
|
|
365
|
-
// (axialPrecessionYears*), the scene engine and the frozen era clock
|
|
366
|
-
// stay on their own families as before.
|
|
367
|
-
// S3 tier unification: when the caller injects the governed secular-
|
|
368
|
-
// series artifact (createModel opts.secularSeriesArtifact — the API/Node
|
|
369
|
-
// path; the npm package alone has no 8 MB series), the movement runs the
|
|
370
|
-
// SERIES tier exactly like the browser — killing the mode-vs-series
|
|
371
|
-
// value split (measured: 6 s on the anomalistic year at J2000).
|
|
372
|
-
// The ONE-SOURCE movement: the hybrid's ε(t) (plan 06 Phase 3 S3b — THE
|
|
373
|
-
// published obliquity) and the one-family year lengths, on the same
|
|
374
|
-
// per-tier sampler.
|
|
375
|
-
const oneSourceM = (() => {
|
|
376
|
-
const AEarth = /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements.earth;
|
|
377
|
-
// The ψ̇ anchor: the IAU 2006 general precession p_A (plan 09; 25,771.575
|
|
378
|
-
// yr — the ONE home certifiedAxialPrecessionJ2000Years, twins in
|
|
379
|
-
// tools-lib and the browser). History: plan 06 S5 anchored it on the
|
|
380
|
-
// certified year combs' beat at 2000 (25,771.4); before that the device's
|
|
381
|
-
// mean pair (meanSiderealYearDays/meanSolarYearDays → 25,796) anchored
|
|
382
|
-
// this movement's realized precession 25 yr off — the hidden split behind
|
|
383
|
-
// the API's 365.242204 tropical mean (found in the owner's
|
|
384
|
-
// one-implementation drive).
|
|
385
|
-
const axial0 = certifiedAxialPrecessionJ2000Years(); // S5: the ONE home
|
|
386
|
-
// D6 → Phase 3 (plan 06): the deep-time ψ̇(t) the hybrid precesses on is
|
|
387
|
-
// the COMPOSED lunisolar rate — its period of date T_p(t) read directly
|
|
388
|
-
// (plan 09 step 5c; it was period₀·H(t)/H₀ on the unit, the same number
|
|
389
|
-
// to 2e-16 since the unit scales with T_p). Not the frozen era clock's
|
|
390
|
-
// H_era (which misses the lunar 1/a³ growth: 70.9 vs Lantink 2022's
|
|
391
|
-
// 108.6 ± 8.5 ″/yr at 2.46 Ga; the composed rate reads 104.5).
|
|
392
|
-
const seriesArt = /** @type {any} */ (secularSeriesArtifact);
|
|
393
|
-
const sb = seriesArt && seriesArt.bodies && seriesArt.bodies.earth;
|
|
394
|
-
// Plan 12 §8.5 (owner): the hybrid's own domain is the banked ζ series' span (years; null
|
|
395
|
-
// without a series). Beyond it the ζ-mode tail carries the Quaternary mean with no tidal
|
|
396
|
-
// evolution — the API refuses the obliquity there and serves the cited mean beside it.
|
|
397
|
-
const obliquityHybridDomainYears = sb
|
|
398
|
-
? /** @type {[number, number]} */ ([2000 + seriesArt.t0Yr, 2000 + seriesArt.t0Yr + (sb.zetaQ.length - 1) * sb.stepYr])
|
|
399
|
-
: null;
|
|
400
|
-
const hist = createDeepOrbitalHistory({
|
|
401
|
-
zModes: DEEP_MODES_ARTIFACT.earthZ,
|
|
402
|
-
zetaModes: DEEP_MODES_ARTIFACT.earthZeta,
|
|
403
|
-
...(sb ? {
|
|
404
|
-
zetaSeries: { t0Yr: seriesArt.t0Yr, stepYr: sb.stepYr, q: sb.zetaQ, p: sb.zetaP },
|
|
405
|
-
zSeries: { t0Yr: seriesArt.t0Yr, stepYr: sb.stepYr, q: sb.zQ, p: sb.zP },
|
|
406
|
-
} : {}),
|
|
407
|
-
anchorE: AEarth.e,
|
|
408
|
-
anchorPeriEclipticDeg: AEarth.lonPeriEclipticDeg,
|
|
409
|
-
anchorInclEclipticDeg: AEarth.inclEclipticDeg,
|
|
410
|
-
anchorAscNodeEclipticDeg: AEarth.ascNodeEclipticDeg,
|
|
411
|
-
axialPrecessionYearsJ2000: axial0,
|
|
412
|
-
// Phase 3 S3b: the hybrid's initial condition is the OBSERVED J2000
|
|
413
|
-
// mean obliquity — the IAU 2006 input constant (84381.406″), the same
|
|
414
|
-
// anchor the browser's _deepHistSeries and the Node one-source movement
|
|
415
|
-
// use. It was the K comb's own J2000 value, 0.233″ above IAU: a
|
|
416
|
-
// rendering-device residual imported as the initial condition of the
|
|
417
|
-
// physics (found when the package began publishing the hybrid).
|
|
418
|
-
obliquityJ2000Deg: C.earthOrbital.obliquityJ2000_deg,
|
|
419
|
-
// The CONSTANT's scaling (the torque period), not the published rate of date: the
|
|
420
|
-
// integration's own ŝ·n̂ carries the obliquity's cosine, so the cited mean obliquity's
|
|
421
|
-
// factor (plan 12 §8 option (a)) must not enter twice. Bit-identical to the pre-§8 form.
|
|
422
|
-
axialPrecessionYearsAtYearFn: (yr) => deepLod.lunisolarTorquePeriodYearsAtAge((startmodelYear - yr) / 1e6) ?? axial0,
|
|
423
|
-
// THE PRECESSION OF DATE (plan 06 §9 item 10): on top of the secular
|
|
424
|
-
// law above, the solar torque at the eccentricity of date and the
|
|
425
|
-
// oblateness of date from the GIA channel — both exactly 1 at J2000,
|
|
426
|
-
// so the unit H(t) and the J2000 anchor are untouched. The channel is
|
|
427
|
-
// read PURE (alphaGia, not the lattice-pin-aware earthMoiFactorAtAge):
|
|
428
|
-
// the samplers are cached, their values must be pure in year.
|
|
429
|
-
solarTorqueShareJ2000: EPOCH_PARAMS.precessionSolarShareJ2000,
|
|
430
|
-
// options.giaEllipticityOfDate === false: the orbital forcing alone (the T1 line derivation).
|
|
431
|
-
dynamicalEllipticityRatioAtYearFn: options.giaEllipticityOfDate === false ? undefined : alphaGia.j2RatioAt,
|
|
432
|
-
});
|
|
433
|
-
// PER-TIER ROUTING (the anomalistic-contamination fix): one sampler PER
|
|
434
|
-
// grid tier, built on first entry and KEPT — a query always reads the
|
|
435
|
-
// tier its own span selects. The former single grown sampler replaced
|
|
436
|
-
// the 100-yr grid with the 1000/5000-yr one after any deep-time probe,
|
|
437
|
-
// and the year-length rates (±0.5-yr central differences through the
|
|
438
|
-
// grid) then returned grid-segment averages instead of local rates
|
|
439
|
-
// (anomalistic of date +2.63 s / +19 s, visit-order dependent).
|
|
440
|
-
const samplers = /** @type {Map<number, any>} */ (new Map());
|
|
441
|
-
const gridStep = (/** @type {number} */ n) => (n <= 50000 ? 100 : n <= 2000000 ? 1000 : 5000);
|
|
442
|
-
const tierSpan = (/** @type {number} */ n) => (n <= 50000 ? 50000 : 2000000);
|
|
443
|
-
const sampleAt = (/** @type {number} */ year) => {
|
|
444
|
-
const t = year - 2000, need = Math.max(20000, Math.abs(t) * 1.25);
|
|
445
|
-
if (need > 2000000) {
|
|
446
|
-
// The deep tier (5000-yr grid): walked in the queried DIRECTION only,
|
|
447
|
-
// to two nodes past the query, and EXTENDED by the factory's shared
|
|
448
|
-
// walk when a deeper epoch arrives (plan 13 A1). It was built to
|
|
449
|
-
// ±1.25·|t| in both directions and rebuilt from J2000 on every deeper
|
|
450
|
-
// probe — bit-identical values, 4× the RK4 steps of one walk.
|
|
451
|
-
const span = Math.ceil((Math.abs(t) + 2 * 5000) / 5000) * 5000;
|
|
452
|
-
return hist.build(t < 0 ? -span : span, 0, 5000).at(t);
|
|
453
|
-
}
|
|
454
|
-
const span = tierSpan(need);
|
|
455
|
-
if (!samplers.has(span)) samplers.set(span, hist.build(span, -span, gridStep(span)));
|
|
456
|
-
return samplers.get(span).at(t);
|
|
457
|
-
};
|
|
458
|
-
// The anomalistic year rides THIS movement's own apsidal line (the
|
|
459
|
-
// scene's perihelion) — the factory owns the construction; the planet
|
|
460
|
-
// chain's secular tangent is no longer a member (year-lengths.cjs).
|
|
461
|
-
const yearLengths = createYearLengths({
|
|
462
|
-
sampleAt,
|
|
463
|
-
massLossSiderealSecondsAtYearFn: (year) => deepLod.siderealYearSecondsAtAge(yearToTMa(year)),
|
|
464
|
-
});
|
|
465
|
-
return {
|
|
466
|
-
yearLengths,
|
|
467
|
-
/** The one-source sample at a decimal year (the engine year) — ε, e, ϖ of date, the Earth-orbit normal (the fields the frame of date and the invariable-plane elements read). @param {number} year */
|
|
468
|
-
sampleAt,
|
|
469
|
-
/** EXPERIMENT accessors: the series' e and equinox-referenced ϖ of date. @param {number} year @returns {number} */
|
|
470
|
-
eAt: (year) => sampleAt(year).e,
|
|
471
|
-
/** @param {number} year @returns {number} */
|
|
472
|
-
periOfDateDegAt: (year) => sampleAt(year).periOfDateDeg,
|
|
473
|
-
/** The hybrid's obliquity at a decimal year, degrees — the banked series inside its span, the α(t)-coupled ζ-tail integration beyond (the deep sampler grows ~0.1 s/Myr). @param {number} year @returns {number} */
|
|
474
|
-
epsAt: (year) => sampleAt(year).epsDeg,
|
|
475
|
-
/** The hybrid's own domain, [yearFrom, yearTo] — the banked ζ series' span (plan 12 §8.5); null without a series. */
|
|
476
|
-
obliquityHybridDomainYears,
|
|
477
|
-
/** The precession of date's two factors at a decimal year (the factory's own — ONE home). @param {number} year @returns {{solarTorque: number, ellipticity: number}} */
|
|
478
|
-
precessionOfDateFactorsAt: (year) => hist.precessionOfDateFactorsAt(year - 2000),
|
|
479
|
-
/** The spin axis's INERTIAL precession period at J2000, years — the self-anchored
|
|
480
|
-
* lunisolar rate the hybrid integrates ŝ on (deep-orbital-history D4e): the general
|
|
481
|
-
* precession anchor plus the planetary mean the ecliptic's own motion carries. */
|
|
482
|
-
axialPrecessionYearsLunisolarJ2000: hist.axialPrecessionYearsLunisolarJ2000,
|
|
483
|
-
};
|
|
484
|
-
})();
|
|
485
|
-
const yearLengthsM = oneSourceM.yearLengths;
|
|
486
|
-
/** THE one-family tropical year of date in SI seconds: route B inside the
|
|
487
|
-
* one-family window, the tidal-chain year beyond (plan 06 R1 — the Sun's
|
|
488
|
-
* mean longitude, the cardinal instants and the published year lengths
|
|
489
|
-
* all ride this one function). @param {number} year @returns {number} */
|
|
490
|
-
const oneFamilyTropicalYearSeconds = (year) => (Math.abs(year - 2000) <= ONE_FAMILY_WINDOW_YEARS
|
|
491
|
-
? yearLengthsM.tropicalYearSecondsAtYear(year)
|
|
492
|
-
: (deepLod.tropicalYearSecondsAtAge(yearToTMa(year)) ?? meanSolarYearDays * 86400));
|
|
493
|
-
|
|
494
|
-
/** Tropical year of date in DAYS OF THE EPOCH (the kinematic day below) —
|
|
495
|
-
* the one-family SI year over the epoch's day length, so solarYearSeconds
|
|
496
|
-
* ≡ the one-family year. Plan 06 R1: formerly the fitted cardinal model's
|
|
497
|
-
* 4-mean. @param {number} year @returns {number} */
|
|
498
|
-
const tropicalYearDays = (year) => oneFamilyTropicalYearSeconds(year) / dayLengthSeconds(year);
|
|
499
|
-
|
|
500
|
-
/** Layer-4 solar day of date in SI seconds — LOD_real, the shipped
|
|
501
|
-
* observable (the tweakpane Solar Day row, the registry's lodRealPhysical,
|
|
502
|
-
* the Framework Verification panel's day): the kinematic day of date + the
|
|
503
|
-
* ecliptic missing-motion term on the nodal period + the calibrated ΔT
|
|
504
|
-
* cycle stack incl. the core-mantle swing. Twin of tools/lib
|
|
505
|
-
* computeLodRealSecondsAtEpoch and the browser's _vfpSolarDaySecondsOfDate
|
|
506
|
-
* (86,400.001780 s at 2000). @param {number} year @returns {number} */
|
|
507
|
-
const lodRealSeconds = (year) =>
|
|
508
|
-
dayLengthSeconds(year)
|
|
509
|
-
+ (deepLod.eclipticLodCorrectionSecondsAtAge(yearToTMa(year)) ?? 0)
|
|
510
|
-
+ dtCycleLodCorrectionSum(year);
|
|
511
|
-
/** Mean sidereal day of date in SI seconds — on LOD_real (plan 08 storyline
|
|
512
|
-
* sweep, 2026-10-09: the published day bases are the SI day of exactly
|
|
513
|
-
* 86,400 s, the IAU constants, and LOD_real; this rode the KINEMATIC day
|
|
514
|
-
* before, 1.7 ms below the simulator's readout at J2000). One rotation
|
|
515
|
-
* more against the equinox than there are solar days in a year.
|
|
516
|
-
* @param {number} year @returns {number} */
|
|
517
|
-
const siderealDaySeconds = (year) => {
|
|
518
|
-
const Y = tropicalYearDays(year);
|
|
519
|
-
return (lodRealSeconds(year) * Y) / (Y + 1);
|
|
520
|
-
};
|
|
521
|
-
/** Mean stellar day of date in SI seconds — the sidereal day plus the
|
|
522
|
-
* equinox's daily regression projected onto the equator (on LOD_real, like
|
|
523
|
-
* the sidereal day). @param {number} year @returns {number} */
|
|
524
|
-
const stellarDaySeconds = (year) => {
|
|
525
|
-
const tMa = yearToTMa(year);
|
|
526
|
-
// S5 (plan 06): one equinox turn per T_p(t) — the composed lunisolar
|
|
527
|
-
// period (its certified J2000 anchor past the chain's domain), NOT the
|
|
528
|
-
// unit's counter H(t)/13 (0.086 % slow; 7 µs on the 8.37 ms offset).
|
|
529
|
-
const TpRaw = deepLod.lunisolarPrecessionPeriodYearsAtAge(tMa);
|
|
530
|
-
const Tp = TpRaw === null ? certifiedAxialPrecessionJ2000Years() : TpRaw;
|
|
531
|
-
const syD = tropicalYearDays(year);
|
|
532
|
-
const sidDay = siderealDaySeconds(year);
|
|
533
|
-
// Layer A (plan 06): the RA projection reads the published ε (the one-source
|
|
534
|
-
// hybrid), not the K comb — the browser's _sceneEpsTargetDeg twin; 1e-8 s.
|
|
535
|
-
const raProjection = Math.cos((oneSourceM.epsAt(year) * Math.PI) / 180);
|
|
536
|
-
return (sidDay / Tp / (syD + 1)) * raProjection + sidDay;
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
// ── Moon at epoch ─────────────────────────────────────────────────────────
|
|
540
|
-
/** Solar-Δa-corrected Kepler month. @param {number} year @returns {number} */
|
|
541
|
-
const moonSiderealMonthDaysAt = (year) => {
|
|
542
|
-
const tMa = yearToTMa(year);
|
|
543
|
-
const lod = deepLod.lodSecondsAtAge(tMa);
|
|
544
|
-
const aAppM = moonDistanceMetresAtAge(tMa);
|
|
545
|
-
if (lod === null || aAppM === null) return NaN;
|
|
546
|
-
const aAppKm = aAppM / 1000;
|
|
547
|
-
const sidYrDays = deepLod.siderealYearSecondsAtAge(tMa) / lod;
|
|
548
|
-
const deltaA = aAppKm * (1 / (MASS_RATIO_EARTH_MOON + 1)) * (moonSiderealMonthInput / sidYrDays);
|
|
549
|
-
const aCorrM = (aAppKm + deltaA) * 1000;
|
|
550
|
-
const monthSeconds = 2 * Math.PI * Math.sqrt(Math.pow(aCorrM, 3) / EPOCH_PARAMS.gmEarthMoonM3S2);
|
|
551
|
-
return monthSeconds / lod;
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
// ── ΔT (TT − UT1): raw Simpson + sequential stack adds ────────────────────
|
|
555
|
-
/** @param {number} tMa @returns {number} */
|
|
556
|
-
// Exact-argument memo (the alphaMemo pattern above): the cardinal Newton
|
|
557
|
-
// solve asks for ΔT at the SAME jd twice per step (jdTTFromUT in the
|
|
558
|
-
// apparent Sun and again under the planetary completion) — measured 8.8 →
|
|
559
|
-
// 5.6 ms per panel year (8 solves) at modern epochs, values bit-identical.
|
|
560
|
-
/** @type {Map<number, number>} */
|
|
561
|
-
const dtMemo = new Map();
|
|
562
|
-
/** @param {number} tMa @returns {number} */
|
|
563
|
-
const meanDeltaTSecondsAtAge = (tMa) => {
|
|
564
|
-
if (tMa === 0) return 0;
|
|
565
|
-
const hit = dtMemo.get(tMa);
|
|
566
|
-
if (hit !== undefined) return hit;
|
|
567
|
-
let result = deepLod.deltaTRawSecondsAtAge(tMa);
|
|
568
|
-
const yearY = 2000 - tMa * 1e6;
|
|
569
|
-
result += dtCycles.cycleDeltaTSecondsAt('bond', yearY);
|
|
570
|
-
result += dtCycles.cycleDeltaTSecondsAt('hallstatt', yearY);
|
|
571
|
-
result += dtCycles.cycleDeltaTSecondsAt('jose5', yearY);
|
|
572
|
-
result += dtCycles.cycleDeltaTSecondsAt('jose4', yearY);
|
|
573
|
-
result += dtCycles.swingDeltaTSecondsAt(yearY);
|
|
574
|
-
if (dtMemo.size >= 8192) dtMemo.clear();
|
|
575
|
-
dtMemo.set(tMa, result);
|
|
576
|
-
return result;
|
|
577
|
-
};
|
|
578
|
-
/** @param {number} year @returns {number} */
|
|
579
|
-
const deltaTSeconds = (year) => C.earthOrbital.deltaTStart + meanDeltaTSecondsAtAge(yearToTMa(year));
|
|
580
|
-
|
|
581
|
-
// ── Planets: Fibonacci-law derivation chain + orientation ─────────────────
|
|
582
|
-
const PLANET_KEYS = ['mercury', 'venus', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune'];
|
|
583
|
-
const massEarthAlone = GM_EARTH_ALONE / G_CONSTANT;
|
|
584
|
-
/** @type {Record<string, number>} */
|
|
585
|
-
const massFraction = {};
|
|
586
|
-
for (const k of PLANET_KEYS) massFraction[k] = 1 / C.physicalConstants.massRatioDE440[k];
|
|
587
|
-
massFraction.earth = massEarthAlone / M_SUN;
|
|
588
|
-
|
|
589
|
-
// (plan 07 R6: eccentricityAmplitudeK — the K constant inverted from
|
|
590
|
-
// Earth's calibration — and the t2000 phase offset it fed went with the
|
|
591
|
-
// eccentricity law; plan 07 R5: PSI — ψ = 3·A_earth·√(m_E/m_☉) — and the
|
|
592
|
-
// inclination law it fed went the same way. systemResetN is kept where
|
|
593
|
-
// other consumers read it.)
|
|
594
|
-
|
|
595
|
-
// Plan 07 R1/R8: the internal PLANET_RECORDS — the device record the
|
|
596
|
-
// fitters once read (the H·num/den perihelion period from
|
|
597
|
-
// perihelionEclipticFraction, fibonacciD, antiPhase, inclinationCycleAnchor,
|
|
598
|
-
// the −8H/N node period) — had no reader left after R6/R5 and is gone with
|
|
599
|
-
// its JSON inputs. What remains is the PUBLISHED record below.
|
|
600
|
-
/** @type {Record<string, Record<string, any>>} */
|
|
601
|
-
const PUBLISHED_PLANET_RECORDS = {}; // what model.planets.record() serves (R8)
|
|
602
|
-
for (const k of PLANET_KEYS) {
|
|
603
|
-
const ar = C.planetOrbitalElements[k];
|
|
604
|
-
// Plan 06 Phase 7 commit 2: the K device's integer axial and obliquity
|
|
605
|
-
// fractions are retired; the obliquity is the DERIVED J2000 obliquity of
|
|
606
|
-
// the spin channel (the IAU pole against the chain's J2000 plane, acute
|
|
607
|
-
// form) — from the governed artifacts, no fractions. (The g-mode beat the
|
|
608
|
-
// K law's period rode left with the internal record at plan 07 R1/R8.)
|
|
609
|
-
const obliquityDerived = computeObliquityJ2000Deg({
|
|
610
|
-
spin: C.planetSpinPhysical[k],
|
|
611
|
-
anchorInclEclipticDeg: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements[k].inclEclipticDeg,
|
|
612
|
-
anchorAscNodeEclipticDeg: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements[k].ascNodeEclipticDeg,
|
|
613
|
-
obliquityJ2000Deg: C.earthOrbital.obliquityJ2000_deg,
|
|
614
|
-
});
|
|
615
|
-
const obliquityMean = Math.min(obliquityDerived, 180 - obliquityDerived); // acute form of the derived J2000 obliquity
|
|
616
|
-
// R8 (plan 07): what `model.planets.record()` PUBLISHES is the structural
|
|
617
|
-
// record, not the device. The internal record that kept the ψ/K law
|
|
618
|
-
// outputs for the fitting pipeline went piecewise: the K half at R6, the ψ
|
|
619
|
-
// half at R5, the lattice inputs at R1/R8 (nothing read it by then).
|
|
620
|
-
// Nothing outside needs the device, and serving it made /v1/bodies
|
|
621
|
-
// contradict the model's own chain on the SAME quantities: Mercury's node
|
|
622
|
-
// cycle 298,060 yr against the chain's 232,001, Jupiter's perihelion period
|
|
623
|
-
// 68,783 against 304,456, Neptune's 670,634 against 2,136,796. The two
|
|
624
|
-
// views are separated here: internal keeps the device for the fitters,
|
|
625
|
-
// published carries the structural inputs and the chain.
|
|
626
|
-
// · kept as-is — the REFERENCE inputs (IAU J2000 ϖ, Souami & Souchay
|
|
627
|
-
// node and inclination, DE440 e, the period input, the axial tilt) and
|
|
628
|
-
// `obliquityMean`, which is engine-DERIVED (the spin channel against
|
|
629
|
-
// the chain's J2000 plane), not a device value.
|
|
630
|
-
// · repointed, the quantity surviving as a chain eigenmode — the two
|
|
631
|
-
// PERIODS, now 1,296,000/g and 1,296,000/s. Signs kept as before:
|
|
632
|
-
// apsidal prograde positive, nodal regression negative.
|
|
633
|
-
// · dropped, the quantity BEING the device — ascendingNodeCyclesIn8H,
|
|
634
|
-
// fibonacciD, antiPhase, inclinationCycleAnchor, wobblePeriod (lattice
|
|
635
|
-
// inputs and the device's beat), and the inclination/eccentricity
|
|
636
|
-
// mean+amplitude+phase triples, which presume a single oscillation the
|
|
637
|
-
// chain does not have. Their honest replacement is the value AT AN
|
|
638
|
-
// EPOCH, which `/v1/bodies` already serves in its `at[]` rows.
|
|
639
|
-
const chainModes = /** @type {any} */ (CHAIN_ARTIFACT);
|
|
640
|
-
const gArc = chainModes.g[k] && chainModes.g[k].arcsecPerYr;
|
|
641
|
-
const sArc = chainModes.s[k] && chainModes.s[k].arcsecPerYr;
|
|
642
|
-
PUBLISHED_PLANET_RECORDS[k] = Object.freeze({
|
|
643
|
-
name: PLANET_DISPLAY_NAMES[k], // presentation — planets/display-names, the deleted JSON's last leaf (plan 11 step 6)
|
|
644
|
-
solarYearInput: ar.solarYearInput,
|
|
645
|
-
longitudePerihelion: ar.longitudePerihelion,
|
|
646
|
-
ascendingNodeInvPlane: ar.ascendingNodeInvPlaneClosedForm, // the closed-form verified J2000 node — astro-reference since plan 11 step 2
|
|
647
|
-
invPlaneInclinationJ2000: ar.invPlaneInclinationJ2000,
|
|
648
|
-
orbitalEccentricityJ2000: ar.orbitalEccentricityJ2000,
|
|
649
|
-
axialTiltJ2000: ar.axialTiltJ2000,
|
|
650
|
-
obliquityMean,
|
|
651
|
-
perihelionEclipticYears: gArc ? 1296000 / gArc : undefined,
|
|
652
|
-
ascendingNodePeriod: sArc ? 1296000 / sArc : undefined,
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
// ── The planets' spin channel (plan 06 Phase 7): the precession constant
|
|
657
|
-
// from each planet's OWN torques (astro-reference planetSpinPhysical) on the
|
|
658
|
-
// model's OWN orbit — the chain's J2000 a/e/plane and the deep ζ table —
|
|
659
|
-
// integrated as dŝ/dt = α(ŝ·n̂)(ŝ×n̂) from the IAU J2000 pole. ONE home:
|
|
660
|
-
// planets/spin-channel.cjs; built lazily per planet, pure in `year`.
|
|
661
|
-
/** @type {Map<string, ReturnType<typeof createPlanetSpinChannelFromArtifacts>>} */
|
|
662
|
-
const spinChannels = new Map();
|
|
663
|
-
/** @param {string} k */
|
|
664
|
-
const planetSpin = (k) => {
|
|
665
|
-
if (!PLANET_KEYS.includes(k)) throw new Error(`planets.spin: unknown planet '${k}'`);
|
|
666
|
-
let ch = spinChannels.get(k);
|
|
667
|
-
if (!ch) {
|
|
668
|
-
ch = createPlanetSpinChannelFromArtifacts({
|
|
669
|
-
key: k,
|
|
670
|
-
planetSpinPhysical: C.planetSpinPhysical,
|
|
671
|
-
chainAnchorElements: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements,
|
|
672
|
-
planetZeta: /** @type {any} */ (DEEP_MODES_ARTIFACT).planetZeta,
|
|
673
|
-
massFractionOfSun: massFraction[k],
|
|
674
|
-
gmSunKm3S2: GM_SUN,
|
|
675
|
-
obliquityJ2000Deg: C.earthOrbital.obliquityJ2000_deg,
|
|
676
|
-
});
|
|
677
|
-
spinChannels.set(k, ch);
|
|
678
|
-
}
|
|
679
|
-
return ch;
|
|
680
|
-
};
|
|
681
|
-
|
|
682
|
-
// The planets' elements of date ride THE CHAIN — the only planet path the
|
|
683
|
-
// simulator renders (K5) — with the D5 series handover beyond each planet's
|
|
684
|
-
// measured boundary when the series artifact is supplied: the mirror of the
|
|
685
|
-
// browser's _kcElementsOfDate → _kcSeriesSecularEl. Until v16.2 the API
|
|
686
|
-
// served the retired device here (the record's linear lattice rates:
|
|
687
|
-
// perihelionEclipticYears, ascendingNodePeriod = −8H/N, the balanced-year
|
|
688
|
-
// inclination oscillation) — a published surface disagreeing with the
|
|
689
|
-
// simulator (owner-found audit, 2026-10). Those forms
|
|
690
|
-
// (planets/orientation.cjs) now serve only the structural record and the
|
|
691
|
-
// browser's no-chain bodies (Pluto, Halley, Eros). The chain's argument is
|
|
692
|
-
// dynamical time; the API's decimal year is taken as that argument (ΔT on a
|
|
693
|
-
// secular element is far below its stated accuracy).
|
|
694
|
-
let planetChains = /** @type {any} */ (null);
|
|
695
|
-
let planetSeriesOverride = /** @type {any} */ (null);
|
|
696
|
-
let planetNodeOriginSSDeg = /** @type {number|null} */ (null);
|
|
697
|
-
/** @param {string} k @param {number} year */
|
|
698
|
-
const planetChainElementsAt = (k, year) => {
|
|
699
|
-
if (!planetChains) planetChains = buildPlanetChainsFromArtifactData(/** @type {any} */ (CHAIN_ARTIFACT));
|
|
700
|
-
const el = computePlanetElementsAtYear(year, planetChains[k], planetChains);
|
|
701
|
-
const seriesArt = /** @type {any} */ (secularSeriesArtifact);
|
|
702
|
-
if (!seriesArt) return el;
|
|
703
|
-
if (!planetSeriesOverride) {
|
|
704
|
-
planetSeriesOverride = createSecularSeriesOverride({
|
|
705
|
-
series: seriesArt,
|
|
706
|
-
anchorElements: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements,
|
|
707
|
-
invariablePlane: /** @type {any} */ (CHAIN_ARTIFACT).invariablePlane,
|
|
708
|
-
planetZModes: /** @type {any} */ (DEEP_MODES_ARTIFACT).planetZ,
|
|
709
|
-
planetZetaModes: /** @type {any} */ (DEEP_MODES_ARTIFACT).planetZeta,
|
|
710
|
-
});
|
|
711
|
-
}
|
|
712
|
-
return planetSeriesOverride.applyToElements(k, year, el);
|
|
713
|
-
};
|
|
714
|
-
/** Ecliptic longitude of perihelion, J2000 ecliptic and equinox (the chain's ϖ). @param {string} k @param {number} year @returns {number} */
|
|
715
|
-
const planetPerihelionDeg = (k, year) => planetChainElementsAt(k, year).lonPeriEclipticDeg;
|
|
716
|
-
/** The S&S longitude origin as an s-frame longitude (J2000-fixed, derived). @returns {number} */
|
|
717
|
-
const nodeOriginSSDeg = () => {
|
|
718
|
-
if (planetNodeOriginSSDeg === null) {
|
|
719
|
-
planetNodeOriginSSDeg = computeEquatorNodeOriginSFrameDeg(/** @type {any} */ (CHAIN_ARTIFACT).invariablePlane, C.earthOrbital.obliquityJ2000_deg);
|
|
720
|
-
}
|
|
721
|
-
return planetNodeOriginSSDeg;
|
|
722
|
-
};
|
|
723
|
-
/** Ascending node on the model's invariable plane, from the plane's ascending node on the ICRF equator (the Souami & Souchay 2012 origin; derived conversion, inv-plane-frame). @param {string} k @param {number} year @returns {number} */
|
|
724
|
-
const planetAscNodeDeg = (k, year) => convertNodeSFrameToEquatorOriginDeg(planetChainElementsAt(k, year).ascNodeInvPlaneDeg, nodeOriginSSDeg());
|
|
725
|
-
/** Inclination to the model's invariable plane (exact orbit-normal rotation). @param {string} k @param {number} year @returns {number} */
|
|
726
|
-
const planetInclinationDeg = (k, year) => planetChainElementsAt(k, year).inclInvPlaneDeg;
|
|
727
|
-
/** Orbital eccentricity of date, from the same chain elements (R8): the
|
|
728
|
-
* honest replacement for the record's retired base + amplitude + phase
|
|
729
|
-
* triple, which presumed a single oscillation the chain's multi-mode
|
|
730
|
-
* e-vector does not have. @param {string} k @param {number} year @returns {number} */
|
|
731
|
-
const planetEccentricity = (k, year) => planetChainElementsAt(k, year).e;
|
|
732
|
-
|
|
733
|
-
// ── Earth's invariable-plane elements of date (plan 07 R5/R9) ─────────────
|
|
734
|
-
// ONE published i_inv / Ω_inv everywhere — the mirror of the browser's
|
|
735
|
-
// inclInvPlaneModel / ascNodeInvPlaneModel (identical ops): the engine's
|
|
736
|
-
// own Earth-orbit normal of date (the one-source sampler — the banked
|
|
737
|
-
// secular series inside ±10 Myr, the mode tail beyond) against the
|
|
738
|
-
// artifact's invariable plane, the node expressed in the Souami & Souchay
|
|
739
|
-
// longitude origin through the same derived conversion the planets' node
|
|
740
|
-
// takes. The H/3 cosine on the fixed apsidal carrier and the −H/5 linear
|
|
741
|
-
// node that served here until R5 were the K device: 1.578677° against
|
|
742
|
-
// 1.578422° at J2000, 1.24° against 1.91° at −100 kyr, and 112° against
|
|
743
|
-
// 94° of node there. Doc 05 banks the one-source reading at rms 0.003°
|
|
744
|
-
// vs La2010 over −500 kyr. Argument: the engine year (dynamical time,
|
|
745
|
-
// Julian from J2000 TT — the sampler's own coordinate, as the chain's).
|
|
746
|
-
const invPlaneGeometry = (() => {
|
|
747
|
-
const ip = /** @type {{ inclEclipticDeg: number, ascNodeEclipticDeg: number }} */ (/** @type {any} */ (CHAIN_ARTIFACT).invariablePlane);
|
|
748
|
-
const D2R = Math.PI / 180;
|
|
749
|
-
const si = Math.sin(ip.inclEclipticDeg * D2R), ci = Math.cos(ip.inclEclipticDeg * D2R);
|
|
750
|
-
const nInv = [si * Math.sin(ip.ascNodeEclipticDeg * D2R), -si * Math.cos(ip.ascNodeEclipticDeg * D2R), ci];
|
|
751
|
-
const xIp = [Math.cos(ip.ascNodeEclipticDeg * D2R), Math.sin(ip.ascNodeEclipticDeg * D2R), 0];
|
|
752
|
-
const yIp = [nInv[1] * xIp[2] - nInv[2] * xIp[1], nInv[2] * xIp[0] - nInv[0] * xIp[2], nInv[0] * xIp[1] - nInv[1] * xIp[0]];
|
|
753
|
-
return { ascNodeEclipticDeg: ip.ascNodeEclipticDeg, nInv, xIp, yIp };
|
|
754
|
-
})();
|
|
755
|
-
/** The engine Earth-orbit normal of date, J2000 ecliptic frame. @param {number} year @returns {number[]} */
|
|
756
|
-
const earthOrbitNormalJ2000At = (year) => {
|
|
757
|
-
const s = oneSourceM.sampleAt(year);
|
|
758
|
-
return [s.orbitNormalX, s.orbitNormalY, Math.sqrt(Math.max(0, 1 - s.orbitNormalX * s.orbitNormalX - s.orbitNormalY * s.orbitNormalY))];
|
|
759
|
-
};
|
|
760
|
-
/** Earth's inclination of date to the model's invariable plane, degrees. @param {number} year @returns {number} */
|
|
761
|
-
const inclinationDeg = (year) => {
|
|
762
|
-
const nE = earthOrbitNormalJ2000At(year), nInv = invPlaneGeometry.nInv;
|
|
763
|
-
const d = nE[0] * nInv[0] + nE[1] * nInv[1] + nE[2] * nInv[2];
|
|
764
|
-
return Math.acos(Math.min(1, Math.max(-1, d))) / (Math.PI / 180);
|
|
765
|
-
};
|
|
766
|
-
/** Earth's ascending node of date on the invariable plane, S&S origin, degrees in [0, 360). @param {number} year @returns {number} */
|
|
767
|
-
const ascendingNodeDeg = (year) => {
|
|
768
|
-
const D2R = Math.PI / 180;
|
|
769
|
-
const { ascNodeEclipticDeg, nInv, xIp, yIp } = invPlaneGeometry;
|
|
770
|
-
const nE = earthOrbitNormalJ2000At(year);
|
|
771
|
-
let N = [nInv[1] * nE[2] - nInv[2] * nE[1], nInv[2] * nE[0] - nInv[0] * nE[2], nInv[0] * nE[1] - nInv[1] * nE[0]];
|
|
772
|
-
const L = Math.hypot(N[0], N[1], N[2]);
|
|
773
|
-
N = [N[0] / L, N[1] / L, N[2] / L];
|
|
774
|
-
const sFrameDeg = ((Math.atan2(N[0] * yIp[0] + N[1] * yIp[1] + N[2] * yIp[2],
|
|
775
|
-
N[0] * xIp[0] + N[1] * xIp[1] + N[2] * xIp[2]) / D2R + ascNodeEclipticDeg) % 360 + 360) % 360;
|
|
776
|
-
return convertNodeSFrameToEquatorOriginDeg(sFrameDeg, nodeOriginSSDeg());
|
|
777
|
-
};
|
|
778
|
-
|
|
779
|
-
// ── Time axis: exact JD ↔ model-year conversion ───────────────────────────
|
|
780
|
-
// The model's `year` inputs live on the SI axis (the axis the fits were
|
|
781
|
-
// anchored on — tools/lib `_jdToSIyear`): linear in SI 86400-s days from the
|
|
782
|
-
// model start, so the JD↔year map is closed-form and exact to double
|
|
783
|
-
// precision. Callers holding an exact JD (e.g. 2058768.5385006 TT) convert
|
|
784
|
-
// here and NEVER roll their own — a caller-side linear-vs-calendar mix once
|
|
785
|
-
// put the eclipse umbra twin 8 km off (§12h; ≤1 m once unified).
|
|
786
|
-
const siTropicalYearDays = meanTropicalYearJ2000Seconds / 86400;
|
|
787
|
-
/** Model year (SI axis) at a JD(TT). @param {number} jd @returns {number} */
|
|
788
|
-
const yearFromJD = (jd) => startmodelYear + (jd - startmodelJD) / siTropicalYearDays;
|
|
789
|
-
/** JD(TT) at a model year (SI axis). @param {number} year @returns {number} */
|
|
790
|
-
const jdFromYear = (year) => startmodelJD + (year - startmodelYear) * siTropicalYearDays;
|
|
791
|
-
|
|
792
|
-
// ── Lunar theory: the shared-chain assembly (§7a slice-2b) ────────────────
|
|
793
|
-
// Wiring mirrors the engine call sites exactly — tools/lib/deep-time.js
|
|
794
|
-
// (ecc channel, month chain, J2000 precession anchors),
|
|
795
|
-
// tools/lib/scene-graph.js (chain-cycles, arguments, series) and
|
|
796
|
-
// tools/verify/eclipse-audit.js (finders). Deep-time and framework-native
|
|
797
|
-
// are hardwired ON here: they are the shipped defaults; the A/B env
|
|
798
|
-
// toggles (SG_DEEP_TIME/MOON_ARGS_PURE_MEEUS) stay an engine concern.
|
|
799
|
-
const j2000JD = 2451545.0;
|
|
800
|
-
const julianCenturyDays = 36525;
|
|
801
|
-
|
|
802
|
-
// J2000 Moon precession anchors (plan 09: the IAU inputs themselves). The
|
|
803
|
-
// legacy-'ICRF'-named inputs hold the EQUINOX-OF-DATE observables (Meeus/
|
|
804
|
-
// IERS 3231.50 d / 6798.38 d); the star-referenced (inertial) periods
|
|
805
|
-
// follow by removing the equinox's own precession, 1/T_E = 1/T_I ∓ 1/T_p
|
|
806
|
-
// (perigee advances, node regresses), T_p the J2000 precession anchor.
|
|
807
|
-
// The retired era device counted these as eighth-integers per 8H and read
|
|
808
|
-
// the periods back as totalDaysInH/N (the ∓13 was H/13 cycles per H).
|
|
809
|
-
const { moonApsidalJ2000Seconds } = chain;
|
|
810
|
-
// (Plan 09 step 5c: the per-H of-date cycle counts and the month chain's H²
|
|
811
|
-
// scaling of the of-date periods are deleted; the of-date perigee/node are
|
|
812
|
-
// the chain's count compositions.)
|
|
813
|
-
|
|
814
|
-
// Derived months on the IAU inputs (constants.js §Moon derived months)
|
|
815
|
-
const moonTropicalMonthDays = 1 / (1 / moonSiderealMonth + 1 / axialPrecessionJ2000Days);
|
|
816
|
-
const moonAnomalisticMonthDays = 1 / (1 / moonSiderealMonth - 86400 / moonApsidalJ2000Seconds);
|
|
817
|
-
const moonSynodicMonthDays = moonSiderealMonth * meanSiderealYearDays / (meanSiderealYearDays - moonSiderealMonth);
|
|
818
|
-
|
|
819
|
-
// The Layer-2 month/precession chain (Brouwer-Clemence m² scaling × the
|
|
820
|
-
// e_E-line modulation on the ONE deep e — decision (ii), plan 02 §8) is
|
|
821
|
-
// the deep-time chain's `moonChain` above.
|
|
822
|
-
|
|
823
|
-
// Chain-cycle integrator. S5/S12 conventions: age anchor = startmodelYear
|
|
824
|
-
// (the scene's t_Ma convention), grid anchor C(2000) = 0 — grid anchor ≠
|
|
825
|
-
// age anchor, deliberately. One stable period fn per chain so the shared
|
|
826
|
-
// Float64Array tables key correctly and persist.
|
|
827
|
-
const chainCycles = createChainCycleIntegrator({
|
|
828
|
-
ageAnchorYear: startmodelYear,
|
|
829
|
-
tropicalYearJ2000Seconds: meanTropicalYearJ2000Seconds, // the SI tick (plan 09 step 7c′)
|
|
830
|
-
isDeepTime: () => true,
|
|
831
|
-
});
|
|
832
|
-
/** @param {number} tMa @returns {number|null} */
|
|
833
|
-
const nodalMonthPeriodFn = (tMa) => moonChain.nodalMonthSecondsAtAge(tMa);
|
|
834
|
-
/** @param {number} tMa @returns {number|null} */
|
|
835
|
-
const tropicalMonthPeriodFn = (tMa) => moonChain.tropicalMonthSecondsAtAge(tMa);
|
|
836
|
-
/** @param {number} tMa @returns {number|null} */
|
|
837
|
-
const anomalisticMonthPeriodFn = (tMa) => moonChain.anomalisticMonthSecondsAtAge(tMa);
|
|
838
|
-
/** @param {number} tMa @returns {number|null} */
|
|
839
|
-
const siderealMonthPeriodFn = (tMa) => moonChain.siderealMonthSecondsAtAge(tMa);
|
|
840
|
-
const jupiterT0Seconds = C.planetOrbitalElements.jupiter.solarYearInput * 86400;
|
|
841
|
-
/** @param {number} tMa @returns {number} */
|
|
842
|
-
const jupiterPeriodFn = (tMa) => driver2PeriodSecondsAtAge(tMa, jupiterT0Seconds, EPOCH_PARAMS.solarMassLossFracPerYear);
|
|
843
|
-
/** @param {number} a @param {number} b @returns {number|null} */
|
|
844
|
-
const mcDraconic = (a, b) => chainCycles.cyclesBetween(nodalMonthPeriodFn, a, b);
|
|
845
|
-
/** @param {number} a @param {number} b @returns {number|null} */
|
|
846
|
-
const mcTropical = (a, b) => chainCycles.cyclesBetween(tropicalMonthPeriodFn, a, b);
|
|
847
|
-
/** @param {number} a @param {number} b @returns {number|null} */
|
|
848
|
-
const mcAnomalistic = (a, b) => chainCycles.cyclesBetween(anomalisticMonthPeriodFn, a, b);
|
|
849
|
-
/** @param {number} a @param {number} b @returns {number|null} */
|
|
850
|
-
const mcJupiter = (a, b) => chainCycles.cyclesBetween(jupiterPeriodFn, a, b);
|
|
851
|
-
/** The Moon's sidereal (star-referenced) orbits — the series' A3 argument (plan 09 step 5c). @param {number} a @param {number} b @returns {number|null} */
|
|
852
|
-
const mcSidereal = (a, b) => chainCycles.cyclesBetween(siderealMonthPeriodFn, a, b);
|
|
853
|
-
/** @param {number} a @param {number} b @returns {number|null} */
|
|
854
|
-
const mcApsidalOfDate = (a, b) => {
|
|
855
|
-
const t = mcTropical(a, b), n = mcAnomalistic(a, b);
|
|
856
|
-
return (t === null || n === null) ? null : t - n;
|
|
857
|
-
};
|
|
858
|
-
/** @param {number} a @param {number} b @returns {number|null} */
|
|
859
|
-
const mcNodalOfDate = (a, b) => {
|
|
860
|
-
const dr = mcDraconic(a, b), t = mcTropical(a, b);
|
|
861
|
-
return (dr === null || t === null) ? null : dr - t;
|
|
862
|
-
};
|
|
863
|
-
|
|
864
|
-
// (The K snapshot-phase obliquity the lunar chain was certified against left
|
|
865
|
-
// with layer A / item 3c: the arguments' carrier reads the published ε.)
|
|
866
|
-
|
|
867
|
-
// The argument skeleton (the _FW_MOON bundle; Sun secular deviations on
|
|
868
|
-
// the CALENDAR year coordinate — S3)
|
|
869
|
-
const moonArgs = createMoonArguments({
|
|
870
|
-
constants: {
|
|
871
|
-
j2000JD,
|
|
872
|
-
julianCenturyDays,
|
|
873
|
-
eccentricityJ2000: C.earthOrbital.earthEccentricityJ2000,
|
|
874
|
-
eccentricityDotJ2000: C.earthOrbital.earthEccentricityDotJ2000,
|
|
875
|
-
eccentricityDotDotJ2000: C.earthOrbital.earthEccentricityDotDotJ2000,
|
|
876
|
-
elpEarthFigureJ2ArcsecPerCy2: C.moonMeeus.elpW1T2Decomposition_arcsecPerCy2.earthFigureJ2,
|
|
877
|
-
elpGeneralPrecessionPA_T2ArcsecPerCy2: C.moonMeeus.elpW1T2Decomposition_arcsecPerCy2.generalPrecessionPA_T2_Lieske1976,
|
|
878
|
-
// Decision (ii): the lunar chain reads ONE deep e end to end
|
|
879
|
-
eccE0: deepEcc.e0,
|
|
880
|
-
},
|
|
881
|
-
fns: {
|
|
882
|
-
eccAt: /** @param {number} tYr */ (tYr) => deepEcc.eccAt(tYr),
|
|
883
|
-
channelIntegral: /** @param {number} T @param {number} s */ (T, s) => deepEcc.channelIntegral(T, s),
|
|
884
|
-
// Layer A / item 3c (plan 06): the arguments' obliquity carrier reads the
|
|
885
|
-
// PUBLISHED ε (the one-source hybrid), not the K snapshot comb — one ε
|
|
886
|
-
// everywhere. Twins: script.js (_sceneEpsTargetDeg), scene-graph.js.
|
|
887
|
-
computeObliquityEarth: /** @param {number} year @returns {number} */ (year) => oneSourceM.epsAt(year),
|
|
888
|
-
// Plan 09: the arguments' Sun IS the one certified Sun — the mean
|
|
889
|
-
// longitude that integrates the one-family tropical year (the eclipse
|
|
890
|
-
// finder's Sun) and the series' mean perihelion of date (unwrapped),
|
|
891
|
-
// both on the TT Julian-year axis. The former "model timeline" Sun
|
|
892
|
-
// (360° per mean solar year plus the integral of the retired year
|
|
893
|
-
// combs) sat 0.2° behind the IAU mean Sun at −2000 — the combs could
|
|
894
|
-
// not carry the tropical year's secular drift. Twins: scene-graph.js,
|
|
895
|
-
// script.js.
|
|
896
|
-
sunMeanLonDegAtJdTT: /** @param {number} jdTT @returns {number} */ (jdTT) => sunMeanLongitudeDegAt(2000 + (jdTT - j2000JD) / 365.25),
|
|
897
|
-
sunPerihelionLonDegAtJdTT: /** @param {number} jdTT @returns {number} */ (jdTT) => sunPerihelionDegAt(2000 + (jdTT - j2000JD) / 365.25),
|
|
898
|
-
jdToSIyear: yearFromJD,
|
|
899
|
-
tropicalOrbitsBetween: mcTropical,
|
|
900
|
-
apsidalOfDateCyclesBetween: mcApsidalOfDate,
|
|
901
|
-
nodalOfDateCyclesBetween: mcNodalOfDate,
|
|
902
|
-
isDeepTime: () => true,
|
|
903
|
-
isFrameworkNative: () => true,
|
|
904
|
-
// (d′) of-date rate completion: the DYNAMICAL axial precession (the
|
|
905
|
-
// tweakpane day-form identity — real at J2000, epoch-valid) and the
|
|
906
|
-
// KINEMATIC pair's beat the chains embed. MATCHED TRIPLE with the
|
|
907
|
-
// tools-lib and browser wirings.
|
|
908
|
-
// Plan 09: the dynamical rate of date is the published precession
|
|
909
|
-
// period's (the one-family beat inside its window, the composed clock
|
|
910
|
-
// beyond) — the retired year combs' day-form beat read 60 % of the
|
|
911
|
-
// secular drift. Degrees per Julian year.
|
|
912
|
-
pDynDegPerYearAt: /** @param {number} year */ (year) => 360 / publishedAxialPrecessionYearsAtYear(year),
|
|
913
|
-
pKinDegPerYearAt: /** @param {number} year */ (year) => {
|
|
914
|
-
// MODEL-START-anchored age, matching the tools-lib/browser wirings
|
|
915
|
-
// bit-exactly — NOT yearToTMa's 2000.0 convention (the recorded
|
|
916
|
-
// 0.4977-yr parity trap, same class as getMoonDistanceKm above).
|
|
917
|
-
const t = (startmodelYear - year) / 1e6;
|
|
918
|
-
const sid = deepLod.siderealYearSecondsAtAge(t);
|
|
919
|
-
const trop = deepLod.tropicalYearSecondsAtAge(t);
|
|
920
|
-
return (sid === null || trop === null) ? 0 : 360 * (sid - trop) / sid;
|
|
921
|
-
},
|
|
922
|
-
},
|
|
923
|
-
});
|
|
924
|
-
|
|
925
|
-
// UT→TT on the CALENDAR decimal-year coordinate (script.js Phase 9.16 —
|
|
926
|
-
// a linear-year approximation here once cost ~5–6 s of ΔT and ~1e-3° of
|
|
927
|
-
// Moon longitude at the Babylonian epochs)
|
|
928
|
-
/** @param {number} jd @returns {number} */
|
|
929
|
-
const jdTTFromUT = (jd) => {
|
|
930
|
-
const tMa = (startmodelYear - jdToDecimalYear(jd)) / 1e6;
|
|
931
|
-
const dT = meanDeltaTSecondsAtAge(tMa);
|
|
932
|
-
return Number.isFinite(dT) ? jd + dT / 86400 : jd;
|
|
933
|
-
};
|
|
934
|
-
// ΔT at a JD on the CALENDAR-year axis (mirrors deep-time frameworkDeltaT;
|
|
935
|
-
// NOT deltaTSeconds above, which adds the deltaTStart anchor)
|
|
936
|
-
/** @param {number} jd @returns {number} */
|
|
937
|
-
const frameworkDeltaTSecondsAtJD = (jd) => {
|
|
938
|
-
const decYear = startmodelYear + (jd - startmodelJD) / meanSolarYearDays;
|
|
939
|
-
const dT = meanDeltaTSecondsAtAge((startmodelYear - decYear) / 1e6);
|
|
940
|
-
return Number.isFinite(dT) ? dT : 0;
|
|
941
|
-
};
|
|
942
|
-
|
|
943
|
-
// Bounded Meeus E-factor from the ONE deep e (decision (ii); the
|
|
944
|
-
// pure-Meeus polynomial A/B branch stays engine-local)
|
|
945
|
-
/** @param {number} dDays @returns {number} */
|
|
946
|
-
// (plan 09 step 7c: on the channel's Julian-year axis — the N-body series'
|
|
947
|
-
// time; the device's rounded tropical-year input read the axis 2e-5 short)
|
|
948
|
-
const fwEFactor = (dDays) => deepEcc.eFactorAt(dDays / 365.25);
|
|
949
|
-
|
|
950
|
-
// D2 derived additional-argument rates (deg/cy, from the J2000 month inputs;
|
|
951
|
-
// the derivation record derive-a1a2a3.js was deleted at plan 09 step 7e — docs/109 §22)
|
|
952
|
-
const fwA2RateDegPerCy = 2 * ((360 * 36525) / moonTropicalMonthDays)
|
|
953
|
-
- (360 * 36525) / moonAnomalisticMonthDays
|
|
954
|
-
- 2 * ((360 * 36525) / C.planetOrbitalElements.jupiter.solarYearInput);
|
|
955
|
-
const fwA3RateDegPerCy = (360 * 36525) / moonSiderealMonth;
|
|
956
|
-
|
|
957
|
-
// Meeus Ch. 47 truncated series (framework-native arguments + E-factor)
|
|
958
|
-
const moonSeries = createMoonSeries({
|
|
959
|
-
constants: {
|
|
960
|
-
moonL: F.MEEUS_LONGITUDE_TERMS,
|
|
961
|
-
moonB: F.MEEUS_LATITUDE_TERMS,
|
|
962
|
-
moonR: F.MEEUS_DISTANCE_TERMS.terms,
|
|
963
|
-
moonRMeanKm: F.MEEUS_DISTANCE_TERMS.meanKm,
|
|
964
|
-
moonDistanceJ2000Km: C.moonReference.moonDistance,
|
|
965
|
-
j2000JD,
|
|
966
|
-
julianCenturyDays,
|
|
967
|
-
fwA2RateDegPerCy,
|
|
968
|
-
fwA3RateDegPerCy,
|
|
969
|
-
},
|
|
970
|
-
fns: {
|
|
971
|
-
argsAt: /** @param {number} jdTT */ (jdTT) => moonArgs.argsAt(jdTT),
|
|
972
|
-
eFactorForD: fwEFactor,
|
|
973
|
-
eFactorAtJdTT: /** @param {number} jdTT */ (jdTT) => fwEFactor(jdTT - j2000JD),
|
|
974
|
-
// 20.3d(i): the Driver-1 ratio at the EVALUATED epoch (per-jd pure
|
|
975
|
-
// evaluator). MATCHED TRIPLE with the tools-lib and browser getters:
|
|
976
|
-
// identical age arithmetic — the SI-linear year (yearFromJD, never
|
|
977
|
-
// the calendar year: the recorded linear-vs-calendar mirror trap)
|
|
978
|
-
// against the MODEL-START anchor (startmodelYear, the browser's
|
|
979
|
-
// J2000_CALENDAR_YEAR — NOT this model's 2000.0 yearToTMa convention:
|
|
980
|
-
// the 0.5-yr difference is 4.95e-11 of distance and failed the
|
|
981
|
-
// bit-exact parity gate; plan 11 step 5 dropped the −0.83-d correction
|
|
982
|
-
// from the anchor, both twins alike). Falls back to the J2000 constant
|
|
983
|
-
// without a jd (legacy call shape) or past the domain.
|
|
984
|
-
getMoonDistanceKm: /** @param {number} [jdTT] */ (jdTT) => {
|
|
985
|
-
if (jdTT === undefined) return moonDistanceKm;
|
|
986
|
-
const d = moonDistanceMetresAtAge((startmodelYear - yearFromJD(jdTT)) / 1e6);
|
|
987
|
-
return d === null ? moonDistanceKm : d / 1000;
|
|
988
|
-
},
|
|
989
|
-
getEccentricityBase: () => C.moonReference.moonOrbitalEccentricityBase,
|
|
990
|
-
deltaTSeconds: /** @param {number} jd */ (jd) => (jdTTFromUT(jd) - jd) * 86400,
|
|
991
|
-
jdToSIyear: yearFromJD,
|
|
992
|
-
tropicalOrbitsBetween: mcTropical,
|
|
993
|
-
apsidalOfDateCyclesBetween: mcApsidalOfDate,
|
|
994
|
-
siderealOrbitsBetween: mcSidereal,
|
|
995
|
-
jupiterOrbitsBetween: mcJupiter,
|
|
996
|
-
isDeepTime: () => true,
|
|
997
|
-
isFrameworkNative: () => true,
|
|
998
|
-
},
|
|
999
|
-
});
|
|
1000
|
-
|
|
1001
|
-
// ── E4: the framework-native Sun (§12i item 11 — the 3b landing) ─────────
|
|
1002
|
-
// Assembled from the model's own laws, ZERO fitted sun constants:
|
|
1003
|
-
// e(t) = the H/16 eccentricity-channel law + the derived H/3
|
|
1004
|
-
// inclination-coupling imprint (amplitude base/2, lattice phase,
|
|
1005
|
-
// J2000-anchored difference form) — the osculating decomposition:
|
|
1006
|
-
// osculating e = H/16 channel + inclination coupling.
|
|
1007
|
-
// L(t) = L0 + the mean tropical rate + the f(Y) drift SHAPE only,
|
|
1008
|
-
// ∫(rate_SI(y) − rate_SI(2000)) dy: the rate ANCHOR stays the mean
|
|
1009
|
-
// year (eclipse-endorsed); the drift is the Step 6c year-harmonic
|
|
1010
|
-
// claim in SI/TT (year-in-days × LOD — the LOD-day part of the
|
|
1011
|
-
// raw drift is UT-vs-TT and stays ΔT's job) PLUS the derived
|
|
1012
|
-
// TORQUE term (E5): the year harmonics carry only the GEOMETRIC
|
|
1013
|
-
// equinox displacement (the tilt nodes — the exact 8:3 amplitude
|
|
1014
|
-
// signature); the classical luni-solar torque adds a precession-
|
|
1015
|
-
// RATE modulation δp = −p₀·tan ε·δε(t) on the model's own
|
|
1016
|
-
// two-component obliquity law (−A cos φ₃ + A cos φ₈). Both
|
|
1017
|
-
// lengthen the year at obliquity max, so they ADD; per-divisor
|
|
1018
|
-
// drift scale 1 + p₀·tan²ε·H/(2π·div) = 1.306 (H/8) / 1.815
|
|
1019
|
-
// (H/3) — the structure the ancient corpus blind-selected before
|
|
1020
|
-
// the derivation existed. Zero new constants. Trapezoid table,
|
|
1021
|
-
// 10-yr steps over −3000..3000; outside, the drift freezes at the
|
|
1022
|
-
// edge (rate reverts to linear — the finder domain is the corpus
|
|
1023
|
-
// era).
|
|
1024
|
-
// ϖ(t) = the shipped H/16 perihelion law (earthPerihelionDeg).
|
|
1025
|
-
// Measured (tools/explore/e3b-native-sun.mjs): beats the Meeus Ch. 25
|
|
1026
|
-
// basis on JPL all-phase (0.95″ vs 1.28″ scatter) and on ancient-corpus
|
|
1027
|
-
// timing structure (0.37 vs 0.50 min detrended vs Meeus-T²); required-ΔT
|
|
1028
|
-
// shift 2–4 min ≈ 0.23σ of Stephenson scatter (lunar bias improves); the
|
|
1029
|
-
// D2 completion table is unchanged (residual 2lE re-fit ≈ 0.1″ — noise).
|
|
1030
|
-
const sunL0Deg = C.earthOrbital.sunMeanLongitudeJ2000_deg;
|
|
1031
|
-
const sunTropicalRateDegPerCy = 360 * julianCenturyDays / meanSolarYearDays;
|
|
1032
|
-
// The eclipse Sun's eccentricity IS the model's one eccentricity law
|
|
1033
|
-
// (eccentricityAt above) — the former sunEccentricityAt (FQ-7-Sun option
|
|
1034
|
-
// C-small: the J2000-anchored H/3 line) was the additive-anchor form of the
|
|
1035
|
-
// same movement and is retired by the unification (measured identical on
|
|
1036
|
-
// every modern gate).
|
|
1037
|
-
const sunMeanLongitudeDegAt = (() => {
|
|
1038
|
-
// Plan 06 R1 — the Sun's mean longitude of date is the INTEGRAL of the
|
|
1039
|
-
// one-source tropical year: L(t) = L0 + 360·∫_{2000}^{t} dt′/T_trop(t′),
|
|
1040
|
-
// T_trop the route-B tropical year of date in SI seconds (the ONE
|
|
1041
|
-
// year-length family; the frozen era clock's tropicalYearDaysBase × LOD
|
|
1042
|
-
// and its comb ripple + torque term left here). MEASURED before the
|
|
1043
|
-
// move (tools/explore r1 probes, plan 06 record): the route-B tropical
|
|
1044
|
-
// year equals the IAU/Laskar drift expression to 0.1 s over −1000..+3000
|
|
1045
|
-
// while the era-clock year carried NO secular drift (+1.09 s flat), so
|
|
1046
|
-
// the former mean longitude wandered +12 min around 500 AD and diverged
|
|
1047
|
-
// −3.3 min/cy after 2100 against both Meeus ch. 27 and the one-source
|
|
1048
|
-
// integral — outside every eclipse and JPL gate. MODERN-WINDOW COST,
|
|
1049
|
-
// stated (plan 06 I1 corrected an earlier misreading of the cache's
|
|
1050
|
-
// clock): against the JPL Sun cache (UT instants, verified; the registry
|
|
1051
|
-
// instrument's bridge) the one-source Sun read 1.29″ sd in 1970–2049
|
|
1052
|
-
// where the era-clock Sun read 0.80″ — both carried ~0.02–0.03″/yr
|
|
1053
|
-
// trends against JPL over 1900–2100; accepted because over millennia
|
|
1054
|
-
// the era-clock Sun is minutes off. Plan 06 I2 located the trend: the
|
|
1055
|
-
// Earth–Mars–Jupiter long inequality (1783 yr, 6.3″) the smooth year
|
|
1056
|
-
// cannot carry — derived on the model's own N-body and shipped in the
|
|
1057
|
-
// planetary completion, the instrument reads 1.03″ (Horizons ±3000 yr:
|
|
1058
|
-
// modern-window mean +8.4 → +0.8″, per-millennium sd roughly halved).
|
|
1059
|
-
// NUMERICS (rate vs point value): a cumulative trapezoid table of
|
|
1060
|
-
// cycles, yearly inside ±20,000 yr and per century beyond, grown on
|
|
1061
|
-
// demand from 2000 in both directions and interpolated inside a cell —
|
|
1062
|
-
// never a rate multiplied by a span. Beyond the one-family window the
|
|
1063
|
-
// tidal-chain year continues the integrand (the scene overlay ends at
|
|
1064
|
-
// 20,000 yr; the finders refuse out-of-domain epochs upstream).
|
|
1065
|
-
const JULIAN_YEAR_S = 365.25 * 86400;
|
|
1066
|
-
const tropSec = oneFamilyTropicalYearSeconds;
|
|
1067
|
-
const FINE_SPAN = 20000, COARSE_STEP = 100;
|
|
1068
|
-
/** cycles from 2000 to 2000 ± i·step (fwd/bwd tiers) */
|
|
1069
|
-
/** @type {number[]} */ const fwdFine = [0];
|
|
1070
|
-
/** @type {number[]} */ const bwdFine = [0];
|
|
1071
|
-
/** @type {number[]} */ const fwdCoarse = [];
|
|
1072
|
-
/** @type {number[]} */ const bwdCoarse = [];
|
|
1073
|
-
/** UNSIGNED trapezoid cycles over the span between two years (Julian
|
|
1074
|
-
* years → SI seconds over the one-family year); the caller applies the
|
|
1075
|
-
* direction sign. @param {number} ya @param {number} yb @returns {number} */
|
|
1076
|
-
const segAbs = (ya, yb) => 0.5 * (Math.abs(yb - ya) * JULIAN_YEAR_S) * (1 / tropSec(ya) + 1 / tropSec(yb));
|
|
1077
|
-
/** signed cycles from 2000 to `year` @param {number} year @returns {number} */
|
|
1078
|
-
const cyclesTo = (year) => {
|
|
1079
|
-
const dy = year - 2000;
|
|
1080
|
-
const s = dy >= 0 ? 1 : -1, a = Math.abs(dy);
|
|
1081
|
-
// WARM THE SAMPLER TO THE TARGET FIRST (plan 06 R4, measured): the
|
|
1082
|
-
// table below grows outward in 1-yr / 100-yr steps, and every step
|
|
1083
|
-
// beyond ~1.6 Myr enlarged the one-family sampler's >2-Myr tier just
|
|
1084
|
-
// past its span, rebuilding the whole deep integration about every 32
|
|
1085
|
-
// steps — ~125 rebuilds and 22 s for the first deep-epoch call (the
|
|
1086
|
-
// scene's first jump to −5 Myr), 0.4 ms once built. One read at the
|
|
1087
|
-
// clamped target builds the tier at its final span; the grid stores
|
|
1088
|
-
// are endpoint-independent, so every value is bit-identical.
|
|
1089
|
-
tropSec(2000 + s * Math.min(a, ONE_FAMILY_WINDOW_YEARS));
|
|
1090
|
-
const fine = s > 0 ? fwdFine : bwdFine;
|
|
1091
|
-
const growFine = (/** @type {number} */ upto) => { while (fine.length <= upto) { const k = fine.length; fine.push(fine[k - 1] + s * segAbs(2000 + s * (k - 1), 2000 + s * k)); } };
|
|
1092
|
-
if (a <= FINE_SPAN) {
|
|
1093
|
-
const i = Math.floor(a), f = a - i;
|
|
1094
|
-
growFine(i + 1);
|
|
1095
|
-
return fine[i] + f * (fine[i + 1] - fine[i]);
|
|
1096
|
-
}
|
|
1097
|
-
growFine(FINE_SPAN);
|
|
1098
|
-
const coarse = s > 0 ? fwdCoarse : bwdCoarse;
|
|
1099
|
-
if (coarse.length === 0) coarse.push(fine[FINE_SPAN]);
|
|
1100
|
-
const c = (a - FINE_SPAN) / COARSE_STEP, ci = Math.floor(c), cf = c - ci;
|
|
1101
|
-
while (coarse.length <= ci + 1) { const k = coarse.length; const y0 = 2000 + s * (FINE_SPAN + (k - 1) * COARSE_STEP); coarse.push(coarse[k - 1] + s * segAbs(y0, y0 + s * COARSE_STEP)); }
|
|
1102
|
-
return coarse[ci] + cf * (coarse[ci + 1] - coarse[ci]);
|
|
1103
|
-
};
|
|
1104
|
-
return /** @param {number} year @returns {number} */ (year) => sunL0Deg + 360 * cyclesTo(year);
|
|
1105
|
-
})();
|
|
1106
|
-
// Plan 09: the lunar arguments' Sun perihelion of date is the eclipse
|
|
1107
|
-
// Sun's mean perihelion (`sunPerihelionDegAt`) read DIRECTLY, wrapped.
|
|
1108
|
-
// Every consumer wraps the argument it enters (M = Lsun − ϖ − 180) or
|
|
1109
|
-
// differences it over ±25 days (the rate anchors, wrapped to ±180°), so
|
|
1110
|
-
// no continuous angle is needed. MEASURED: a 100-yr unwrapping ladder
|
|
1111
|
-
// (two series reads per rung, 53,400 rungs at −5.34 Myr) cost the cold
|
|
1112
|
-
// deep jump 1,062 s — 343× the in-table jump against the perf gate's 8× —
|
|
1113
|
-
// for a value the consumers reduced mod 360 anyway.
|
|
1114
|
-
|
|
1115
|
-
// Eclipse finders — wired like the engine probe (tools/verify/
|
|
1116
|
-
// eclipse-audit.js). The finder axis is JD(UT): the series wrapper applies
|
|
1117
|
-
// UT→TT internally. Ground-track/umbra paths deliberately absent: the
|
|
1118
|
-
// scene-umbra projection navigates the Tychosium-derived scaffold, which
|
|
1119
|
-
// never enters this package (§2h).
|
|
1120
|
-
const eclipseFinders = createEclipseFinders({
|
|
1121
|
-
moonLonDegAt: /** @param {number} jd */ (jd) => moonSeries.truncatedLonDeg(jd),
|
|
1122
|
-
moonBetaDegAt: /** @param {number} jd */ (jd) => moonSeries.truncatedBetaDeg(jd),
|
|
1123
|
-
moonDistanceKmAt: /** @param {number} jd */ (jd) => moonSeries.truncatedDistanceKm(jd),
|
|
1124
|
-
deltaTSecondsAt: frameworkDeltaTSecondsAtJD,
|
|
1125
|
-
getSynodicMonthDays: () => moonSynodicMonthDays,
|
|
1126
|
-
getSunDistanceKm: () => currentAUDistance,
|
|
1127
|
-
frameworkSun: {
|
|
1128
|
-
sunMeanLongitudeJ2000Deg: sunL0Deg,
|
|
1129
|
-
tropicalRateDegPerCy: sunTropicalRateDegPerCy,
|
|
1130
|
-
eccentricityAt: sunEccentricityAt,
|
|
1131
|
-
perihelionLongitudeDegAt: sunPerihelionDegAt,
|
|
1132
|
-
meanLongitudeDegAt: sunMeanLongitudeDegAt,
|
|
1133
|
-
},
|
|
1134
|
-
constants: {
|
|
1135
|
-
rEarthMetres: (C.bodyDiametersKm.earth / 2) * 1000,
|
|
1136
|
-
moonDiameterKm: C.bodyDiametersKm.moon,
|
|
1137
|
-
sunDiameterKm: C.bodyDiametersKm.sun,
|
|
1138
|
-
j2000JD,
|
|
1139
|
-
julianCenturyDays,
|
|
1140
|
-
},
|
|
1141
|
-
});
|
|
1142
|
-
|
|
1143
|
-
// 20.3g — the solar-eclipse LOCATION tier: shadow geometry on the FULL
|
|
1144
|
-
// series (sceneEvalAt — the truncated finder forms omit the fitted Lp
|
|
1145
|
-
// anchor and the −2235·sin(Lp) β family, deliberate for finder
|
|
1146
|
-
// statistics, required here) at the model's ABSOLUTE TT (deltaTStart +
|
|
1147
|
-
// curve, the same convention every other ΔT consumer reads). Both axis
|
|
1148
|
-
// conventions are measured against the NASA path-table centerlines —
|
|
1149
|
-
// see eclipse/besselian.cjs.
|
|
1150
|
-
// Derived Earth-around-EMB wobble for the Sun completion: a_M·μ/AU,
|
|
1151
|
-
// μ = 1/(1+M_E/M_M) — 6.4399″ at current constants, tracks them live.
|
|
1152
|
-
const embWobbleArcsec = (moonDistanceKm / (MASS_RATIO_EARTH_MOON + 1) / currentAUDistance)
|
|
1153
|
-
* (648000 / Math.PI);
|
|
1154
|
-
// FQ-5 N3 — the completion's carriers are FRAMEWORK-derived from the
|
|
1155
|
-
// model's own planet period records (the Moon-elongation rate from the
|
|
1156
|
-
// sidereal month/year identity). Plan 06 I2 — the carriers are SIDEREAL
|
|
1157
|
-
// (measured): the records' solarYearInput are OF-DATE periods (their
|
|
1158
|
-
// rates sit +1.39..1.62°/cy above the VSOP sidereal mean motions — the
|
|
1159
|
-
// framework precession plus input rounding), and a perturbation argument
|
|
1160
|
-
// is inertial (D'Alembert: only Σk = 0 arguments are frame-free), so on
|
|
1161
|
-
// of-date carriers every Σk ≠ 0 argument drifted by Σk·ψ(t) — 42..52° at
|
|
1162
|
-
// −3000 for the table's Σk = −1 terms (their ancient scatter against
|
|
1163
|
-
// Horizons 6.4 → 4.4″ on sidereal carriers), and 6 % of frequency for the
|
|
1164
|
-
// 1783-yr long inequality (1683 yr on the of-date carriers). Constant-free:
|
|
1165
|
-
// the record rate minus the model's own J2000 precession p₀ =
|
|
1166
|
-
// 360·36525·(1/T_trop − 1/T_sid) for the planets, the framework sidereal
|
|
1167
|
-
// year for Earth; identical to the N3 carriers at J2000 (same phase
|
|
1168
|
-
// anchors), ≤ 1.4°·|Σk| apart at the 200-yr extraction window's edges
|
|
1169
|
-
// (the composed table reproduces the N3 one there: JPL 1900–2100
|
|
1170
|
-
// all-phase sd unchanged to 0.01″). The parity gate's fingerprint mirrors
|
|
1171
|
-
// this arithmetic (test/create-model-parity.test.mjs).
|
|
1172
|
-
// PLAN 06 I3 — the carriers are the model's own banked J2000 sidereal mean
|
|
1173
|
-
// motions (the embedded sun-completion artifact; ONE home,
|
|
1174
|
-
// computeCarrierRatesDegPerCy — the former record-based arithmetic sat
|
|
1175
|
-
// 4.1″/yr off for Venus, 1.7″/yr for Jupiter: 83° of the Venus–Earth
|
|
1176
|
-
// argument at ±9000 yr), Earth the framework sidereal year, the Moon
|
|
1177
|
-
// elongation from the sidereal month/year identity. The long-period rows
|
|
1178
|
-
// ride the embedded e-vectors of date, and the lunar equation rides the
|
|
1179
|
-
// framework's own Moon elongation of date (ṅ included) — the constant-rate
|
|
1180
|
-
// carrier ran ~29° off it at ±9000 yr.
|
|
1181
|
-
const carrierRatesDegPerCy = computeCarrierRatesDegPerCy({ meanSiderealYearDays, moonSiderealMonthDays: moonSiderealMonthInput });
|
|
1182
|
-
const { sunPlanetaryCompletionDeg } = createSunPlanetaryCompletion({
|
|
1183
|
-
embWobbleArcsec,
|
|
1184
|
-
carrierRatesDegPerCy,
|
|
1185
|
-
moonElongationDegAtT: /** @param {number} T */ (T) => moonArgs.argsAt(j2000JD + T * julianCenturyDays).D,
|
|
1186
|
-
});
|
|
1187
|
-
const besselian = createBesselian({
|
|
1188
|
-
moonFullAtDaysTT: /** @param {number} dDaysTT */ (dDaysTT) => {
|
|
1189
|
-
const ev = moonSeries.sceneEvalAt(dDaysTT);
|
|
1190
|
-
return { lonDeg: ev.lonDeg, latDeg: ev.latDeg, distKm: ev.distKm };
|
|
1191
|
-
},
|
|
1192
|
-
sunLonDegAt: /** @param {number} jdUT */ (jdUT) => eclipseFinders.sunLonDegAt(jdUT),
|
|
1193
|
-
sunCompletionDeg: sunPlanetaryCompletionDeg,
|
|
1194
|
-
// plan 06 R3 item 1: the location tier on APPARENT places — the Sun's derived κ
|
|
1195
|
-
// (the same helper the cardinal instants use), the Moon's relative light-time
|
|
1196
|
-
// inside the besselian; the series-extension tail now lives in sceneEvalAt.
|
|
1197
|
-
sunAberrationDegAt: /** @param {number} year */ (year) => sunAberrationArcsecAt(year) / 3600,
|
|
1198
|
-
deltaTSecondsAt: /** @param {number} jd */ (jd) => (jdTTFromUT(jd) - jd) * 86400,
|
|
1199
|
-
obliquityDegAt: obliquityDeg,
|
|
1200
|
-
eccentricityAt: sunEccentricityAt,
|
|
1201
|
-
perihelionLongitudeDegAt: sunPerihelionDegAt,
|
|
1202
|
-
yearFromJD,
|
|
1203
|
-
constants: {
|
|
1204
|
-
j2000JD,
|
|
1205
|
-
julianCenturyDays,
|
|
1206
|
-
earthDiameterKm: C.bodyDiametersKm.earth,
|
|
1207
|
-
moonDiameterKm: C.bodyDiametersKm.moon,
|
|
1208
|
-
sunDiameterKm: C.bodyDiametersKm.sun,
|
|
1209
|
-
sunDistanceKm: currentAUDistance,
|
|
1210
|
-
earthFlatteningInverse: C.physicalConstants.earthFlatteningInverseWGS84,
|
|
1211
|
-
ttBridgeSeconds: C.earthOrbital.deltaTStart,
|
|
1212
|
-
gmstMeanSiderealT0Deg: C.physicalConstants.gmstMeanSiderealT0Deg,
|
|
1213
|
-
gmstMeanSiderealRateDegPerDay: C.physicalConstants.gmstMeanSiderealRateDegPerDay,
|
|
1214
|
-
gmstMeanSiderealT2Deg: C.physicalConstants.gmstMeanSiderealT2Deg,
|
|
1215
|
-
speedOfLightKmS: C.physicalConstants.speedOfLight,
|
|
1216
|
-
},
|
|
1217
|
-
});
|
|
1218
|
-
|
|
1219
|
-
// ── The assembled surface ─────────────────────────────────────────────────
|
|
1220
|
-
// Plan 06 Phase 3 S2 — THE published of-date precession period and mean
|
|
1221
|
-
// tropical year: the one-family route (B) inside the banked tiers
|
|
1222
|
-
// (|Δyear| ≤ ONE_FAMILY_WINDOW_YEARS), the composed lunisolar period
|
|
1223
|
-
// beyond (S5: on the derived J2000 anchor, so the two faces agree at
|
|
1224
|
-
// 25,771.4 at J2000 and the deep tail is the same clock scaled; the
|
|
1225
|
-
// tidal-chain year). Shared by `epoch` and `lunisolar`.
|
|
1226
|
-
/** @param {number} year @returns {number} */
|
|
1227
|
-
const publishedAxialPrecessionYearsAtYear = (year) => {
|
|
1228
|
-
if (Math.abs(year - 2000) <= ONE_FAMILY_WINDOW_YEARS) return yearLengthsM.axialPrecessionYearsAtYear(year);
|
|
1229
|
-
const p = deepLod.lunisolarPrecessionPeriodYearsAtAge(yearToTMa(year));
|
|
1230
|
-
return p === null ? certifiedAxialPrecessionJ2000Years() : p;
|
|
1231
|
-
};
|
|
1232
|
-
/** @param {number} year @returns {number} */
|
|
1233
|
-
const publishedTropicalYearSecondsAtYear = (year) => {
|
|
1234
|
-
if (Math.abs(year - 2000) <= ONE_FAMILY_WINDOW_YEARS) return yearLengthsM.tropicalYearSecondsAtYear(year);
|
|
1235
|
-
return deepLod.tropicalYearSecondsAtAge(yearToTMa(year));
|
|
1236
|
-
};
|
|
1237
|
-
/** The published sidereal year of date, SI seconds — the one-family λ̇
|
|
1238
|
-
* channel inside the window, the mass-loss law beyond (plan 09: the
|
|
1239
|
-
* `lengths` surface's days ride it). @param {number} year @returns {number} */
|
|
1240
|
-
const publishedSiderealYearSecondsAtYear = (year) => {
|
|
1241
|
-
if (Math.abs(year - 2000) <= ONE_FAMILY_WINDOW_YEARS) return yearLengthsM.siderealYearSecondsAtYear(year);
|
|
1242
|
-
return deepLod.siderealYearSecondsAtAge(yearToTMa(year));
|
|
1243
|
-
};
|
|
1244
|
-
// ── Cardinal instants (plan 06 R1) ─────────────────────────────────────
|
|
1245
|
-
/** The completed certified Sun (finder Sun − the derived planetary
|
|
1246
|
-
* completion) at a UT model-JD — the same longitude the scene renders
|
|
1247
|
-
* inside the overlay window; MEAN GEOMETRIC, mean equinox of date.
|
|
1248
|
-
* @param {number} jdUT @returns {number} */
|
|
1249
|
-
const sunLonCompletedDegAtJdUT = (jdUT) => eclipseFinders.sunLonDegAt(jdUT)
|
|
1250
|
-
- sunPlanetaryCompletionDeg((jdTTFromUT(jdUT) - j2000JD) / julianCenturyDays);
|
|
1251
|
-
/** The APPARENT Sun the cardinal instants are defined on (an equinox is
|
|
1252
|
-
* the apparent Sun crossing the equator — the USNO/Meeus instants are
|
|
1253
|
-
* apparent): the completed geometric Sun minus the aberration constant,
|
|
1254
|
-
* plus the nutation in longitude. Both derived, zero new constants —
|
|
1255
|
-
* κ = 2π·a/(c·T_sid·√(1−e²)) from the AU, c, the one-family sidereal year
|
|
1256
|
-
* and the Sun's e (20.50″ at J2000); Δψ from the four IAU 1980 leading
|
|
1257
|
-
* terms on the model's OWN lunar node, mean Sun and mean Moon (the
|
|
1258
|
-
* framework arguments), the same family the registry's JPL Sun
|
|
1259
|
-
* instrument bridges with. @param {number} jdUT @returns {number} */
|
|
1260
|
-
/** The Sun's derived aberration constant of date, arcsec — κ = 2π·a/(c·T_sid·√(1−e²))
|
|
1261
|
-
* from the AU, c, the one-family sidereal year and the Sun's e (20.50″ at
|
|
1262
|
-
* J2000); ONE home for the cardinal instants and the eclipse location tier.
|
|
1263
|
-
* @param {number} year @returns {number} */
|
|
1264
|
-
const sunAberrationArcsecAt = (year) => {
|
|
1265
|
-
const e = sunEccentricityAt(year);
|
|
1266
|
-
return (2 * Math.PI * currentAUDistance
|
|
1267
|
-
/ (C.physicalConstants.speedOfLight * yearLengthsM.siderealYearSecondsAtYear(year) * Math.sqrt(1 - e * e)))
|
|
1268
|
-
* (648000 / Math.PI);
|
|
1269
|
-
};
|
|
1270
|
-
/** @param {number} jdUT @returns {number} */
|
|
1271
|
-
const sunApparentLonDegAtJdUT = (jdUT) => {
|
|
1272
|
-
const jdTT = jdTTFromUT(jdUT);
|
|
1273
|
-
const year = 2000 + (jdTT - j2000JD) / 365.25;
|
|
1274
|
-
const kappaArcsec = sunAberrationArcsecAt(year);
|
|
1275
|
-
const a = moonArgs.argsAt(jdTT);
|
|
1276
|
-
const d2r = Math.PI / 180;
|
|
1277
|
-
const Om = (a.Lp - a.F) * d2r, Ls = (a.Lp - a.D) * d2r, Lm = a.Lp * d2r;
|
|
1278
|
-
const NU = C.physicalConstants.nutationLeadingTermsArcsec;
|
|
1279
|
-
const dPsiArcsec = NU.psiOmega * Math.sin(Om) + NU.psi2Ls * Math.sin(2 * Ls)
|
|
1280
|
-
+ NU.psi2Lm * Math.sin(2 * Lm) + NU.psi2Omega * Math.sin(2 * Om);
|
|
1281
|
-
return sunLonCompletedDegAtJdUT(jdUT) + (dPsiArcsec - kappaArcsec) / 3600;
|
|
1282
|
-
};
|
|
1283
|
-
/** @param {string} type @returns {number} */
|
|
1284
|
-
const cardinalTargetDeg = (type) => {
|
|
1285
|
-
const t = { VE: 0, SS: 90, AE: 180, WS: 270 }[type];
|
|
1286
|
-
if (t === undefined) throw new RangeError(`cardinal type must be VE|SS|AE|WS, got ${type}`);
|
|
1287
|
-
return t;
|
|
1288
|
-
};
|
|
1289
|
-
const CARDINAL_SI_YEAR_D = 365.2422;
|
|
1290
|
-
/** The crossing NEAREST a seed instant — the unique root within ±½ tropical
|
|
1291
|
-
* year of the seed (the wrapped longitude difference is the Newton residual).
|
|
1292
|
-
* Plan 06 R4c: the seed is a JD because the caller's year may live on a
|
|
1293
|
-
* different axis than the model year — the simulator's cardinal panel
|
|
1294
|
-
* labels its year with the displayed CALENDAR date (the Julian calendar
|
|
1295
|
-
* before 1582, 365.25-d years) while `year` below is the model year (the SI
|
|
1296
|
-
* axis, 365.2422-d count from J2000); the two part by 0.0078 d/yr, 114 yr at
|
|
1297
|
-
* −5.34 Myr, where the panel showed the events of −5341772 for a date in
|
|
1298
|
-
* −5341886 (owner). Seeding at the calendar year's midpoint returns that
|
|
1299
|
-
* year's own events at every epoch. @param {number} jdSeedUT @param {string} type @returns {number} */
|
|
1300
|
-
const cardinalCrossingNearJdUT = (jdSeedUT, type) => {
|
|
1301
|
-
const target = cardinalTargetDeg(type);
|
|
1302
|
-
const RATE = 360 / CARDINAL_SI_YEAR_D;
|
|
1303
|
-
let jd = jdSeedUT;
|
|
1304
|
-
for (let i = 0; i < 20; i++) {
|
|
1305
|
-
const d = ((((sunApparentLonDegAtJdUT(jd) - target) + 540) % 360 + 360) % 360) - 180;
|
|
1306
|
-
jd -= d / RATE;
|
|
1307
|
-
if (Math.abs(d) < 1e-10) break;
|
|
1308
|
-
}
|
|
1309
|
-
return jd - C.earthOrbital.deltaTStart / 86400;
|
|
1310
|
-
};
|
|
1311
|
-
/** The TRUE-UT JD at which the APPARENT Sun's longitude of date equals
|
|
1312
|
-
* the cardinal target in the given year — Newton on the crossing (the
|
|
1313
|
-
* Sun's rate 360°/tropical year; a handful of steps from the tropical-year
|
|
1314
|
-
* seed). Replaces the fitted cardinal model's instants (R1). Plan 06 R3
|
|
1315
|
-
* item 2: the Newton root lives on the FINDER axis (the curve-only ΔT the
|
|
1316
|
-
* eclipse finders certify), and the returned instant is that root minus the
|
|
1317
|
-
* deltaTStart bridge — true UT = TT − (deltaTStart + curve), the same
|
|
1318
|
-
* bridge the besselian and the registry instruments apply. Before this the
|
|
1319
|
-
* published instants were 54.55 s (0.9 min) late. Against Horizons over
|
|
1320
|
-
* ±3000 yr the remaining offset is the Sun's (plan 06 I2 measured).
|
|
1321
|
-
* `year` is the MODEL year (the SI axis) — see cardinalCrossingNearJdUT.
|
|
1322
|
-
* @param {number} year @param {string} type @returns {number} */
|
|
1323
|
-
const cardinalCrossingJdUT = (year, type) => {
|
|
1324
|
-
const target = cardinalTargetDeg(type);
|
|
1325
|
-
// seed: Jan 1.5 of the year (J2000 = 2000 Jan 1.5) + the mean date of the
|
|
1326
|
-
// March equinox (day 79.3) + the quarter-turns to the target
|
|
1327
|
-
const seed = j2000JD + (year - 2000) * CARDINAL_SI_YEAR_D + 79.3 + (target / 360) * CARDINAL_SI_YEAR_D;
|
|
1328
|
-
return cardinalCrossingNearJdUT(seed, type);
|
|
1329
|
-
};
|
|
1330
|
-
|
|
1331
|
-
return Object.freeze({
|
|
1332
|
-
time: Object.freeze({
|
|
1333
|
-
yearFromJD,
|
|
1334
|
-
jdFromYear,
|
|
1335
|
-
siTropicalYearDays,
|
|
1336
|
-
}),
|
|
1337
|
-
// The Moon-Kepler mass chain — the J2000 derivation docs 24 / the website's
|
|
1338
|
-
// "mass from the Moon" page narrate, published from the one place that
|
|
1339
|
-
// computes it (physics 22.1.0; the pages used to carry its numbers as
|
|
1340
|
-
// hand-typed literals): Kepler III on the Moon's orbit with the
|
|
1341
|
-
// solar-tidal shift Δa = a·μ·m (μ the Moon's mass fraction, m the lunar
|
|
1342
|
-
// small parameter T_M/T_sidereal-year), the Earth/Moon split on the
|
|
1343
|
-
// DE440 mass ratio, and GM_Sun from Earth's heliocentric orbit minus
|
|
1344
|
-
// GM_Earth. Every value is the J2000 snapshot the rest of the model runs
|
|
1345
|
-
// on; the of-date Moon distance is the recession history (epoch.*).
|
|
1346
|
-
massChain: Object.freeze({
|
|
1347
|
-
moonDistanceKm,
|
|
1348
|
-
moonSiderealMonthDays: moonSiderealMonth,
|
|
1349
|
-
siderealYearDays: meanSiderealYearDays,
|
|
1350
|
-
dayLengthSeconds: meanLengthOfDay,
|
|
1351
|
-
massRatioEarthMoon: MASS_RATIO_EARTH_MOON,
|
|
1352
|
-
lunarSmallParameter: moonSiderealMonth / meanSiderealYearDays,
|
|
1353
|
-
moonMassFraction: 1 / (MASS_RATIO_EARTH_MOON + 1),
|
|
1354
|
-
solarTidalShiftKm: moonOrbitalShift,
|
|
1355
|
-
moonDistanceCorrectedKm: moonDistanceCorrected,
|
|
1356
|
-
gmEarthMoonSystemKm3S2: GM_EARTH_MOON_SYSTEM,
|
|
1357
|
-
gmEarthKm3S2: GM_EARTH_ALONE,
|
|
1358
|
-
gmMoonKm3S2: GM_MOON_ALONE,
|
|
1359
|
-
gmSunPlusEarthKm3S2: GM_SUN_PLUS_EARTH,
|
|
1360
|
-
gmSunKm3S2: GM_SUN,
|
|
1361
|
-
sunMassKg: M_SUN,
|
|
1362
|
-
earthMassKg: GM_EARTH_ALONE / G_CONSTANT,
|
|
1363
|
-
gravitationalConstantKm3KgS2: G_CONSTANT,
|
|
1364
|
-
}),
|
|
1365
|
-
// Plan 09: the ONE certified Sun's mean elements of date — the lunar
|
|
1366
|
-
// arguments of every runtime build their Sun from these two (the Node
|
|
1367
|
-
// scene twin and the browser read them here; the "model timeline" Sun on
|
|
1368
|
-
// the retired year combs is gone).
|
|
1369
|
-
sun: Object.freeze({
|
|
1370
|
-
/** Mean longitude of date, degrees, unwrapped — L0 + 360·∫dt/T_trop (the one-family tropical year). @param {number} year @returns {number} */
|
|
1371
|
-
meanLongitudeDegAt: sunMeanLongitudeDegAt,
|
|
1372
|
-
/** The Sun's mean perihelion longitude of date (Earth's ϖ, mean elements), degrees, wrapped to [0, 360). @param {number} year @returns {number} */
|
|
1373
|
-
perihelionLongitudeDegAt: sunPerihelionDegAt,
|
|
1374
|
-
}),
|
|
1375
|
-
epoch: Object.freeze({
|
|
1376
|
-
yearToTMa,
|
|
1377
|
-
// (plan 09 step 7b: `hAtYear` — the unit H(t) on a published surface, the
|
|
1378
|
-
// API's `epoch.h` — is deleted; the deep-time clock is axialPrecessionYearsAtYear)
|
|
1379
|
-
// The Layer-2 mean day of date — the tidal + GIA base the deep-time law
|
|
1380
|
-
// gives at any age (86,399.9997 s at J2000): the day the paleo anchors
|
|
1381
|
-
// and the ΔT integrand ride. NOT the observable solar day of date —
|
|
1382
|
-
// that is lodRealSecondsAtYear below (plan 08 storyline sweep).
|
|
1383
|
-
lodSecondsAtYear: /** @param {number} year @returns {number|null} */ (year) => deepLod.lodSecondsAtAge(yearToTMa(year)),
|
|
1384
|
-
// LOD_real of date — the Layer-4 observable (the simulator's Solar Day,
|
|
1385
|
-
// the registry's lodRealPhysical): the kinematic day + the ecliptic term
|
|
1386
|
-
// + the calibrated ΔT cycle stack. 86,400.001780 s at J2000.
|
|
1387
|
-
lodRealSecondsAtYear: /** @param {number} year @returns {number} */ (year) => lodRealSeconds(year),
|
|
1388
|
-
alphaAtYear: /** @param {number} year @returns {number} */ (year) => earthMoiFactorAtAge(yearToTMa(year)),
|
|
1389
|
-
moonDistanceKmAtYear: /** @param {number} year @returns {number} */ (year) => moonDistanceKmAtYearOrNaN(year),
|
|
1390
|
-
// D6: OF-DATE — mass-loss law / the banked planetary λ̇ ratio
|
|
1391
|
-
// (identical at J2000 where the ratio ≡ 1 by construction)
|
|
1392
|
-
siderealYearSecondsAtYear: /** @param {number} year @returns {number} */ (year) => yearLengthsM.siderealYearSecondsAtYear(year),
|
|
1393
|
-
deltaTSecondsAtYear: deltaTSeconds,
|
|
1394
|
-
// Plan 06 Phase 3 S2 — THE published of-date precession period is the
|
|
1395
|
-
// one-family route (B): the hybrid's own equinox regression against
|
|
1396
|
-
// the λ̇-corrected sidereal year (~25,771 yr at J2000 ≈ IAU), inside
|
|
1397
|
-
// the banked tiers (|Δyear| ≤ ONE_FAMILY_WINDOW_YEARS); beyond, the
|
|
1398
|
-
// composed lunisolar period on the same J2000 anchor (S5; the
|
|
1399
|
-
// of-date wobble is unresolved there). The comb family's beat (the
|
|
1400
|
-
// frozen era clock's kinematic-day device) is deleted at plan 09; the
|
|
1401
|
-
// lunar chain's (d′) rate completion (pDynDegPerYearAt) rides THIS
|
|
1402
|
-
// published period — a MATCHED TRIPLE with the eclipse gates (M0(a)
|
|
1403
|
-
// measured a 3–15 min lunar-timing shift when it moved; the records
|
|
1404
|
-
// were re-baselined on the plan 09 move).
|
|
1405
|
-
axialPrecessionYearsAtYear: publishedAxialPrecessionYearsAtYear,
|
|
1406
|
-
// The same publication rule for the mean tropical year of date (SI s):
|
|
1407
|
-
// one-family inside the window, the tidal-chain mean beyond.
|
|
1408
|
-
tropicalYearSecondsAtYear: publishedTropicalYearSecondsAtYear,
|
|
1409
|
-
}),
|
|
1410
|
-
// Plan 06 Phase 3 S3 → S5 — the lunisolar precession clock as a
|
|
1411
|
-
// first-class surface: Earth's spin clock, ONE home for its published
|
|
1412
|
-
// faces, spoken in PERIODS and their RATIOS — no unit, no integer.
|
|
1413
|
-
// ONE J2000 reading (S5): every face reads 25,771.4 yr at J2000 — the
|
|
1414
|
-
// of-date period (the published family, seamed at ±2 Myr) and the
|
|
1415
|
-
// composed mean T_p(t) (the deep-time clock, anchored on the same
|
|
1416
|
-
// derived value). The composition's terms; the apsidal period from the
|
|
1417
|
-
// engine-D chain's secular tangent; the two ratios the owner found
|
|
1418
|
-
// wandering by hand — T_aps/T_p (4.33 at J2000, 0.84 … 9.9 across
|
|
1419
|
-
// ±26 kyr) and T_peri/T_p with T_peri = 1/(1/T_p + 1/T_aps) the
|
|
1420
|
-
// perihelion-of-date period (0.812 at J2000) — on the of-date T_p.
|
|
1421
|
-
lunisolar: Object.freeze({
|
|
1422
|
-
/** The mean lunisolar precession period T_p(t), years — 1,296,000/the precession RATE of date (25,771.6 at J2000): THE published deep-time clock. @param {number} year @returns {number} */
|
|
1423
|
-
meanPeriodYearsAtYear: (year) => { const p = deepLod.lunisolarPrecessionPeriodYearsAtAge(yearToTMa(year)); return p === null ? certifiedAxialPrecessionJ2000Years() : p; },
|
|
1424
|
-
/** THE PRECESSION RATE OF DATE ψ̇(t) = [ω/ω₀]·p₀·[f_S + (1 − f_S)(a₀/a_M)³] × cos ε̄(t)/cos ε̄(0), ″/yr — the constant's scaling on the spin and the lunar torque times the cited mean obliquity's cosine (plan 12 §8 option (a); p₀ = 50.2880, the IAU 2006 input). @param {number} year @returns {number} */
|
|
1425
|
-
meanRateArcsecPerYrAtYear: (year) => { const r = deepLod.lunisolarPrecessionRateArcsecPerYrAtAge(yearToTMa(year)); return r === null ? 1296000 / certifiedAxialPrecessionJ2000Years() : r; },
|
|
1426
|
-
/** THE PRECESSION CONSTANT OF DATE as a rate on the J2000 obliquity, ″/yr — the spin and torque scaling alone (the hybrid obliquity integration's integrand: its own ŝ·n̂ carries the cosine). @param {number} year @returns {number} */
|
|
1427
|
-
torqueRateArcsecPerYrAtYear: (year) => { const r = deepLod.lunisolarTorqueRateArcsecPerYrAtAge(yearToTMa(year)); return r === null ? 1296000 / certifiedAxialPrecessionJ2000Years() : r; },
|
|
1428
|
-
/** 1,296,000/the torque rate, years. @param {number} year @returns {number} */
|
|
1429
|
-
torquePeriodYearsAtYear: (year) => { const p = deepLod.lunisolarTorquePeriodYearsAtAge(yearToTMa(year)); return p === null ? certifiedAxialPrecessionJ2000Years() : p; },
|
|
1430
|
-
/** cos ε̄(t)/cos ε̄(0) — the rate of date's obliquity factor on the constant (1 at J2000; 1.0075 at the Devonian, 1.0245 at 2.46 Ga). @param {number} year @returns {number} */
|
|
1431
|
-
precessionObliquityFactorAtYear: (year) => { const f = deepLod.precessionObliquityFactorAtAge(yearToTMa(year)); return f === null ? 1 : f; },
|
|
1432
|
-
/** THE CITED MEAN OBLIQUITY OF DATE ε̄(t), degrees — Farhat et al. 2022's own column of the Earth–Moon history (a Myr-scale MEAN: 23.25° at age 0 against the J2000 instant 23.44°; 22.23° Devonian, 19.73° at 2.46 Ga); read as the shape cos ε̄(t)/cos ε̄(0) on the precession rate. NaN beyond the input's span (4,429 Ma); forward of J2000 the J2000 slope is held. @param {number} year @returns {number} */
|
|
1433
|
-
meanObliquityCitedDegAtYear: (year) => { const e = chain.meanObliquityCitedDegAtAge(yearToTMa(year)); return e === null ? NaN : e; },
|
|
1434
|
-
/** The of-date period — the one-family beat inside ±2 Myr, the composed mean beyond. @param {number} year @returns {number} */
|
|
1435
|
-
ofDatePeriodYearsAtYear: publishedAxialPrecessionYearsAtYear,
|
|
1436
|
-
/** f_S, the solar fraction of the J2000 precession torque. */
|
|
1437
|
-
solarShareJ2000: EPOCH_PARAMS.precessionSolarShareJ2000,
|
|
1438
|
-
/** THE PRECESSION OF DATE — the solar-torque factor 1 + f_S·([(1 − e²)/(1 − e₀²)]^(−3/2) − 1) at the eccentricity of date (1 at J2000; +3.2·10⁻⁴ on the million-year mean). The spin integration multiplies it into the secular rate. @param {number} year @returns {number} */
|
|
1439
|
-
solarTorqueFactorOfDateAtYear: (year) => oneSourceM.precessionOfDateFactorsAt(year).solarTorque,
|
|
1440
|
-
/** THE PRECESSION OF DATE — J₂(t)/J₂₀, the oblateness of date from the GIA channel (ψ̇ ∝ J₂; 1 at J2000, bounded ±5·10⁻⁴; dJ₂/dt at J2000 = the observed satellite rate). @param {number} year @returns {number} */
|
|
1441
|
-
ellipticityRatioOfDateAtYear: (year) => oneSourceM.precessionOfDateFactorsAt(year).ellipticity,
|
|
1442
|
-
/** (a₀/a_M(t))³ — the lunar torque's growth on the recession history. @param {number} year @returns {number} */
|
|
1443
|
-
lunarTorqueFactorAtYear: (year) => { const f = deepLod.lunarTorqueFactorAtAge(yearToTMa(year)); return f === null ? 1 : f; },
|
|
1444
|
-
/** f_S + (1 − f_S)(a₀/a_M)³ — the torque term the unit divides H_era by. @param {number} year @returns {number} */
|
|
1445
|
-
torqueTermAtYear: (year) => { const t = deepLod.precessionTorqueTermAtAge(yearToTMa(year)); return t === null ? 1 : t; },
|
|
1446
|
-
/** The hybrid's precession constant α = p₀ / cos ε₀, ″/yr (p₀ the derived J2000 rate, ε₀ the J2000 obliquity input; 54.81). */
|
|
1447
|
-
torqueConstantJ2000ArcsecPerYr: (1296000 / certifiedAxialPrecessionJ2000Years()) / Math.cos((C.earthOrbital.obliquityJ2000_deg * Math.PI) / 180),
|
|
1448
|
-
/** |s₃|, the dominant nodal mode of Earth's orbit — the largest-amplitude ζ mode of the banked deep secular modes, ″/yr (18.85; the obliquity beat's partner). ONE home for the registry, the browser and the API. */
|
|
1449
|
-
nodalModeS3ArcsecPerYr: s3ArcsecPerYr,
|
|
1450
|
-
/** The ecliptic (nodal) precession period 1,296,000/|s₃|, years (68,751) — an orbital quantity, fixed at every epoch at the two-body level. */
|
|
1451
|
-
nodalPeriodYears: 1296000 / s3ArcsecPerYr,
|
|
1452
|
-
/** THE SPIN AXIS'S INERTIAL PRECESSION RATE OF DATE, ″/yr — the composed rate scaled by the
|
|
1453
|
-
* hybrid's self-anchor factor (the inertial-to-general ratio at J2000, the multiplicative form
|
|
1454
|
-
* the obliquity integration itself applies): 50.385 at J2000 (series-driven). The obliquity beat and the
|
|
1455
|
-
* obliquity lines ride THIS rate; the general precession (meanRateArcsecPerYrAtYear) is the
|
|
1456
|
-
* equinox along the ecliptic of date. @param {number} year @returns {number} */
|
|
1457
|
-
spinAxisInertialRateArcsecPerYrAtYear: (year) => {
|
|
1458
|
-
const r = deepLod.lunisolarPrecessionRateArcsecPerYrAtAge(yearToTMa(year));
|
|
1459
|
-
const psiDot = r === null ? 1296000 / certifiedAxialPrecessionJ2000Years() : r;
|
|
1460
|
-
return psiDot * (certifiedAxialPrecessionJ2000Years() / oneSourceM.axialPrecessionYearsLunisolarJ2000);
|
|
1461
|
-
},
|
|
1462
|
-
/** The obliquity beat 2π/(ψ̇ᵢₙ(t) − |s₃|), years — the SHIPPED deep-time obliquity period at an INSTANT
|
|
1463
|
-
* (falsification leg 1; 41,098 at J2000). ψ̇ᵢₙ is the spin axis's INERTIAL rate (above): the equator
|
|
1464
|
-
* against the ecliptic's nodal mode in the inertial frame, the rate the hybrid obliquity integration
|
|
1465
|
-
* self-anchors on — not the general precession, which reads the beat 0.3 % long (41,224). v23.0: a
|
|
1466
|
-
* dated record sees the beat of the pole rate's mean over its own window, with the pole's of-date
|
|
1467
|
-
* factors (obliquityPeriodRealizedYears below: 40,927 over the LR04 record, the climate formula's p+s₀
|
|
1468
|
-
* line; La2004's own series reads 40,900 on the same window — compare realized with realized, never
|
|
1469
|
-
* this instant with Laskar's long-window precession frequency 50.476). @param {number} year @returns {number} */
|
|
1470
|
-
obliquityBeatYearsAtYear: (year) => {
|
|
1471
|
-
const r = deepLod.lunisolarPrecessionRateArcsecPerYrAtAge(yearToTMa(year));
|
|
1472
|
-
const psiDot = r === null ? 1296000 / certifiedAxialPrecessionJ2000Years() : r;
|
|
1473
|
-
const psiDotInertial = psiDot * (certifiedAxialPrecessionJ2000Years() / oneSourceM.axialPrecessionYearsLunisolarJ2000);
|
|
1474
|
-
return 1296000 / (psiDotInertial - s3ArcsecPerYr);
|
|
1475
|
-
},
|
|
1476
|
-
/** THE REALIZED POLE RATE OVER A WINDOW, ″/yr — see the one home above (the mean of the inertial rate of
|
|
1477
|
-
* date with its three of-date factors); the rate the obliquity lines of a record spanning the window carry. */
|
|
1478
|
-
spinAxisInertialRateMeanArcsecPerYr,
|
|
1479
|
-
/** THE REALIZED OBLIQUITY PERIOD OVER A WINDOW, years — 1,296,000/(⟨ψ̇ᵢₙ⟩_window − |s₃|): the period a record
|
|
1480
|
-
* spanning [yearFrom, yearTo] sees (40,930 over the LR04 record 0–5.32 Ma, 41,018 over the last Myr); the
|
|
1481
|
-
* J2000 beat (obliquityBeatYearsAtYear) is its instantaneous limit.
|
|
1482
|
-
* @param {number} yearFrom @param {number} yearTo @returns {number} */
|
|
1483
|
-
obliquityPeriodRealizedYears: (yearFrom, yearTo) => 1296000 / (spinAxisInertialRateMeanArcsecPerYr(yearFrom, yearTo) - s3ArcsecPerYr),
|
|
1484
|
-
/** The apsidal (perihelion vs the stars) period of date, JULIAN years — the ONE movement's own apsidal rate (the scene's perihelion; anom/(anom − sid) of the one family, ≡ 360°/apsidalRateFixedArcsecPerJulianYr), inside the published window only; null beyond. Before 2026-09 this rode the planet chain's secular tangent, which parted from the scene's perihelion passages by seconds of anomalistic year within a few millennia (year-lengths.cjs). @param {number} year @returns {number|null} */
|
|
1485
|
-
apsidalPeriodYearsAtYear: (year) => (Math.abs(year - 2000) <= ONE_FAMILY_WINDOW_YEARS ? yearLengthsM.inclinationPrecessionYearsAtYear(year) : null),
|
|
1486
|
-
/** T_aps(t) / T_p(t) — the apsidal period in of-date precession periods (4.33 at J2000, a reading; 0.84 … 9.9 across ±26 kyr, measured); null beyond the published window. @param {number} year @returns {number|null} */
|
|
1487
|
-
apsidalPerPrecessionAtYear: (year) => {
|
|
1488
|
-
if (Math.abs(year - 2000) > ONE_FAMILY_WINDOW_YEARS) return null;
|
|
1489
|
-
return yearLengthsM.inclinationPrecessionYearsAtYear(year) / publishedAxialPrecessionYearsAtYear(year);
|
|
1490
|
-
},
|
|
1491
|
-
/** T_peri(t) = 1/(1/T_p + 1/T_aps) — the perihelion-of-date period (equinox precession + inertial perihelion motion, frame arithmetic at every epoch), JULIAN years, on the of-date T_p — ≡ the one family's anom/(anom − trop); null beyond the published window. @param {number} year @returns {number|null} */
|
|
1492
|
-
periOfDatePeriodYearsAtYear: (year) => {
|
|
1493
|
-
if (Math.abs(year - 2000) > ONE_FAMILY_WINDOW_YEARS) return null;
|
|
1494
|
-
const tp = publishedAxialPrecessionYearsAtYear(year), taps = yearLengthsM.inclinationPrecessionYearsAtYear(year);
|
|
1495
|
-
return 1 / (1 / tp + 1 / taps);
|
|
1496
|
-
},
|
|
1497
|
-
/** T_peri(t) / T_p(t) (0.812 at J2000 — the J2000 reading); null beyond the published window. @param {number} year @returns {number|null} */
|
|
1498
|
-
periOfDatePerPrecessionAtYear: (year) => {
|
|
1499
|
-
if (Math.abs(year - 2000) > ONE_FAMILY_WINDOW_YEARS) return null;
|
|
1500
|
-
const tp = publishedAxialPrecessionYearsAtYear(year), taps = yearLengthsM.inclinationPrecessionYearsAtYear(year);
|
|
1501
|
-
return (1 / (1 / tp + 1 / taps)) / tp;
|
|
1502
|
-
},
|
|
1503
|
-
/** The published of-date window, years from 2000. */
|
|
1504
|
-
publishedWindowYears: ONE_FAMILY_WINDOW_YEARS,
|
|
1505
|
-
/** THE SPIN AXIS'S INERTIAL PRECESSION PERIOD at J2000, years (25,722 in the shipped,
|
|
1506
|
-
* series-driven configuration) — the rate the hybrid obliquity integration self-anchors
|
|
1507
|
-
* ŝ on (earth/deep-orbital-history, D4e): the general-precession anchor p₀ PLUS the
|
|
1508
|
-
* planetary mean the N-body ecliptic's own motion carries (+0.097 ″/yr ≡ IAU's planetary
|
|
1509
|
-
* precession ψ_A − p_A; the bare 18-mode table anchors 0.18 — the g₂-gap trap: pass the
|
|
1510
|
-
* secular series). Two rates, two uses — the obliquity line frequencies p + s_i (the
|
|
1511
|
-
* spin axis against the ecliptic's nodal modes, in the inertial frame) carry THIS
|
|
1512
|
-
* rate; the climatic-precession lines p + g_i (the perihelion from the equinox along
|
|
1513
|
-
* the ecliptic of date) carry p₀. */
|
|
1514
|
-
spinAxisInertialPeriodYearsJ2000: oneSourceM.axialPrecessionYearsLunisolarJ2000,
|
|
1515
|
-
/** The same as a rate, ″/yr (50.385 at J2000 with the series; p₀ = 50.288 is the general precession). */
|
|
1516
|
-
spinAxisInertialRateArcsecPerYrJ2000: 1296000 / oneSourceM.axialPrecessionYearsLunisolarJ2000,
|
|
1517
|
-
}),
|
|
1518
|
-
earth: Object.freeze({
|
|
1519
|
-
perihelionLongitudeDeg: earthPerihelionDeg,
|
|
1520
|
-
// Plan 06 Phase 3 S3b: THE published obliquity is the hybrid — one
|
|
1521
|
-
// torque law integrated on the dynamical orbit plane of the N-body
|
|
1522
|
-
// chain, zero fitted constants (≡ La2004 to ≤ 4″ over ±50 kyr). The
|
|
1523
|
-
// fitted 16-harmonic K comb that sat beside it as `obliquityCombDeg`
|
|
1524
|
-
// (a device fitted to the scene's own wheel geometry, 1.27° off
|
|
1525
|
-
// La2004 at −20 kyr) is deleted with the frozen era device (plan 09).
|
|
1526
|
-
// Beyond the ζ series' span (±10 Myr) the hybrid carries NO tidal evolution
|
|
1527
|
-
// of the mean obliquity (nothing in ds/dt = α(ŝ·n̂)(ŝ×n̂) moves ŝ·n̂'s mean):
|
|
1528
|
-
// its deep mean is the Quaternary mean on the tail's mean plane (plan 12
|
|
1529
|
-
// §8.3). The cited mean obliquity of date is `meanObliquityCitedDeg`.
|
|
1530
|
-
obliquityDeg: /** @param {number} year @returns {number} */ (year) => oneSourceM.epsAt(year),
|
|
1531
|
-
/** The hybrid's own domain, [yearFrom, yearTo] — the banked ζ series' span, ±10 Myr about J2000 (plan 12 §8.5: the published surfaces serve `obliquityDeg` inside it only; null without a series, i.e. a bare createModel()). */
|
|
1532
|
-
obliquityHybridDomainYears: oneSourceM.obliquityHybridDomainYears,
|
|
1533
|
-
/** The cited mean obliquity of date ε̄(t) (Farhat et al. 2022's column; plan 12 §8 option (a)), degrees — a Myr-scale mean; NaN beyond 4,429 Ma. @param {number} year @returns {number} */
|
|
1534
|
-
meanObliquityCitedDeg: /** @param {number} year @returns {number} */ (year) => { const e = chain.meanObliquityCitedDegAtAge(yearToTMa(year)); return e === null ? NaN : e; },
|
|
1535
|
-
eccentricity: eccentricityAt,
|
|
1536
|
-
inclinationDeg,
|
|
1537
|
-
ascendingNodeDeg,
|
|
1538
|
-
}),
|
|
1539
|
-
// The DEVICE family (plan 06 Phase 3 S2): the frozen era clock's comb
|
|
1540
|
-
// year lengths (A), its cardinal 4-mean (A′) and the kinematic-day stack
|
|
1541
|
-
// built on them (the ΔT stack's Layer 3/4 basis, USNO-anchored). NOT the
|
|
1542
|
-
// published year lengths — those are `yearLengths` (the one-family
|
|
1543
|
-
// route) and the seamed `epoch.*AtYear` surfaces above.
|
|
1544
|
-
lengths: Object.freeze({
|
|
1545
|
-
tropicalYearDays,
|
|
1546
|
-
siderealYearDays,
|
|
1547
|
-
anomalisticYearDays,
|
|
1548
|
-
dayLengthSeconds,
|
|
1549
|
-
lodRealSeconds,
|
|
1550
|
-
siderealDaySeconds,
|
|
1551
|
-
stellarDaySeconds,
|
|
1552
|
-
}),
|
|
1553
|
-
// Plan 06 R1: the instants are the crossings of the ONE Sun (the
|
|
1554
|
-
// certified completed Sun the scene renders), UT model-JD; the RA at a
|
|
1555
|
-
// crossing is the target longitude by construction (λ = 0/90/180/270 ⇒
|
|
1556
|
-
// RA = 0/90/180/270, any obliquity); the per-type year length is the
|
|
1557
|
-
// interval between successive crossings (SI days).
|
|
1558
|
-
cardinal: Object.freeze({
|
|
1559
|
-
jd: /** @param {number} year @param {string} type @returns {number} */ (year, type) => cardinalCrossingJdUT(year, type),
|
|
1560
|
-
// R4c: the crossing nearest a UT instant (a JD seed — for callers whose
|
|
1561
|
-
// year coordinate is not the model year, e.g. a calendar year's midpoint).
|
|
1562
|
-
jdNearUT: /** @param {number} jdUT @param {string} type @returns {number} */ (jdUT, type) => cardinalCrossingNearJdUT(jdUT, type),
|
|
1563
|
-
raDeg: /** @param {number} year @param {string} type @returns {number} */ (year, type) => { void year; return cardinalTargetDeg(type); },
|
|
1564
|
-
yearLengthDays: /** @param {number} year @param {string} type @returns {number} */ (year, type) => cardinalCrossingJdUT(year + 1, type) - cardinalCrossingJdUT(year, type),
|
|
1565
|
-
}),
|
|
1566
|
-
// D4b: the one-source cardinal STRUCTURE — the EoC layer on the
|
|
1567
|
-
// movement's own e(t)/ϖ(t), valid at every epoch (mode tier). Absolute
|
|
1568
|
-
// dates deliberately absent; `cardinal` above stays the certified era
|
|
1569
|
-
// device for those.
|
|
1570
|
-
cardinalStructure: Object.freeze({
|
|
1571
|
-
// D6: year LENGTHS gain the λ̇ drift coherently (rate-form
|
|
1572
|
-
// correction — beats stay invariant); offsets/spreads keep the raw
|
|
1573
|
-
// form (μs-class / second-order there).
|
|
1574
|
-
yearLengthSeconds: /** @param {number} year @param {'VE'|'SS'|'AE'|'WS'} type @returns {number} */ (year, type) => yearLengthsM.cardinal.yearLengthSeconds(year, type),
|
|
1575
|
-
eocOffsetSeconds: /** @param {number} year @param {'VE'|'SS'|'AE'|'WS'} type @returns {number} */ (year, type) => yearLengthsM.cardinal.eocOffsetSeconds(year, type),
|
|
1576
|
-
spreadSeconds: /** @param {number} year */ (year) => yearLengthsM.cardinal.spreadSeconds(year),
|
|
1577
|
-
anomalisticYearSeconds: /** @param {number} year @returns {number} */ (year) => yearLengthsM.anomalisticYearSecondsAtYear(year),
|
|
1578
|
-
}),
|
|
1579
|
-
// THE ONE of-date year-length family + its beats (S2; SI seconds) —
|
|
1580
|
-
// the single surface the panel, charts, API and website consume.
|
|
1581
|
-
yearLengths: yearLengthsM,
|
|
1582
|
-
moon: Object.freeze({
|
|
1583
|
-
distanceKmAtYear: /** @param {number} year @returns {number} */ (year) => moonDistanceKmAtYearOrNaN(year),
|
|
1584
|
-
siderealMonthDaysAtYear: moonSiderealMonthDaysAt,
|
|
1585
|
-
synodicMonthDays: moonSynodicMonthDays,
|
|
1586
|
-
// The apparent-position chain (truncated Meeus Ch. 47 series on
|
|
1587
|
-
// framework-native arguments). JD(UT) axis — UT→TT applied internally.
|
|
1588
|
-
lonDegAtJD: /** @param {number} jd @returns {number} */ (jd) => moonSeries.truncatedLonDeg(jd),
|
|
1589
|
-
betaDegAtJD: /** @param {number} jd @returns {number} */ (jd) => moonSeries.truncatedBetaDeg(jd),
|
|
1590
|
-
distanceKmAtJD: /** @param {number} jd @returns {number} */ (jd) => moonSeries.truncatedDistanceKm(jd),
|
|
1591
|
-
}),
|
|
1592
|
-
eclipse: Object.freeze({
|
|
1593
|
-
sunLonDegAtJD: /** @param {number} jd @returns {number} */ (jd) => eclipseFinders.sunLonDegAt(jd),
|
|
1594
|
-
// The COMPLETED tier Sun (K8b follow-up, owner-approved injection):
|
|
1595
|
-
// the bare finder Sun minus the DERIVED planetary-completion table —
|
|
1596
|
-
// 70 framework-carrier terms plus the 6.44″ Earth-around-EMB wobble
|
|
1597
|
-
// (the "lunar equation"; eclipse/sun-planetary-completion.cjs, zero
|
|
1598
|
-
// fitted constants). The finders themselves deliberately stay bare
|
|
1599
|
-
// (their certified canon statistics were produced on the bare form;
|
|
1600
|
-
// besselian.cjs applies the same subtraction internally). This
|
|
1601
|
-
// surface exists for the SCENE tier's E5 wheel-Sun bridge, so the
|
|
1602
|
-
// rendered Sun carries the model's own derived apparent-class terms.
|
|
1603
|
-
// Clock: the completion argument rides TT centuries from the same
|
|
1604
|
-
// framework ΔT the besselian composition uses.
|
|
1605
|
-
sunLonCompletedDegAtJD: /** @param {number} jd @returns {number} */ (jd) =>
|
|
1606
|
-
eclipseFinders.sunLonDegAt(jd)
|
|
1607
|
-
- sunPlanetaryCompletionDeg((jdTTFromUT(jd) - j2000JD) / julianCenturyDays),
|
|
1608
|
-
/** The APPARENT Sun (completed geometric − the derived aberration constant + the leading nutation terms on the model's own arguments) — the quantity Horizons' observer ecliptic longitude is; the cardinal instants are its crossings (plan 06 R1/I1). @param {number} jdUT @returns {number} */
|
|
1609
|
-
sunApparentLonDegAtJD: /** @param {number} jdUT @returns {number} */ (jdUT) => sunApparentLonDegAtJdUT(jdUT),
|
|
1610
|
-
findLunarInRange: /** @param {number} jdStart @param {number} jdEnd */ (jdStart, jdEnd) => eclipseFinders.findLunarEclipsesInRange(jdStart, jdEnd),
|
|
1611
|
-
findSolarInRange: /** @param {number} jdStart @param {number} jdEnd */ (jdStart, jdEnd) => eclipseFinders.findSolarEclipsesInRange(jdStart, jdEnd),
|
|
1612
|
-
deltaTSecondsAtJD: frameworkDeltaTSecondsAtJD,
|
|
1613
|
-
// E4 — the framework-native Sun deps, exported so the OTHER finder
|
|
1614
|
-
// construction sites (tools/verify/eclipse-audit.js, the browser
|
|
1615
|
-
// _eclipse twins) spread the SAME assembly into their own
|
|
1616
|
-
// createEclipseFinders call instead of triplicating it (the
|
|
1617
|
-
// three-runtimes rule — cf. moon-distance-history):
|
|
1618
|
-
frameworkSunDeps: Object.freeze({
|
|
1619
|
-
sunMeanLongitudeJ2000Deg: sunL0Deg,
|
|
1620
|
-
tropicalRateDegPerCy: sunTropicalRateDegPerCy,
|
|
1621
|
-
eccentricityAt: sunEccentricityAt,
|
|
1622
|
-
perihelionLongitudeDegAt: sunPerihelionDegAt,
|
|
1623
|
-
meanLongitudeDegAt: sunMeanLongitudeDegAt,
|
|
1624
|
-
}),
|
|
1625
|
-
// 20.3g location tier (see eclipse/besselian.cjs):
|
|
1626
|
-
umbraGroundAtJD: /** @param {number} jd @returns {{latDeg: number, lonDeg: number} | null} */ (jd) => besselian.umbraGroundAt(jd),
|
|
1627
|
-
solarLocalCircumstances: /** @param {number} jdGreatest @param {number} latDeg @param {number} lonDeg */ (jdGreatest, latDeg, lonDeg) => besselian.localCircumstances(jdGreatest, latDeg, lonDeg),
|
|
1628
|
-
}),
|
|
1629
|
-
climate: Object.freeze({
|
|
1630
|
-
l1OrbitalPermil: evalClimateL1,
|
|
1631
|
-
}),
|
|
1632
|
-
planets: Object.freeze({
|
|
1633
|
-
keys: Object.freeze([...PLANET_KEYS]),
|
|
1634
|
-
record: /** @param {string} k @returns {Record<string, any>|undefined} */ (k) => PUBLISHED_PLANET_RECORDS[k],
|
|
1635
|
-
perihelionLongitudeDeg: planetPerihelionDeg,
|
|
1636
|
-
ascendingNodeInvPlaneDeg: planetAscNodeDeg,
|
|
1637
|
-
invPlaneInclinationDeg: planetInclinationDeg,
|
|
1638
|
-
eccentricity: planetEccentricity,
|
|
1639
|
-
spin: planetSpin,
|
|
1640
|
-
}),
|
|
1641
|
-
});
|
|
64
|
+
/** The forward bindings (model/context.js) — each filled the moment its owning slice returns. */
|
|
65
|
+
const late = /** @type {import('./model/context.js').LateBindings} */ ({});
|
|
66
|
+
/** @type {import('./model/context.js').ModelInputs} */
|
|
67
|
+
const inputs = { C, F, laws, secularSeriesArtifact, options, late };
|
|
68
|
+
const c1 = Object.assign(inputs, assembleDerivedConstants(inputs));
|
|
69
|
+
const c2 = Object.assign(c1, assembleDeepTimeChain(c1));
|
|
70
|
+
const c3 = Object.assign(c2, assembleEarthScalars(c2));
|
|
71
|
+
const c4 = Object.assign(c3, assembleYearDayLengths(c3));
|
|
72
|
+
late.certifiedAxialPrecessionJ2000Years = c4.certifiedAxialPrecessionJ2000Years;
|
|
73
|
+
const c5 = Object.assign(c4, assembleOneSourceMovement(c4));
|
|
74
|
+
late.oneSourceM = c5.oneSourceM;
|
|
75
|
+
late.yearLengthsM = c5.yearLengthsM;
|
|
76
|
+
const c6 = Object.assign(c5, assembleMoonEpoch(c5));
|
|
77
|
+
const c7 = Object.assign(c6, assembleDeltaT(c6));
|
|
78
|
+
const c8 = Object.assign(c7, assemblePlanetRecords(c7));
|
|
79
|
+
const c9 = Object.assign(c8, assemblePlanetSpinChannel(c8));
|
|
80
|
+
const c10 = Object.assign(c9, assemblePlanetElementsOfDate(c9));
|
|
81
|
+
const c11 = Object.assign(c10, assembleInvPlaneElements(c10));
|
|
82
|
+
const c12 = Object.assign(c11, assembleTimeAxis(c11));
|
|
83
|
+
const c13 = Object.assign(c12, assembleLunarTheory(c12));
|
|
84
|
+
const c14 = Object.assign(c13, assembleSunAndEclipses(c13));
|
|
85
|
+
late.sunMeanLongitudeDegAt = c14.sunMeanLongitudeDegAt;
|
|
86
|
+
const c15 = Object.assign(c14, assemblePublishedPeriods(c14));
|
|
87
|
+
late.publishedAxialPrecessionYearsAtYear = c15.publishedAxialPrecessionYearsAtYear;
|
|
88
|
+
late.publishedSiderealYearSecondsAtYear = c15.publishedSiderealYearSecondsAtYear;
|
|
89
|
+
const c16 = Object.assign(c15, assembleCardinalInstants(c15));
|
|
90
|
+
late.sunAberrationArcsecAt = c16.sunAberrationArcsecAt;
|
|
91
|
+
return assembleSurface(c16);
|
|
1642
92
|
}
|