@essrt/physics 23.3.3 → 24.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +4 -1
  2. package/package.json +2 -2
  3. package/src/cardinal/one-source-structure.cjs +3 -1
  4. package/src/constants/coefficients.d.ts +5 -1
  5. package/src/constants/coefficients.js +3 -2
  6. package/src/constants/generated.d.ts +13 -14
  7. package/src/constants/generated.js +14 -15
  8. package/src/constants/units.cjs +4 -1
  9. package/src/deltat/deep-time.cjs +37 -72
  10. package/src/earth/deep-orbital-history.cjs +48 -34
  11. package/src/earth/year-lengths.cjs +2 -1
  12. package/src/eclipse/besselian.cjs +24 -11
  13. package/src/index.js +30 -48
  14. package/src/model/cardinal-instants.js +101 -0
  15. package/src/model/context.js +54 -0
  16. package/src/model/deep-time-chain.js +79 -0
  17. package/src/model/delta-t.js +38 -0
  18. package/src/model/derived-constants.js +58 -0
  19. package/src/model/earth-scalars.js +47 -0
  20. package/src/model/inv-plane-elements.js +56 -0
  21. package/src/model/lunar-theory.js +216 -0
  22. package/src/model/moon-epoch.js +28 -0
  23. package/src/model/one-source-movement.js +192 -0
  24. package/src/model/planet-elements-of-date.js +61 -0
  25. package/src/model/planet-records.js +63 -0
  26. package/src/model/planet-spin-channel.js +41 -0
  27. package/src/model/published-periods.js +38 -0
  28. package/src/model/sun-and-eclipses.js +199 -0
  29. package/src/model/surface.js +332 -0
  30. package/src/model/time-axis.js +24 -0
  31. package/src/model/year-day-lengths.js +42 -0
  32. package/src/model.js +62 -1612
  33. package/src/moon/arguments.cjs +27 -43
  34. package/src/planets/chain-artifact.js +2 -2
  35. package/src/planets/keplerian-chain.cjs +3 -3
  36. package/src/planets/model.cjs +2 -2
  37. package/types/constants/coefficients.d.ts +5 -1
  38. package/types/constants/generated.d.ts +13 -14
  39. package/types/constants/units.d.cts +3 -0
  40. package/types/deltat/deep-time.d.cts +18 -24
  41. package/types/earth/deep-orbital-history.d.cts +23 -0
  42. package/types/eclipse/besselian.d.cts +37 -18
  43. package/types/index.d.ts +1 -1
  44. package/types/model/cardinal-instants.d.ts +14 -0
  45. package/types/model/context.d.ts +87 -0
  46. package/types/model/deep-time-chain.d.ts +288 -0
  47. package/types/model/delta-t.d.ts +11 -0
  48. package/types/model/derived-constants.d.ts +25 -0
  49. package/types/model/earth-scalars.d.ts +14 -0
  50. package/types/model/inv-plane-elements.d.ts +6 -0
  51. package/types/model/lunar-theory.d.ts +72 -0
  52. package/types/model/moon-epoch.d.ts +10 -0
  53. package/types/model/one-source-movement.d.ts +74 -0
  54. package/types/model/planet-elements-of-date.d.ts +9 -0
  55. package/types/model/planet-records.d.ts +7 -0
  56. package/types/model/planet-spin-channel.d.ts +29 -0
  57. package/types/model/published-periods.d.ts +7 -0
  58. package/types/model/sun-and-eclipses.d.ts +53 -0
  59. package/types/model/surface.d.ts +281 -0
  60. package/types/model/time-axis.d.ts +12 -0
  61. package/types/model/year-day-lengths.d.ts +8 -0
  62. package/types/model.d.ts +10 -81
  63. package/types/moon/arguments.d.cts +5 -11
  64. package/types/planets/keplerian-chain.d.cts +4 -2
  65. package/types/planets/model.d.cts +3 -3
@@ -1,11 +1,10 @@
1
1
  /**
2
2
  * Deep-time LOD / ΔT core — THE shared implementation (Phase 8.4, slice 3).
3
3
  *
4
- * The angular-momentum-conservation LOD (Layer 1/2), the H(t) identity, the
5
- * mass-loss year chain, the Simpson ΔT integrator with the H/5 ecliptic
6
- * "missing motion" integrand, the corrected-LOD composite, the Actual-LOD
7
- * Fourier ripple, and the dLOD/dt driver decomposition (tidal / GIA /
8
- * stack / resonator channels).
4
+ * The angular-momentum-conservation LOD (Layer 1/2), the composed precession
5
+ * rate, the mass-loss year chain, the Simpson ΔT integrator with the ecliptic
6
+ * "missing motion" integrand, the corrected-LOD composite, and the dLOD/dt
7
+ * driver decomposition (tidal / GIA / stack / resonator channels).
9
8
  *
10
9
  * INJECTED, by design:
11
10
  * - moonDistanceMetresAtAge — the 8.2 moon month-chain (each engine's own
@@ -44,11 +43,11 @@ const { createComposedPrecession } = require('../earth/precession-composed.cjs')
44
43
  * @property {number} aLockMetres - tidal-lock distance (LOD denominator → 0)
45
44
  * @property {number} aMoonNowMetres - Farhat polynomial anchor
46
45
  * @property {number} alpha1PerMa - the LLR recession rate (the J2000 slope of the cited history)
47
- * @property {number} lodNowH13Seconds - ω₀, the J2000 day length (the SI day since plan 09; identifier kept)
46
+ * @property {number} lodNowH13Seconds - ω₀, the J2000 day length (the SI day; identifier kept)
48
47
  * @property {number} meanSiderealYearJ2000Seconds
49
48
  * @property {number} solarMassLossFracPerYear
50
49
  * @property {number} precessionSolarShareJ2000 - f_S, the solar fraction of the J2000
51
- * precession torque (derive-params) — the unit H(t) = 13·T_p,composed needs it
50
+ * precession torque (derive-params) — the composed precession rate needs it
52
51
  */
53
52
 
54
53
  /**
@@ -59,23 +58,20 @@ const { createComposedPrecession } = require('../earth/precession-composed.cjs')
59
58
  * @property {(year: number) => number} cycleLodSumAt - gated δLOD sum (incl. swing)
60
59
  * @property {(year: number) => number} swingLodAt - gated swing δLOD alone
61
60
  * @property {(year: number) => number} swingLodRateAt - gated analytic swing rate
62
- * @property {() => number} precessionPeriodJ2000YearsFn - the model's DERIVED
63
- * J2000 axial precession period: the certified year-length laws' beat at
64
- * 2000, sid/(sid − trop) ≈ 25,771.4 yr (plan 06 S5 — one J2000 precession
65
- * reading; the same anchor the hybrid obliquity self-anchors on). Read
61
+ * @property {() => number} precessionPeriodJ2000YearsFn - the model's J2000 axial
62
+ * precession period, 1,296,000/p_A = 25,771.575 yr (the IAU 2006 general
63
+ * precession; the same anchor the hybrid obliquity self-anchors on). Read
66
64
  * LAZILY on the first composed-rate use, never at construction: every
67
65
  * runtime's year laws read THIS factory's bases.
68
66
  * @property {() => number} nodalPeriodYearsFn - the period of Earth's orbit
69
67
  * plane's nodal regression on the invariable plane, 1,296,000/|s₃| with s₃
70
68
  * the dominant ζ mode of the banked deep secular modes (≈ 68,751 yr). An
71
69
  * ORBITAL quantity (μ-tier: it does not follow Earth's spin), the reference
72
- * the solar day's "ecliptic missing motion" term rides (plan 06 T2 item —
73
- * formerly the spin unit's H/5, 67,063 yr, 2.5 % off and scaling with the
74
- * spin at deep time). Lazy, like the precession anchor.
70
+ * the solar day's "ecliptic missing motion" term rides. Lazy, like the
71
+ * precession anchor.
75
72
  * @property {(tMa: number) => number} [lEmAtAgeKgm2S] - OPTIONAL time-dependent
76
73
  * Earth-Moon angular momentum. Absent → the J2000 constant: conservation
77
- * (plan 12 option A — the Driver-1½ solar-channel budget is deleted;
78
- * measured: conservation on the cited history reproduces Farhat's own LOD
74
+ * (measured: conservation on the cited history reproduces Farhat's own LOD
79
75
  * to 0.01 h at 100 Ma, 0.14 h at 2.46 Ga).
80
76
  * @property {(tMa: number) => number|null} [moonDistanceSlopeMetresPerMaAtAge] -
81
77
  * OPTIONAL analytic slope of the distance history (metres per Ma, positive
@@ -84,7 +80,7 @@ const { createComposedPrecession } = require('../earth/precession-composed.cjs')
84
80
  * @property {(tMa: number) => number|null} [meanObliquityCosRatioAtAge] -
85
81
  * OPTIONAL cos ε̄(t)/cos ε̄(0) of the cited mean obliquity (earth/mean-
86
82
  * obliquity-history) — the factor the precession RATE of date carries on the
87
- * constant (plan 12 §8 option (a)); absent → 1, the constant alone, bit-identical.
83
+ * constant; absent → 1, the constant alone, bit-identical.
88
84
  */
89
85
 
90
86
  /** @param {DeepTimeLodDeps} deps */
@@ -117,26 +113,12 @@ function createDeepTimeLod(deps) {
117
113
  return (s === null) ? null : s / 3600;
118
114
  }
119
115
 
120
- // (Plan 09 step 7a deleted the FROZEN ERA CLOCK's public counter
121
- // `eraClockHAtAge` — H_era(t) = H₀·LOD(t)/LOD₀, plan 06 D8's second named
122
- // counter — with its year twins; step 7b deleted the unit itself, `hAtAge`
123
- // = H_era/[f_S + (1 − f_S)(a₀/a_M)³] — H(t) was 13.011 composed precession
124
- // periods, a fit constant's multiple of T_p(t), never a period of anything
125
- // the model computes. The physics it scaled is the composed precession
126
- // below: ψ̇(t) and T_p(t) = 1,296,000/ψ̇ are the published quantities.)
127
- // The `…FromLod` twins take an ALREADY-COMPUTED LOD(t): the Simpson ΔT
128
- // integrand below evaluated the LOD four times and the tropical year twice
129
- // per node through these helpers (measured 8.8 → 4.8 ms per cardinal panel
130
- // year with the model's ΔT memo). Same operations, same inputs — every
131
- // value bit-identical (11,958-value sweep, 0 differences).
132
-
133
- // The composed lunisolar precession (plan 06 D6 → Phase 3 → S5; plan 12 §8):
134
- // the CONSTANT's scaling [ω(t)/ω₀]·p₀·[f_S + (1 − f_S)(a₀/a_M(t))³] and the
135
- // RATE of date, that × cos ε̄(t)/cos ε̄(0) on the cited mean obliquity; p₀ the
136
- // model's J2000 rate 1,296,000/axial0 (the IAU 2006 general precession since
137
- // plan 09). ONE formula home: earth/precession-composed, built here on this
138
- // factory's own LOD, recession and obliquity histories; the anchor resolves
139
- // lazily on the first rate use.
116
+ // The composed lunisolar precession: the CONSTANT's scaling
117
+ // [ω(t)/ω₀]·p₀·[f_S + (1 − f_S)(a₀/a_M(t))³] and the RATE of date, that ×
118
+ // cos ε̄(t)/cos ε̄(0) on the cited mean obliquity; p₀ the model's J2000 rate
119
+ // 1,296,000/axial0 (the IAU 2006 general precession). ONE formula home:
120
+ // earth/precession-composed, built here on this factory's own LOD, recession
121
+ // and obliquity histories; the anchor resolves lazily on the first rate use.
140
122
  const composed = createComposedPrecession({
141
123
  p0ArcsecPerYr: () => 1296000 / deps.precessionPeriodJ2000YearsFn(),
142
124
  solarShare: K.precessionSolarShareJ2000,
@@ -148,11 +130,10 @@ function createDeepTimeLod(deps) {
148
130
  meanObliquityCosRatioAtAge: deps.meanObliquityCosRatioAtAge,
149
131
  });
150
132
 
151
-
152
133
  /** THE PRECESSION RATE OF DATE ψ̇(t), ″/yr — the constant's scaling
153
134
  * p₀·[ω/ω₀]·[f_S + (1 − f_S)(a₀/a_M)³] × cos ε̄(t)/cos ε̄(0), ε̄ the cited mean
154
- * obliquity (plan 12 §8 option (a); the chain held cos ε̄ at J2000 before —
155
- * 2.5 % of rate at 2.46 Ga, 2e-7 at 10 kyr). p₀ the J2000 anchor (S5).
135
+ * obliquity (its factor is 2.5 % of the rate at 2.46 Ga, 2e-7 at 10 kyr);
136
+ * p₀ the J2000 anchor.
156
137
  * @param {number} t_Ma @returns {number|null} */
157
138
  function lunisolarPrecessionRateArcsecPerYrAtAge(t_Ma) {
158
139
  return composed.composedRateArcsecPerYrAtAge(t_Ma);
@@ -192,23 +173,18 @@ function createDeepTimeLod(deps) {
192
173
  // a(t) = a₀·(1−Δm)): T ∝ M⁻² ⇒ T(t) = T₀·(1−Δm)² — the SAME Driver-2
193
174
  // law the planet chains use (orbit-chain driver2PeriodSecondsAtAge).
194
175
  // The previous (1 − 2Δm) was this law's first-order Taylor — the one
195
- // form in the model inconsistent with it (measured on the retired day-count
196
- // identity of the era counter: with the product form the counter's
197
- // H_era·(days/yr)·(AU₀/AU)² held exactly — a tautology of spin scaling ∘
198
- // Kepler, deleted with the counter and the unit at plan 09 steps 7a/7b).
176
+ // form in the model inconsistent with it.
199
177
  return K.meanSiderealYearJ2000Seconds * (1 - mass_loss_fraction) * (1 - mass_loss_fraction);
200
178
  }
201
179
 
202
180
  /** Tropical year of date, seconds — the sidereal year less the equinox's
203
181
  * own motion over one year: one turn per the composed lunisolar precession
204
182
  * period T_p(t), 1/T_trop = 1/T_sid + ψ̇(t)/(1,296,000″ · Julian-year s),
205
- * ψ̇(t) the RATE of date (with the cited mean obliquity's cosine, plan 12 §8).
206
- * Plan 09 step 5d: it was the unit's calendar convention sid·(1 − 13/H(t))
207
- * — plan 06 D2 had kept it as a named device — 0.086 % slow on the equinox
208
- * term (1.0 s of year at J2000), and the deep JD↔year calendar integrates
209
- * THIS. The SAME operations as layer0's tropicalYearSecondsCore (the
210
- * layer0 gate holds the twins bit-identical). Past the tidal chain's domain
211
- * the J2000 rate stands in. @param {number} t_Ma @returns {number} */
183
+ * ψ̇(t) the RATE of date (with the cited mean obliquity's cosine). The deep
184
+ * JD↔year calendar integrates THIS. The SAME operations as layer0's
185
+ * tropicalYearSecondsCore (the layer0 gate holds the twins bit-identical).
186
+ * Past the tidal chain's domain the J2000 rate stands in.
187
+ * @param {number} t_Ma @returns {number} */
212
188
  function tropicalYearSecondsAtAge(t_Ma) {
213
189
  return tropicalYearSecondsFromLod(t_Ma, lodSecondsAtAge(t_Ma));
214
190
  }
@@ -235,10 +211,6 @@ function createDeepTimeLod(deps) {
235
211
  return tropicalYearSecondsAtAge(t_Ma) / LOD_s;
236
212
  }
237
213
 
238
- // (Plan 09 step 7a: the frozen era clock's year twins on H_era —
239
- // T_sid·(1 − 13/H_era) and its day count, the bases the deleted cardinal
240
- // record and year-length combs were fitted against — are deleted.)
241
-
242
214
  /**
243
215
  * The solar day's "ecliptic missing motion" correction, seconds: the mean
244
216
  * solar day is counted against the Sun on the ECLIPTIC, whose plane turns
@@ -247,8 +219,7 @@ function createDeepTimeLod(deps) {
247
219
  * (≈ 3.44 ms at J2000). T_s₃ is an orbital quantity: constant at every
248
220
  * epoch (μ-tier), so the term rides only LOD_mean and the year length at
249
221
  * deep time. ONE home for the three runtimes' `h5Correction` twins (the
250
- * identifier keeps its name; the divisor is the nodal period since the
251
- * plan 06 T2 restatement, formerly the spin unit's H/5).
222
+ * identifier keeps its historical name; the divisor is the nodal period).
252
223
  * @param {number} t_Ma @returns {number|null} seconds (null past tidal lock)
253
224
  */
254
225
  function eclipticLodCorrectionSecondsAtAge(t_Ma) {
@@ -305,10 +276,6 @@ function createDeepTimeLod(deps) {
305
276
  return tidal + deps.cycleLodSumAt(year);
306
277
  }
307
278
 
308
- // (Plan 09: the "Actual LOD" — the tidal mean × the retired sidereal-year
309
- // comb's ripple — is deleted with the comb; the ripple was the sidereal
310
- // year's λ̇ variation misattributed to the day length.)
311
-
312
279
  /**
313
280
  * dLOD/dt driver decomposition, ms/century per channel.
314
281
  * tidal: Moon-recession (Farhat da/dt, LLR-anchored) · gia: α(t) numeric
@@ -331,12 +298,11 @@ function createDeepTimeLod(deps) {
331
298
  const I_E = alpha * K.mEarthAloneKg * K.rEarthMetres * K.rEarthMetres;
332
299
  const year = 2000 - t_Ma * 1e6;
333
300
 
334
- // The cited history's slope (plan 12 option A): the engine's
335
- // moonDistanceSlopeMetresPerMaAtAge when it provides one (the Hermite's
336
- // analytic derivative — C1, smooth), else a ±1-kyr central difference on
337
- // the distance itself. t_Ma > 0 = past; forward-time sign flip. At J2000
338
- // the slope IS the LLR observation (the history's boundary condition):
339
- // +3.82 cm/yr ✓
301
+ // The cited history's slope: the engine's moonDistanceSlopeMetresPerMaAtAge
302
+ // when it provides one (the Hermite's analytic derivative — C1, smooth),
303
+ // else a ±1-kyr central difference on the distance itself. t_Ma > 0 =
304
+ // past; forward-time sign flip. At J2000 the slope IS the LLR observation
305
+ // (the history's boundary condition): +3.82 cm/yr ✓
340
306
  let slopePerMa = deps.moonDistanceSlopeMetresPerMaAtAge ? deps.moonDistanceSlopeMetresPerMaAtAge(t_Ma) : null;
341
307
  if (slopePerMa === null || slopePerMa === undefined) {
342
308
  const H_MA = 1e-3;
@@ -387,19 +353,18 @@ function createDeepTimeLod(deps) {
387
353
  return {
388
354
  lodSecondsAtAge, lodSecondsAtAgeWithAlpha, lodHoursAtAge,
389
355
  lunisolarPrecessionRateArcsecPerYrAtAge, lunisolarPrecessionPeriodYearsAtAge,
390
- // the constant's scaling alone (the hybrid's integrand) and the rate's obliquity factor (plan 12 §8)
356
+ // the constant's scaling alone (the hybrid's integrand) and the rate's obliquity factor
391
357
  lunisolarTorqueRateArcsecPerYrAtAge, lunisolarTorquePeriodYearsAtAge, precessionObliquityFactorAtAge,
392
- // the composition's terms (plan 06 Phase 3 S3, the lunisolar surface): (a₀/a_M)³ and f_S + (1 − f_S)(a₀/a_M)³
358
+ // the composition's terms (the lunisolar surface): (a₀/a_M)³ and f_S + (1 − f_S)(a₀/a_M)³
393
359
  lunarTorqueFactorAtAge: composed.lunarTorqueFactorAtAge,
394
360
  precessionTorqueTermAtAge: composed.torqueTermAtAge,
395
361
  siderealYearSecondsAtAge, tropicalYearSecondsAtAge, tropicalYearDaysAtAge,
396
- // the same law on a caller-supplied LOD (the browser's L1-α sensitivity sweep; plan 09 step 7c)
362
+ // the same law on a caller-supplied LOD (the browser's L1-α sensitivity sweep)
397
363
  tropicalYearSecondsFromLod,
398
- // the solar day's ecliptic missing-motion term on the nodal period (plan 06 T2 item; one home)
364
+ // the solar day's ecliptic missing-motion term on the nodal period (one home)
399
365
  eclipticLodCorrectionSecondsAtAge,
400
366
  yearInDaysAtAge, deltaTRawSecondsAtAge, lodSecondsWithCorrectionsAtAge,
401
367
  dLodDtDecompositionAtAge,
402
- // (plan 09 step 7a: the frozen era clock's counter and bases left with the last comb)
403
368
  };
404
369
  }
405
370
 
@@ -30,6 +30,49 @@
30
30
 
31
31
  'use strict';
32
32
 
33
+ /**
34
+ * The CO-ROTATING anchored mode sum — the z-side evaluator of the history
35
+ * (the ϖ̇ fix, measured): the plain DC anchor residual is a spurious
36
+ * zero-frequency mode that preserves the J2000 VALUE but dilutes the local
37
+ * argument rate by |sum(0)|/|anchor| (z: 11.47 → 7.93″/yr, a 92 s-class
38
+ * anomalistic-year bias in the mode tier). Here the residual ROTATES at the
39
+ * raw sum's own local arg-rate g* = Im(ż·z̄)/|z|² (analytic), so at t = 0
40
+ * both the value AND the rate are exact, and at depth the residual is one
41
+ * |R|-amplitude term at a physical frequency instead of a DC offset (deep
42
+ * envelope measured unchanged: [0.0001, 0.0672] → [0.0003, 0.0678] over
43
+ * 10–50 Myr). Exported: e(t) = hypot(sum(t)) needs no spin integration,
44
+ * so a fixture can read a deep eccentricity node here (bit-identical at the
45
+ * grid nodes; the published surface is the grid's linear interpolation and
46
+ * stays on the history).
47
+ * @param {ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>} modes
48
+ * @param {[number, number]} anchor the J2000 value (q, p) the sum is pinned to
49
+ * @returns {(t: number) => [number, number]} t in years from J2000
50
+ */
51
+ function createCoRotatingAnchoredModeSum(modes, anchor) {
52
+ const sum = (/** @type {number} */ t) => {
53
+ let re = 0, im = 0;
54
+ for (const m of modes) {
55
+ const c = Math.cos(m.omegaRadPerYr * t), s = Math.sin(m.omegaRadPerYr * t);
56
+ re += m.re * c - m.im * s;
57
+ im += m.re * s + m.im * c;
58
+ }
59
+ return [re, im];
60
+ };
61
+ let q0 = 0, p0 = 0, dq0 = 0, dp0 = 0;
62
+ for (const m of modes) {
63
+ q0 += m.re; p0 += m.im;
64
+ dq0 += -m.omegaRadPerYr * m.im;
65
+ dp0 += m.omegaRadPerYr * m.re;
66
+ }
67
+ const gStar = (dp0 * q0 - dq0 * p0) / (q0 * q0 + p0 * p0);
68
+ const R = [anchor[0] - q0, anchor[1] - p0];
69
+ return (/** @type {number} */ t) => {
70
+ const [x, y] = sum(t);
71
+ const c = Math.cos(gStar * t), s = Math.sin(gStar * t);
72
+ return [x + R[0] * c - R[1] * s, y + R[0] * s + R[1] * c];
73
+ };
74
+ }
75
+
33
76
  /**
34
77
  * @param {{
35
78
  * zModes: ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>,
@@ -97,43 +140,14 @@ function createDeepOrbitalHistory({
97
140
  // CO-ROTATING anchor (the ϖ̇ fix, measured): the DC residual above is a
98
141
  // spurious zero-frequency mode — it preserves the J2000 VALUE but dilutes
99
142
  // the local argument rate by |sum(0)|/|anchor| (z: 11.47 → 7.93″/yr, a
100
- // 92 s-class anomalistic-year bias in the mode tier). Here the residual
101
- // ROTATES at the raw sum's own local arg-rate g* = Im(ż·z̄)/|z|²
102
- // (analytic), so at t=0 both the value AND the rate are exact, and at
103
- // depth the residual is one |R|-amplitude term at a physical frequency
104
- // instead of a DC offset (deep envelope measured unchanged:
105
- // [0.0001, 0.0672] → [0.0003, 0.0678] over 10–50 Myr).
143
+ // 92 s-class anomalistic-year bias in the mode tier). The co-rotating form
144
+ // is the module-level createCoRotatingAnchoredModeSum (exported — the
145
+ // plan-06 fixture reads the deep eccentricity from it directly).
106
146
  // z ONLY: ζ keeps the DC anchor DELIBERATELY — its anchor is ~0 by
107
147
  // definition (Earth's inclination to the J2000 ecliptic at J2000), i.e.
108
148
  // the coordinate origin; a rotating residual there would inject a fake
109
149
  // wobble into n̂(t).
110
- const mkAnchoredCoRot = (
111
- /** @type {ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>} */ modes,
112
- /** @type {[number, number]} */ anchor,
113
- ) => {
114
- const sum = (/** @type {number} */ t) => {
115
- let re = 0, im = 0;
116
- for (const m of modes) {
117
- const c = Math.cos(m.omegaRadPerYr * t), s = Math.sin(m.omegaRadPerYr * t);
118
- re += m.re * c - m.im * s;
119
- im += m.re * s + m.im * c;
120
- }
121
- return [re, im];
122
- };
123
- let q0 = 0, p0 = 0, dq0 = 0, dp0 = 0;
124
- for (const m of modes) {
125
- q0 += m.re; p0 += m.im;
126
- dq0 += -m.omegaRadPerYr * m.im;
127
- dp0 += m.omegaRadPerYr * m.re;
128
- }
129
- const gStar = (dp0 * q0 - dq0 * p0) / (q0 * q0 + p0 * p0);
130
- const R = [anchor[0] - q0, anchor[1] - p0];
131
- return (/** @type {number} */ t) => {
132
- const [x, y] = sum(t);
133
- const c = Math.cos(gStar * t), s = Math.sin(gStar * t);
134
- return [x + R[0] * c - R[1] * s, y + R[0] * s + R[1] * c];
135
- };
136
- };
150
+ const mkAnchoredCoRot = createCoRotatingAnchoredModeSum;
137
151
  const s2h = Math.sin(anchorInclEclipticDeg / 2 * D2R);
138
152
  const zetaAnchor = /** @type {[number, number]} */ (
139
153
  [s2h * Math.cos(anchorAscNodeEclipticDeg * D2R), s2h * Math.sin(anchorAscNodeEclipticDeg * D2R)]);
@@ -676,4 +690,4 @@ function createDeepOrbitalHistory({
676
690
  };
677
691
  }
678
692
 
679
- module.exports = { createDeepOrbitalHistory };
693
+ module.exports = { createDeepOrbitalHistory, createCoRotatingAnchoredModeSum };
@@ -42,6 +42,7 @@
42
42
  // • The frozen era clock stays the certified era device (opt-out /
43
43
  // era-certification record), not a member of this family.
44
44
 
45
+ const { wrap180 } = require('../math/angles.cjs');
45
46
  const { createCardinalStructure } = require('../cardinal/one-source-structure.cjs');
46
47
  const { createSiderealYearChannel } = require('./sidereal-year-channel.cjs');
47
48
 
@@ -64,7 +65,7 @@ function createYearLengths({ sampleAt, massLossSiderealSecondsAtYearFn }) {
64
65
  if (typeof sampleAt !== 'function' || typeof massLossSiderealSecondsAtYearFn !== 'function') {
65
66
  throw new Error('createYearLengths: sampleAt and massLossSiderealSecondsAtYearFn are required');
66
67
  }
67
- const w180 = (/** @type {number} */ d) => ((d + 540) % 360) - 180;
68
+ const w180 = wrap180; // math/angles — bit-identical to the former inline form for the sub-degree differences wrapped here
68
69
  const chan = createSiderealYearChannel({ massLossSiderealSecondsAtYearFn });
69
70
  /** A year length from a longer year and a retrograde angular rate of the
70
71
  * reference point, RATE form: 1/T = 1/T_long + p/(360°·JY) — exact (the
@@ -69,6 +69,8 @@
69
69
 
70
70
  'use strict';
71
71
 
72
+ const { wrap180 } = require('../math/angles.cjs');
73
+
72
74
  /**
73
75
  * @typedef {Object} BesselianDeps
74
76
  * @property {(dDaysTT: number) => {lonDeg: number, latDeg: number, distKm: number}} moonFullAtDaysTT
@@ -88,6 +90,23 @@
88
90
  * gmstMeanSiderealT2Deg: number, speedOfLightKmS: number }} constants
89
91
  */
90
92
 
93
+ /** Mean sidereal time at Greenwich, degrees (mean equinox — pairs with the
94
+ * mean-of-date body longitudes; coefficients single-sourced from
95
+ * astro-reference.json physicalConstants). THE ONE GMST of the model: the
96
+ * eclipse location tier, the API's observer tier, the eclipse and lunar
97
+ * audits and the browser's diagnostics all read it. Meeus 12.4's
98
+ * cubic term (−T³/38,710,000) is deliberately absent: it is 0.9″ in the
99
+ * eclipse canon and at most 93″ (6 s of time) at the edge of the observer
100
+ * era, and every recorded eclipse and lunar value was measured without it.
101
+ * @param {number} jdUT
102
+ * @param {{ j2000JD: number, julianCenturyDays: number, gmstMeanSiderealT0Deg: number, gmstMeanSiderealRateDegPerDay: number, gmstMeanSiderealT2Deg: number }} K
103
+ * @returns {number} */
104
+ function computeGmstDeg(jdUT, K) {
105
+ const T = (jdUT - K.j2000JD) / K.julianCenturyDays;
106
+ return ((K.gmstMeanSiderealT0Deg + K.gmstMeanSiderealRateDegPerDay * (jdUT - K.j2000JD)
107
+ + K.gmstMeanSiderealT2Deg * T * T) % 360 + 360) % 360;
108
+ }
109
+
91
110
  /** @param {BesselianDeps} deps */
92
111
  function createBesselian(deps) {
93
112
  const K = deps.constants;
@@ -97,14 +116,8 @@ function createBesselian(deps) {
97
116
  const R_MOON_KM = K.moonDiameterKm / 2;
98
117
  const F = 1 / K.earthFlatteningInverse;
99
118
 
100
- /** Mean sidereal time at Greenwich, degrees (mean equinox — pairs with the
101
- * mean-of-date body longitudes; coefficients single-sourced from
102
- * astro-reference.json physicalConstants). @param {number} jdUT @returns {number} */
103
- function gmstDeg(jdUT) {
104
- const T = (jdUT - K.j2000JD) / K.julianCenturyDays;
105
- return ((K.gmstMeanSiderealT0Deg + K.gmstMeanSiderealRateDegPerDay * (jdUT - K.j2000JD)
106
- + K.gmstMeanSiderealT2Deg * T * T) % 360 + 360) % 360;
107
- }
119
+ /** @param {number} jdUT @returns {number} */
120
+ const gmstDeg = (jdUT) => computeGmstDeg(jdUT, K);
108
121
 
109
122
  /** Ecliptic-of-date → equatorial-of-date vector (km).
110
123
  * @param {number} lonDeg @param {number} betDeg @param {number} distKm
@@ -150,7 +163,7 @@ function createBesselian(deps) {
150
163
  const moon = deps.moonFullAtDaysTT(dTT);
151
164
  const H_DAYS = 0.02;
152
165
  const dLon = deps.moonFullAtDaysTT(dTT + H_DAYS).lonDeg - deps.moonFullAtDaysTT(dTT - H_DAYS).lonDeg;
153
- const moonRateDegPerDay = (((dLon + 540) % 360) - 180) / (2 * H_DAYS);
166
+ const moonRateDegPerDay = wrap180(dLon) / (2 * H_DAYS);
154
167
  const tauDays = moon.distKm / K.speedOfLightKmS / 86400;
155
168
  return {
156
169
  S: eclToEq(sunLon, 0, sunDistanceKm(year, sunLon), eps),
@@ -310,7 +323,7 @@ function createBesselian(deps) {
310
323
  return { kind, magnitude: Math.max(0, atMax.magnitude), maxJd, contacts, centralDurationSeconds };
311
324
  }
312
325
 
313
- return { umbraGroundAt, shadowStateAt, localCircumstances };
326
+ return { umbraGroundAt, shadowStateAt, localCircumstances, gmstDeg };
314
327
  }
315
328
 
316
- module.exports = { createBesselian };
329
+ module.exports = { createBesselian, computeGmstDeg };
package/src/index.js CHANGED
@@ -61,7 +61,7 @@ const NEVER_INJECTABLE = Object.keys(REFERENCE_DATA);
61
61
 
62
62
  /**
63
63
  * Generated at build time from `public/input/astro-reference.json` (plus the
64
- * deep-time block the generator assembles; model-parameters.json is deleted, plan 11)
64
+ * deep-time block the generator assembles)
65
65
  * (§2g) by `tools/constants/generate.mjs`. 324 values across 15 blocks.
66
66
  *
67
67
  * Free parameters and measured anchors only. Validation targets are excluded by
@@ -95,29 +95,21 @@ export { FITTED_COEFFICIENTS, COEFFICIENTS_HASH } from './constants/index.js';
95
95
  export { createEpochPrimitives } from './layer0/index.js';
96
96
  export { deriveEpochParams } from './layer0/derive-params.js';
97
97
  export { createDerivedViews } from './layer1/index.js';
98
- // (Plan 09 step 7a: the Phase 7 integrated-phase machinery `createPhaseMachinery`
99
- // — the ∫dt/H_era table and the cycle counters every comb read — and the
100
- // frozen cardinal record evaluator `createCardinalModel` (the §10 derived
101
- // form on the deleted CARDINAL_POINT_* coefficients) are DELETED; the
102
- // cardinal instants are createModel().cardinal, the one Sun's crossings.)
103
98
  // The deep-time calendar (year ↔ JD under the drifting year length) — ONE
104
- // implementation for both engines since the year/day collapse (formerly the
105
- // PHASE-B-DUPLICATE family). CJS on purpose: tools/lib requires the same
99
+ // implementation for both engines. CJS on purpose: tools/lib requires the same
106
100
  // file via the exports-map subpath; re-exported here so bundled ESM
107
101
  // consumers need only the package root.
108
102
  export { createDeepCalendar } from './phase/deep-calendar.cjs';
109
- // Plan 13 B1: the civil calendar ↔ JD (Meeus ch. 7 with the 1582-10-15
110
- // reform) and the angle constants/wraps — ONE home; the browser's eighteen
111
- // calendar copies and 27 local D2R constants import these.
103
+ // The civil calendar ↔ JD (Meeus ch. 7 with the 1582-10-15 reform) and the
104
+ // angle constants/wraps — ONE home for every runtime.
112
105
  export { GREGORIAN_START, GREGORIAN_START_JD, calendarToJD, jdToCalendar, jdToDecimalYear, dayFractionToHMS, julianCalendarToJD, jdToJulianCalendar } from './time/calendar.cjs';
113
106
  export { DEG2RAD, RAD2DEG, ARCSEC_PER_TURN, ARCSEC_PER_RAD, wrap360, wrap180, wrap180Closed, wrap2pi, wrapPi } from './math/angles.cjs';
114
- // Plan 13 B2: THE deep-time chain assembly — the GIA α channel, the Layer-0
115
- // bundle, the cited Moon-distance history, the ΔT cycle stack, |s₃|, the
116
- // LOD/ΔT core, the lunar month chain and the mean*AtAge family, assembled
117
- // ONCE from the generated constants; the Node twin and the browser destructure it.
107
+ // THE deep-time chain assembly — the GIA α channel, the Layer-0 bundle, the
108
+ // cited Moon-distance history, the ΔT cycle stack, |s₃|, the LOD/ΔT core, the
109
+ // lunar month chain and the mean*AtAge family, assembled ONCE from the
110
+ // generated constants; the Node twin and the browser destructure it.
118
111
  export { createDeepTimeChain, MOON_ECC_SENSITIVITY_PERIGEE, MOON_ECC_SENSITIVITY_NODE } from './deltat/deep-time-chain.js';
119
- // Plan 13 B3: the J2000 mass chain and the Moon's J2000 periods (one home for
120
- // three copies each) and the unit constants.
112
+ // The J2000 mass chain, the Moon's J2000 periods and the unit constants — ONE home.
121
113
  export { computeMassChainJ2000, computeMoonPeriodsJ2000 } from './earth/mass-chain.cjs';
122
114
  export { SECONDS_PER_DAY, DAYS_PER_JULIAN_YEAR, JULIAN_CENTURY_DAYS, SECONDS_PER_JULIAN_YEAR } from './constants/units.cjs';
123
115
  // D4b: the one-source cardinal structure — the EoC layer (year lengths,
@@ -127,7 +119,6 @@ export { createCardinalStructure } from './cardinal/one-source-structure.cjs';
127
119
  // Phase 8.2 — the lunar machinery, extracted layer by layer (survey order:
128
120
  // eccentricity channel → month chain → cycle tables → arguments → series →
129
121
  // apparent). Same CJS + root re-export convention.
130
- // (plan 09 step 6: createMoonEccChannel — the H/3 eccentricity law — is deleted; Earth's e of date is the N-body series on every path)
131
122
  export { createMoonMonthChain } from './moon/month-chain.cjs';
132
123
  export { createChainCycleIntegrator } from './chain-cycles/index.cjs';
133
124
  export { createMoonArguments } from './moon/arguments.cjs';
@@ -137,26 +128,26 @@ export { createMoonApparent } from './moon/apparent.cjs';
137
128
  // sample) and the offset-circle wheel-angle solver: the scene twins' one placement.
138
129
  export { computeEarthFrameOfDate, solveWheelAngleForLongitude, computeSceneWorldFrameJ2000, SCENE_EQUINOX_VIEW_AZIMUTH_DEG } from './earth/frame-of-date.cjs';
139
130
  // Phase 8.3 — the planet machinery, extracted by LAW over body records
140
- // (survey order: geometry → channels → chains). The ψ/K amplitude laws
141
- // (planets/fibonacci-laws), the record-based orientation forms
142
- // (planets/orientation) and the ascending-node integrator
143
- // (planets/asc-node-integrator) are DELETED at plan 07 R5/R6: the planets'
144
- // elements of date have one home, the N-body chain.
131
+ // (survey order: geometry → channels → chains). The planets' elements of date
132
+ // have one home, the N-body chain.
145
133
  export { derivePlanetGeometry, scaffoldOrbitInputs } from './planets/geometry.cjs';
146
134
  // (plan 09 step 6: eccentricityFromCycles / computeEccentricityIntegrated — the H/16 law-of-cosines eccentricity — are deleted; no runtime read them)
147
135
  export * as planetOrbitChain from './planets/orbit-chain.cjs';
148
136
  // P5/K4.6c — the engine-D Keplerian chain (pure evaluator + the embedded
149
137
  // governed artifact; the browser flag path consumes exactly these).
150
138
  export { computeSecularShape } from './planets/secular-shape.cjs';
151
- export { buildPlanetChainsFromArtifactData, computePlanetElementsAtYear, computeHeliocentricEclipticFromElements, computePoissonArgRad, computeOsculatingElements, solveKeplerRad, computeApsidalSecularDegPerYr, ANCHOR_EPOCH_YEAR, ANCHOR_EPOCH_JD } from './planets/keplerian-chain.cjs';
139
+ // `computeApsidalTangentDegPerYr` is the chain's ±150-yr central tangent of the perihelion
140
+ // longitude (the panels' "Prec." cell — osculating, NOT the ±1-kyr secular stencil of the
141
+ // "Secular" cell). Its former name `computeApsidalSecularDegPerYr` left the API at 24.0.0
142
+ // (no reader in the simulator, the website or the paper).
143
+ export { buildPlanetChainsFromArtifactData, computePlanetElementsAtYear, computeHeliocentricEclipticFromElements, computePoissonArgRad, computeOsculatingElements, solveKeplerRad, computeApsidalTangentDegPerYr, ANCHOR_EPOCH_YEAR, ANCHOR_EPOCH_JD } from './planets/keplerian-chain.cjs';
152
144
  export { computeEquatorNodeOriginSFrameDeg, convertNodeSFrameToEquatorOriginDeg } from './planets/inv-plane-frame.cjs';
153
145
  export { createSecularSeriesOverride } from './planets/secular-series.cjs';
154
- // Plan 06 Phase 7 — the planets' spin channel (the precession constant from
155
- // each planet's own torques, the spin integrated on its own ζ plane history).
146
+ // The planets' spin channel (the precession constant from each planet's own
147
+ // torques, the spin integrated on its own ζ plane history).
156
148
  export { computePlanetPrecessionConstant, createPlanetSpinChannel, createPlanetSpinChannelFromArtifacts, computeObliquityJ2000Deg } from './planets/spin-channel.cjs';
157
149
  export { CHAIN_ARTIFACT, CHAIN_ARTIFACT_HASH } from './planets/chain-artifact.js';
158
- // Engine-switch Stage B, T5d-(d): the deep-time Earth-z channel (the deep
159
- // lunar-chain modulation rides it; era consumers stay on the H/3 channel).
150
+ // The deep-time Earth-z channel (the deep lunar-chain modulation rides it).
160
151
  export { createDeepEccChannel } from './moon/deep-ecc-channel.cjs';
161
152
  export { DEEP_MODES_ARTIFACT, DEEP_MODES_ARTIFACT_HASH } from './moon/deep-modes-artifact.cjs';
162
153
  // Stage C-3: the ONE home of the obliquity-hybrid / deep-orbital-history
@@ -166,28 +157,25 @@ export { createDeepOrbitalHistory } from './earth/deep-orbital-history.cjs';
166
157
  export { createSiderealYearChannel } from './earth/sidereal-year-channel.cjs';
167
158
  // S2: THE ONE of-date year-length family (years + precession beats, SI seconds)
168
159
  export { createYearLengths, computeMeanTropicalYearJ2000Days, ONE_FAMILY_WINDOW_YEARS } from './earth/year-lengths.cjs';
169
- // Plan 06 D6: THE ONE home of the composed lunisolar precession rate ψ̇(t)
170
- // (spin ω(t) × [solar torque + lunar torque on the recession history]) —
171
- // leg-1's physical rate; the structural H(t)/13 clock is its named diagnostic.
160
+ // THE ONE home of the composed lunisolar precession rate ψ̇(t) (spin ω(t) ×
161
+ // [solar torque + lunar torque on the recession history]) — falsification
162
+ // leg 1's physical rate.
172
163
  export { computeSolarTorqueShare, createComposedPrecession } from './earth/precession-composed.cjs';
173
- // Plan 12 §8 option (a): the cited mean obliquity of date — the second column read from the
174
- // Earth–Moon history; the precession RATE of date carries its cos ε̄(t)/cos ε̄(0) on the constant.
164
+ // The cited mean obliquity of date — the second column read from the Earth–Moon
165
+ // history; the precession RATE of date carries its cos ε̄(t)/cos ε̄(0) on the constant.
175
166
  export { createMeanObliquityHistory } from './earth/mean-obliquity-history.cjs';
176
167
  // (planets/predict.cjs — the planet predictive-precession feature basis — was
177
168
  // retired at plan 06 R8 with PREDICT_COEFFS_PHYSICAL.)
178
169
  // L10 — the composition front door: one law set, N body records. Thin by
179
170
  // design; engines keep their direct call sites (see planets/model.cjs).
180
171
  export { createPlanetModel } from './planets/model.cjs';
181
- // plan 11 step 6 — the planets' presentation names, the last leaf of the
182
- // deleted model-parameters.json (code, not an input: not injectable, not hashed).
172
+ // the planets' presentation names (code, not an input: not injectable, not hashed).
183
173
  export { PLANET_DISPLAY_NAMES } from './planets/display-names.cjs';
184
174
  // Phase 8.4 — the climate/ΔT machinery, extracted layer by layer.
185
175
  export { createDeltaTCycles } from './deltat/cycles.cjs';
186
176
  export { createDeepTimeLod } from './deltat/deep-time.cjs';
187
- // plan 12 (option A): the Earth–Moon distance history is a CITED PHYSICAL
188
- // INPUT (Farhat et al. 2022, the AstroGeo22 ephemeris) read as a shape on the
189
- // model's J2000 anchor; the fitted quartic, the rock-fitted regime spline and
190
- // the solar-channel budget are deleted.
177
+ // The Earth–Moon distance history is a CITED PHYSICAL INPUT (Farhat et al.
178
+ // 2022, the AstroGeo22 ephemeris) read as a shape on the model's J2000 anchor.
191
179
  export { createMoonDistanceHistory } from './deltat/moon-distance-history.cjs';
192
180
  export { MOON_DISTANCE_ARTIFACT, MOON_DISTANCE_ARTIFACT_HASH } from './deltat/moon-distance-artifact.cjs';
193
181
  export { deltaTEspenakMeeusCanonSeconds } from './deltat/historical.cjs';
@@ -199,9 +187,6 @@ export { createEclipseFinders } from './eclipse/finders.cjs';
199
187
  // (reference/published-curves MIGRATED to @essrt/reference at the 4.0.0
200
188
  // major — the published model package carries no comparison references;
201
189
  // the K2 one-way wall is package-structural.)
202
- // Phase 9 — S-P8: the fitted sun-longitude harmonic stack (three copies → one).
203
- // (plan 09 step 5a: createSunLongitudeCorrection — the Step-0 Sun comb's evaluator,
204
- // retired from the Sun node at plan 06 R4 — is deleted with the comb and its fitter.)
205
190
 
206
191
  /**
207
192
  * Build a model bound to a set of constants.
@@ -270,15 +255,12 @@ export const createModel = (constants = GENERATED, opts = {}) => {
270
255
  constants: ctx,
271
256
  hash,
272
257
 
273
- // Plan 09: the fit-era lattice identities H/13, H/3, H/16
274
- // (`computeLatticePeriodsYears`, DEVICE tier) left this surface — the
275
- // published periods are `epoch.axialPrecessionYearsAtYear` and the
258
+ // The published periods are `epoch.axialPrecessionYearsAtYear` and the
276
259
  // lunisolar surface's apsidal and perihelion-of-date periods; the
277
- // counterfactual gate now reads the obliquity anchor through the assembly.
260
+ // counterfactual gate reads the obliquity anchor through the assembly.
278
261
 
279
262
  /**
280
- * Earth eccentricity at a year — the Phase-6 promise, fulfilled by the
281
- * §7a assembly (law-of-cosines on the integrated H/16 phase).
263
+ * Earth eccentricity at a year — the one-source series through the §7a assembly.
282
264
  * @param {number} year
283
265
  * @returns {number}
284
266
  */