@essrt/physics 23.0.0 → 23.2.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/package.json +7 -2
- package/src/constants/generated.d.ts +4 -3
- package/src/constants/generated.js +5 -4
- package/src/constants/units.cjs +20 -0
- package/src/deltat/deep-time-chain.js +457 -0
- package/src/deltat/deep-time.cjs +42 -13
- package/src/deltat/moon-distance-artifact.cjs +6 -3
- package/src/earth/deep-orbital-history.cjs +44 -15
- package/src/earth/mass-chain.cjs +95 -0
- package/src/earth/mean-obliquity-history.cjs +94 -0
- package/src/earth/precession-composed.cjs +49 -3
- package/src/index.js +17 -0
- package/src/layer0/index.js +20 -6
- package/src/math/angles.cjs +38 -0
- package/src/model.js +76 -227
- package/src/moon/arguments.cjs +5 -31
- package/src/planets/chain-artifact.js +2 -2
- package/src/time/calendar.cjs +165 -0
- package/types/constants/generated.d.ts +4 -3
- package/types/constants/units.d.cts +8 -0
- package/types/deltat/deep-time-chain.d.ts +266 -0
- package/types/deltat/deep-time.d.cts +14 -0
- package/types/deltat/moon-distance-artifact.d.cts +3 -0
- package/types/earth/deep-orbital-history.d.cts +5 -3
- package/types/earth/mass-chain.d.cts +78 -0
- package/types/earth/mean-obliquity-history.d.cts +32 -0
- package/types/earth/precession-composed.d.cts +11 -1
- package/types/index.d.ts +6 -0
- package/types/layer0/index.d.ts +3 -2
- package/types/math/angles.d.cts +18 -0
- package/types/model.d.ts +21 -3
- package/types/moon/arguments.d.cts +2 -6
- package/types/time/calendar.d.cts +78 -0
|
@@ -57,9 +57,11 @@
|
|
|
57
57
|
* measured at the 500-yr artifact cadence: 0.16″/0.18″ rms vs IAU-2006
|
|
58
58
|
* over 1900–2100/1600–2400 vs the era tier's 0.31″/0.63″, and 0.0396°
|
|
59
59
|
* vs La2004 over −200 kyr vs the deep tier's 0.069° — the C-1 verdict,
|
|
60
|
-
* plan 02) and zetaModes serves only as the TAIL beyond the span
|
|
61
|
-
*
|
|
62
|
-
*
|
|
60
|
+
* plan 02) and zetaModes serves only as the TAIL beyond the span, joined
|
|
61
|
+
* to the series at each edge so n̂ is continuous there (plan 12 §8.3 — the
|
|
62
|
+
* J2000-point anchor left a 1.6° step at −10 Myr that kicked the hybrid's
|
|
63
|
+
* mean obliquity +0.9° for the whole tail; far outside every certified window).
|
|
64
|
+
* solarTorqueShareJ2000 and
|
|
63
65
|
* dynamicalEllipticityRatioAtYearFn: THE PRECESSION OF DATE — the two
|
|
64
66
|
* factors on the precession constant (see alphaAtGeneral below); absent,
|
|
65
67
|
* the constant is the secular law alone, bit-identical.
|
|
@@ -73,19 +75,22 @@ function createDeepOrbitalHistory({
|
|
|
73
75
|
}) {
|
|
74
76
|
const D2R = Math.PI / 180, R2D = 180 / Math.PI;
|
|
75
77
|
|
|
78
|
+
const mkRawSum = (
|
|
79
|
+
/** @type {ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>} */ modes,
|
|
80
|
+
) => (/** @type {number} */ t) => {
|
|
81
|
+
let re = 0, im = 0;
|
|
82
|
+
for (const m of modes) {
|
|
83
|
+
const c = Math.cos(m.omegaRadPerYr * t), s = Math.sin(m.omegaRadPerYr * t);
|
|
84
|
+
re += m.re * c - m.im * s;
|
|
85
|
+
im += m.re * s + m.im * c;
|
|
86
|
+
}
|
|
87
|
+
return [re, im];
|
|
88
|
+
};
|
|
76
89
|
const mkAnchored = (
|
|
77
90
|
/** @type {ReadonlyArray<{omegaRadPerYr: number, re: number, im: number}>} */ modes,
|
|
78
91
|
/** @type {[number, number]} */ anchor,
|
|
79
92
|
) => {
|
|
80
|
-
const sum = (
|
|
81
|
-
let re = 0, im = 0;
|
|
82
|
-
for (const m of modes) {
|
|
83
|
-
const c = Math.cos(m.omegaRadPerYr * t), s = Math.sin(m.omegaRadPerYr * t);
|
|
84
|
-
re += m.re * c - m.im * s;
|
|
85
|
-
im += m.re * s + m.im * c;
|
|
86
|
-
}
|
|
87
|
-
return [re, im];
|
|
88
|
-
};
|
|
93
|
+
const sum = mkRawSum(modes);
|
|
89
94
|
const s0 = sum(0), R = [anchor[0] - s0[0], anchor[1] - s0[1]];
|
|
90
95
|
return (/** @type {number} */ t) => { const [x, y] = sum(t); return [x + R[0], y + R[1]]; };
|
|
91
96
|
};
|
|
@@ -161,9 +166,33 @@ function createDeepOrbitalHistory({
|
|
|
161
166
|
const nS = sq.length, tEndYr = t0Yr + (nS - 1) * stepYr;
|
|
162
167
|
const li = mkSeriesCubic(t0Yr, stepYr, nS);
|
|
163
168
|
const R = [zetaAnchor[0] - li(sq, 0), zetaAnchor[1] - li(sp, 0)];
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
169
|
+
// THE TAIL JOINS THE SERIES AT EACH SEAM (plan 12 §8.3, measured 2026-10).
|
|
170
|
+
// The mode-sum tail anchored to the J2000 POINT reached the span edges
|
|
171
|
+
// 1.61° (past) / 0.74° (future) away from the series — its ~70-kyr phases
|
|
172
|
+
// drift over 10 Myr (the extraction residual) and its J2000 anchor misses
|
|
173
|
+
// the series' mean plane by 0.506° — and the hybrid's mean obliquity
|
|
174
|
+
// STEPPED +0.90° / +0.30° there and stayed stepped (24.17° over ±1 Myr at
|
|
175
|
+
// −20 Myr against 23.3° inside the span; the API served it to ±500 Myr).
|
|
176
|
+
// Three anchors measured: J2000 point (above), the series' MEAN plane
|
|
177
|
+
// (n̂ step 1.12°/0.54°, ε step +0.74°/+0.57°), and the SEAM POINT per side
|
|
178
|
+
// — the tail's constant chosen so n̂ is continuous at the edge it continues
|
|
179
|
+
// (ε step +0.09°/+0.13°, the tail's mean 23.31–23.36° over ±100 Myr). The
|
|
180
|
+
// pole follows n̂ adiabatically (ds/dt = α(ŝ·n̂)(ŝ×n̂) conserves ŝ·n̂ for a
|
|
181
|
+
// slowly moving n̂), so a DISCONTINUITY in n̂ is what kicks ε, not the
|
|
182
|
+
// tail's mean plane: continuity wins. Inside the span nothing changes
|
|
183
|
+
// (bit-identical); beyond it the hybrid carries the Quaternary mean on the
|
|
184
|
+
// tail — NO tidal evolution of the mean (the cited mean obliquity of date
|
|
185
|
+
// is model.earth.meanObliquityCitedDeg).
|
|
186
|
+
const rawSum = mkRawSum(zetaModes);
|
|
187
|
+
const e0 = rawSum(t0Yr), e1 = rawSum(tEndYr);
|
|
188
|
+
const RPast = [li(sq, t0Yr) + R[0] - e0[0], li(sp, t0Yr) + R[1] - e0[1]];
|
|
189
|
+
const RFuture = [li(sq, tEndYr) + R[0] - e1[0], li(sp, tEndYr) + R[1] - e1[1]];
|
|
190
|
+
zetaAt = (/** @type {number} */ t) => {
|
|
191
|
+
if (t >= t0Yr && t <= tEndYr) return [li(sq, t) + R[0], li(sp, t) + R[1]];
|
|
192
|
+
const [x, y] = rawSum(t);
|
|
193
|
+
const Rt = t < t0Yr ? RPast : RFuture;
|
|
194
|
+
return [x + Rt[0], y + Rt[1]];
|
|
195
|
+
};
|
|
167
196
|
}
|
|
168
197
|
const zAnchor = /** @type {[number, number]} */ (
|
|
169
198
|
[anchorE * Math.cos(anchorPeriEclipticDeg * D2R), anchorE * Math.sin(anchorPeriEclipticDeg * D2R)]);
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The J2000 mass chain and the Moon's J2000 periods — ONE home (holisticuniverse
|
|
3
|
+
* plan 13 B3). Before B3 the mass chain (Moon Kepler → GM_EM → the Earth/Moon
|
|
4
|
+
* split → the Sun) was computed in three places (model.js, tools/lib/
|
|
5
|
+
* constants.js, src/script.js), and the Moon's derived periods in three more.
|
|
6
|
+
*
|
|
7
|
+
* Every expression here is the twins' expression in the twins' operation
|
|
8
|
+
* order (floating point is not associative; the goldens pin the values).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The mass chain in §9 order: Δa (the Sun's tidal coupling to the Earth–Moon
|
|
15
|
+
* barycentric wobble, leading order), the corrected Moon distance, Kepler on
|
|
16
|
+
* the Moon's orbit → G(M_E + M_M), the DE440 split → GM_E and GM_M, Kepler on
|
|
17
|
+
* Earth's orbit → G(M_☉ + M_E), the subtraction → GM_☉ and M_☉.
|
|
18
|
+
* @param {{
|
|
19
|
+
* moonDistanceKm: number, moonSiderealMonthDays: number, meanSiderealYearDays: number,
|
|
20
|
+
* meanLengthOfDaySeconds: number, massRatioEarthMoon: number, currentAUDistanceKm: number,
|
|
21
|
+
* gravitationalConstantKm3KgS2: number,
|
|
22
|
+
* }} c
|
|
23
|
+
* @returns {{
|
|
24
|
+
* meanSiderealYearSeconds: number, moonOrbitalShiftKm: number, moonDistanceCorrectedKm: number,
|
|
25
|
+
* gmEarthMoonSystemKm3S2: number, gmEarthAloneKm3S2: number, gmMoonAloneKm3S2: number,
|
|
26
|
+
* gmSunPlusEarthKm3S2: number, gmSunKm3S2: number, sunMassKg: number,
|
|
27
|
+
* }}
|
|
28
|
+
*/
|
|
29
|
+
function computeMassChainJ2000(c) {
|
|
30
|
+
const meanSiderealYearSeconds = c.meanSiderealYearDays * 86400;
|
|
31
|
+
const moonOrbitalShiftKm = c.moonDistanceKm * (1 / (c.massRatioEarthMoon + 1)) * (c.moonSiderealMonthDays / c.meanSiderealYearDays);
|
|
32
|
+
const moonDistanceCorrectedKm = c.moonDistanceKm + moonOrbitalShiftKm;
|
|
33
|
+
const gmEarthMoonSystemKm3S2 = (4 * Math.PI * Math.PI * Math.pow(moonDistanceCorrectedKm, 3))
|
|
34
|
+
/ Math.pow(c.moonSiderealMonthDays * c.meanLengthOfDaySeconds, 2);
|
|
35
|
+
const gmEarthAloneKm3S2 = gmEarthMoonSystemKm3S2 * (c.massRatioEarthMoon / (c.massRatioEarthMoon + 1));
|
|
36
|
+
const gmMoonAloneKm3S2 = gmEarthMoonSystemKm3S2 / (c.massRatioEarthMoon + 1);
|
|
37
|
+
const gmSunPlusEarthKm3S2 = (4 * Math.PI * Math.PI * Math.pow(c.currentAUDistanceKm, 3))
|
|
38
|
+
/ Math.pow(meanSiderealYearSeconds, 2);
|
|
39
|
+
const gmSunKm3S2 = gmSunPlusEarthKm3S2 - gmEarthAloneKm3S2;
|
|
40
|
+
const sunMassKg = gmSunKm3S2 / c.gravitationalConstantKm3KgS2;
|
|
41
|
+
return { meanSiderealYearSeconds, moonOrbitalShiftKm, moonDistanceCorrectedKm, gmEarthMoonSystemKm3S2, gmEarthAloneKm3S2, gmMoonAloneKm3S2, gmSunPlusEarthKm3S2, gmSunKm3S2, sunMassKg };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The Moon's J2000 periods on the IAU inputs. The two precession inputs are
|
|
46
|
+
* equinox-OF-DATE observables (3231.50 d / 6798.38 d; the legacy "ICRF" name
|
|
47
|
+
* is kept); the star-referenced periods remove the equinox's own precession,
|
|
48
|
+
* 1/T_E = 1/T_I ∓ 1/T_p (the perigee advances, the node regresses), T_p the
|
|
49
|
+
* J2000 precession anchor in days. The months follow kinematically.
|
|
50
|
+
* @param {{
|
|
51
|
+
* moonSiderealMonthDays: number, moonApsidalPrecessionDaysInput: number, moonNodalPrecessionDaysInput: number,
|
|
52
|
+
* axialPrecessionJ2000Days: number, meanSiderealYearDays: number, meanSolarYearDays: number,
|
|
53
|
+
* }} c
|
|
54
|
+
* @returns {{
|
|
55
|
+
* moonApsidalPrecessionDaysEarth: number, moonNodalPrecessionDaysEarth: number,
|
|
56
|
+
* moonApsidalJ2000Seconds: number, moonNodalJ2000Seconds: number, moonSiderealMonthJ2000Seconds: number,
|
|
57
|
+
* moonAnomalisticMonthDays: number, moonNodalMonthDays: number, moonSynodicMonthDays: number, moonTropicalMonthDays: number,
|
|
58
|
+
* moonFullMoonCycleEarthDays: number, moonFullMoonCycleICRFDays: number,
|
|
59
|
+
* moonApsidalMeetsNodalDays: number, moonLunarLevelingCycleDays: number,
|
|
60
|
+
* moonDraconicYearICRFDays: number, moonDraconicYearEarthDays: number,
|
|
61
|
+
* }}
|
|
62
|
+
*/
|
|
63
|
+
function computeMoonPeriodsJ2000(c) {
|
|
64
|
+
const T = c.axialPrecessionJ2000Days;
|
|
65
|
+
const M = c.moonSiderealMonthDays;
|
|
66
|
+
// the days forms (tools/lib/constants.js §7, src/script.js)
|
|
67
|
+
const moonApsidalPrecessionDaysEarth = 1 / (1 / c.moonApsidalPrecessionDaysInput - 1 / T);
|
|
68
|
+
const moonNodalPrecessionDaysEarth = 1 / (1 / c.moonNodalPrecessionDaysInput + 1 / T);
|
|
69
|
+
const moonAnomalisticMonthDays = 1 / (1 / M - 1 / moonApsidalPrecessionDaysEarth);
|
|
70
|
+
const moonNodalMonthDays = 1 / (1 / M + 1 / moonNodalPrecessionDaysEarth);
|
|
71
|
+
const moonSynodicMonthDays = M * c.meanSiderealYearDays / (c.meanSiderealYearDays - M);
|
|
72
|
+
const moonTropicalMonthDays = 1 / (1 / M + 1 / T);
|
|
73
|
+
const moonFullMoonCycleEarthDays = (moonSynodicMonthDays / (moonSynodicMonthDays - moonAnomalisticMonthDays)) * moonAnomalisticMonthDays;
|
|
74
|
+
const moonFullMoonCycleICRFDays = 1 / (1 / moonFullMoonCycleEarthDays + 1 / T);
|
|
75
|
+
const moonApsidalMeetsNodalDays = (moonNodalMonthDays / (moonAnomalisticMonthDays - moonNodalMonthDays)) * moonAnomalisticMonthDays;
|
|
76
|
+
const moonLunarLevelingCycleDays = (moonNodalPrecessionDaysEarth / (moonNodalPrecessionDaysEarth - moonApsidalPrecessionDaysEarth) * (moonApsidalPrecessionDaysEarth / c.meanSolarYearDays)) * c.meanSolarYearDays;
|
|
77
|
+
const moonDraconicYearICRFDays = 1 / ((1 / c.meanSolarYearDays) + (1 / moonNodalPrecessionDaysEarth));
|
|
78
|
+
const moonDraconicYearEarthDays = 1 / (1 / moonDraconicYearICRFDays - 1 / T);
|
|
79
|
+
// the seconds forms the deep-time chain anchors on (model.js / tools/lib/deep-time.js — the same
|
|
80
|
+
// relation written on the seconds, so the J2000 anchors of the month chain are bit-identical)
|
|
81
|
+
const moonApsidalOfDateJ2000Seconds = c.moonApsidalPrecessionDaysInput * 86400;
|
|
82
|
+
const moonNodalOfDateJ2000Seconds = c.moonNodalPrecessionDaysInput * 86400;
|
|
83
|
+
const moonApsidalJ2000Seconds = 1 / (1 / moonApsidalOfDateJ2000Seconds - 1 / (T * 86400));
|
|
84
|
+
const moonNodalJ2000Seconds = 1 / (1 / moonNodalOfDateJ2000Seconds + 1 / (T * 86400));
|
|
85
|
+
const moonSiderealMonthJ2000Seconds = M * 86400;
|
|
86
|
+
return {
|
|
87
|
+
moonApsidalPrecessionDaysEarth, moonNodalPrecessionDaysEarth,
|
|
88
|
+
moonApsidalJ2000Seconds, moonNodalJ2000Seconds, moonSiderealMonthJ2000Seconds,
|
|
89
|
+
moonAnomalisticMonthDays, moonNodalMonthDays, moonSynodicMonthDays, moonTropicalMonthDays,
|
|
90
|
+
moonFullMoonCycleEarthDays, moonFullMoonCycleICRFDays, moonApsidalMeetsNodalDays, moonLunarLevelingCycleDays,
|
|
91
|
+
moonDraconicYearICRFDays, moonDraconicYearEarthDays,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
module.exports = { computeMassChainJ2000, computeMoonPeriodsJ2000 };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The mean obliquity of date ε̄(t) — the SECOND column the model reads from the
|
|
3
|
+
* cited Earth–Moon history (plan 12 §8, option (a)): Farhat, Auclair-Desrotour,
|
|
4
|
+
* Boué & Laskar 2022's own mean obliquity, carried in
|
|
5
|
+
* data/astrogeo22-earth-moon.json beside the distance.
|
|
6
|
+
*
|
|
7
|
+
* WHY AN INPUT. The composed lunisolar law (earth/precession-composed.cjs)
|
|
8
|
+
* scales the precession CONSTANT of date — α(t)/α₀ on the spin history and the
|
|
9
|
+
* lunar torque's (a₀/a_M)³. The precession RATE is α(t)·cos ε̄(t), and the chain
|
|
10
|
+
* had held cos ε̄ at its J2000 value at every epoch — a purity freeze without
|
|
11
|
+
* its twin. Standard theory since Goldreich 1966 (Touma & Wisdom 1994; Farhat
|
|
12
|
+
* et al. 2022) has the mean obliquity lower in the deep past, evolved by the
|
|
13
|
+
* lunar tidal torque through the Laplace-plane transition — the same
|
|
14
|
+
* ocean-dissipation physics option A declined to model for the distance. The
|
|
15
|
+
* published solution that computes ε̄(t) alongside a(t) is the input, as the
|
|
16
|
+
* distance is. Measured (plan 12 §8.1): the factor cos ε̄(t)/cos ε̄(0) closes
|
|
17
|
+
* the composed rate to Farhat's own precession column from −2.0 % to +0.4 % at
|
|
18
|
+
* 2.46 Ga and moves every paleo precession referee toward its source.
|
|
19
|
+
*
|
|
20
|
+
* WHAT IS READ. The column's cosine RATIO cos ε̄(t)/cos ε̄(0) — the SHAPE, as
|
|
21
|
+
* the distance is read as a(t)/a(0). The column's own value is published as the
|
|
22
|
+
* cited mean: 23.2545° at age 0, a Myr-scale MEAN of a secular solution, not
|
|
23
|
+
* the J2000 instant 23.4393° the hybrid obliquity integration starts from.
|
|
24
|
+
*
|
|
25
|
+
* INTERPOLATION. Cubic Hermite with central-difference tangents between the
|
|
26
|
+
* 1-Myr samples (one-sided at the ends) — C1. The column is monotone (measured:
|
|
27
|
+
* no sign change of its first difference across the 4,429 samples), so no
|
|
28
|
+
* limiter is needed. Forward of J2000 (t < 0) the column's J2000 one-sided
|
|
29
|
+
* slope is held — a labelled extrapolation, as the distance holds the LLR rate
|
|
30
|
+
* (the input has no future). Beyond the table's last sample the history
|
|
31
|
+
* REFUSES: null, never an extrapolation.
|
|
32
|
+
*
|
|
33
|
+
* HISTORICAL ERA. The slope at J2000 is −0.00264°/Myr: the factor is
|
|
34
|
+
* 1 − 2.0e-7 at 10 kyr and 1 − 2.0e-6 at 100 kyr — the ΔT era is untouched at
|
|
35
|
+
* the 1e-7 class; the deep-time clock T_p(t) shortens 0.75 % at the Devonian
|
|
36
|
+
* and 2.5 % at 2.46 Ga.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
'use strict';
|
|
40
|
+
|
|
41
|
+
const D2R = Math.PI / 180;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @typedef {Object} MeanObliquityTable
|
|
45
|
+
* @property {ReadonlyArray<number>} ageMa - ascending, 0 first, uniform 1-Myr step
|
|
46
|
+
* @property {ReadonlyArray<number>} obliquityDeg - the cited mean obliquity column, degrees
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param {{ table: MeanObliquityTable }} deps
|
|
51
|
+
* @returns {{
|
|
52
|
+
* meanObliquityDegAtAge: (tMa: number) => number|null,
|
|
53
|
+
* cosRatioAtAge: (tMa: number) => number|null,
|
|
54
|
+
* meanObliquityJ2000Deg: number,
|
|
55
|
+
* spanMa: number,
|
|
56
|
+
* }}
|
|
57
|
+
*/
|
|
58
|
+
function createMeanObliquityHistory(deps) {
|
|
59
|
+
const ages = deps.table.ageMa, eps = deps.table.obliquityDeg;
|
|
60
|
+
const n = ages ? ages.length : 0;
|
|
61
|
+
if (!(n >= 2) || !eps || eps.length !== n || ages[0] !== 0) {
|
|
62
|
+
throw new Error('mean-obliquity-history: the table must start at age 0 with ≥ 2 obliquity samples (a stale moon-distance embed lacks the obliquity column — regenerate the constants)');
|
|
63
|
+
}
|
|
64
|
+
const step = ages[1] - ages[0];
|
|
65
|
+
for (let i = 1; i < n; i++) {
|
|
66
|
+
if (ages[i] - ages[i - 1] !== step) throw new Error(`mean-obliquity-history: non-uniform age step at index ${i}`);
|
|
67
|
+
}
|
|
68
|
+
const spanMa = ages[n - 1];
|
|
69
|
+
// Central-difference tangents, deg per Ma (one-sided at the ends).
|
|
70
|
+
const m = new Float64Array(n);
|
|
71
|
+
m[0] = (eps[1] - eps[0]) / step;
|
|
72
|
+
for (let i = 1; i < n - 1; i++) m[i] = (eps[i + 1] - eps[i - 1]) / (2 * step);
|
|
73
|
+
m[n - 1] = (eps[n - 1] - eps[n - 2]) / step;
|
|
74
|
+
const cos0 = Math.cos(eps[0] * D2R);
|
|
75
|
+
|
|
76
|
+
/** @param {number} tMa @returns {number|null} the cited mean obliquity, degrees */
|
|
77
|
+
function meanObliquityDegAtAge(tMa) {
|
|
78
|
+
if (tMa <= 0) return eps[0] + m[0] * tMa; // forward: the J2000 slope held (labelled extrapolation)
|
|
79
|
+
if (tMa > spanMa) return null; // beyond the input: refused
|
|
80
|
+
const i = Math.min(Math.floor(tMa / step), n - 2);
|
|
81
|
+
const h = step, s = (tMa - ages[i]) / h, s2 = s * s, s3 = s2 * s;
|
|
82
|
+
return (2 * s3 - 3 * s2 + 1) * eps[i] + (s3 - 2 * s2 + s) * h * m[i]
|
|
83
|
+
+ (-2 * s3 + 3 * s2) * eps[i + 1] + (s3 - s2) * h * m[i + 1];
|
|
84
|
+
}
|
|
85
|
+
/** cos ε̄(t)/cos ε̄(0) — the factor the precession RATE of date carries on the precession constant. ≡ 1 at J2000.
|
|
86
|
+
* @param {number} tMa @returns {number|null} */
|
|
87
|
+
function cosRatioAtAge(tMa) {
|
|
88
|
+
const e = meanObliquityDegAtAge(tMa);
|
|
89
|
+
return e === null ? null : Math.cos(e * D2R) / cos0;
|
|
90
|
+
}
|
|
91
|
+
return { meanObliquityDegAtAge, cosRatioAtAge, meanObliquityJ2000Deg: eps[0], spanMa };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = { createMeanObliquityHistory };
|
|
@@ -13,6 +13,20 @@
|
|
|
13
13
|
* (1 − e²)^(−3/2) eccentricity factors and the lunar-inclination factor
|
|
14
14
|
* 1 − 3/2·sin² i_M; ≈ 0.316, the textbook value). At J2000 every factor is 1.
|
|
15
15
|
*
|
|
16
|
+
* THE RATE OF DATE vs THE CONSTANT (plan 12 §8, option (a)): the law above
|
|
17
|
+
* scales the precession CONSTANT α(t) ∝ ω(t)·[torque term] — the rate at the
|
|
18
|
+
* J2000 obliquity. The precession RATE is α(t)·cos ε̄(t), so the published
|
|
19
|
+
* rate carries one more factor, the cited mean obliquity's cos ε̄(t)/cos ε̄(0)
|
|
20
|
+
* (earth/mean-obliquity-history.cjs — Farhat 2022's own column, the second
|
|
21
|
+
* column read from the distance history; the chain had held cos ε̄ at J2000
|
|
22
|
+
* at every epoch). torqueRate… is the constant's scaling — what the hybrid
|
|
23
|
+
* obliquity integration takes, since its own ŝ·n̂ carries the cosine;
|
|
24
|
+
* composedRate… is the rate of date — T_p(t), the obliquity beat, the tropical
|
|
25
|
+
* year of date, the paleo referees' precession constant k. Both ≡ p₀ at J2000;
|
|
26
|
+
* the factor is 1 − 2e-7 at 10 kyr and 1.0245 at 2.46 Ga (the composed rate
|
|
27
|
+
* 106.6 → 109.2 ″/yr against Lantink 2022's 108.6 ± 8.5; Farhat's own
|
|
28
|
+
* precession column on the same table: 108.8).
|
|
29
|
+
*
|
|
16
30
|
* THE ANCHOR p₀ (plan 06 S5 — one J2000 precession reading): p₀ is the
|
|
17
31
|
* model's DERIVED J2000 rate, 1,296,000/axial0 with axial0 the certified
|
|
18
32
|
* year-length laws' beat at 2000 (sid/(sid − trop) = 25,771.4 yr = 50.2883
|
|
@@ -64,14 +78,20 @@ function computeSolarTorqueShare(c) {
|
|
|
64
78
|
* moonDistanceMetresAtAge: (tMa: number) => (number | null),
|
|
65
79
|
* moonDistanceJ2000Metres: number,
|
|
66
80
|
* yearToTMa: (year: number) => number,
|
|
81
|
+
* meanObliquityCosRatioAtAge?: (tMa: number) => (number | null),
|
|
67
82
|
* }} deps - p0 = the model's derived J2000 rate, 1,296,000/axial0 (S5; a
|
|
68
83
|
* number or a LAZY getter — the callers' certified year laws read the
|
|
69
84
|
* deep-time factory this is built inside, so the anchor is resolved on
|
|
70
85
|
* the first RATE use, never at construction; the torque term needs no
|
|
71
|
-
* anchor); lodJ2000Seconds the SAME day basis lodSecondsAtAge(0) returns
|
|
86
|
+
* anchor); lodJ2000Seconds the SAME day basis lodSecondsAtAge(0) returns;
|
|
87
|
+
* meanObliquityCosRatioAtAge the cited mean obliquity's cos ε̄(t)/cos ε̄(0)
|
|
88
|
+
* (OPTIONAL — absent, the rate of date is the constant alone, bit-identical).
|
|
72
89
|
* @returns {{
|
|
73
90
|
* composedRateArcsecPerYrAtAge: (tMa: number) => (number | null),
|
|
74
91
|
* composedPeriodYearsAtAge: (tMa: number) => (number | null),
|
|
92
|
+
* torqueRateArcsecPerYrAtAge: (tMa: number) => (number | null),
|
|
93
|
+
* torquePeriodYearsAtAge: (tMa: number) => (number | null),
|
|
94
|
+
* obliquityFactorAtAge: (tMa: number) => (number | null),
|
|
75
95
|
* composedRateArcsecPerYrAtYear: (year: number) => (number | null),
|
|
76
96
|
* composedPeriodYearsAtYear: (year: number) => (number | null),
|
|
77
97
|
* composedRateRatioAtAge: (tMa: number) => (number | null),
|
|
@@ -107,14 +127,37 @@ function createComposedPrecession(deps) {
|
|
|
107
127
|
const lf = lunarTorqueFactorAtAge(tMa);
|
|
108
128
|
return lf === null ? null : fS + (1 - fS) * lf;
|
|
109
129
|
};
|
|
110
|
-
/**
|
|
111
|
-
|
|
130
|
+
/** cos ε̄(t)/cos ε̄(0) from the cited mean obliquity — 1 when no history is
|
|
131
|
+
* injected (the constant alone, bit-identical). @param {number} tMa @returns {number|null} */
|
|
132
|
+
const cosRatio = deps.meanObliquityCosRatioAtAge;
|
|
133
|
+
/** @type {(tMa: number) => number|null} */
|
|
134
|
+
const obliquityFactorAtAge = cosRatio ? (tMa) => cosRatio(tMa) : () => 1;
|
|
135
|
+
/** THE PRECESSION CONSTANT OF DATE as a rate on the J2000 obliquity, ″/yr —
|
|
136
|
+
* [ω(t)/ω₀]·p₀·[f_S + (1 − f_S)(a₀/a_M)³] = α(t)·cos ε̄₀. The hybrid
|
|
137
|
+
* obliquity integration takes THIS: ds/dt = α(ŝ·n̂)(ŝ×n̂) carries its own cosine.
|
|
138
|
+
* @param {number} tMa */
|
|
139
|
+
const torqueRateArcsecPerYrAtAge = (tMa) => {
|
|
112
140
|
const lod = deps.lodSecondsAtAge(tMa);
|
|
113
141
|
const term = torqueTermAtAge(tMa);
|
|
114
142
|
if (lod === null || !(lod > 0) || term === null) return null;
|
|
115
143
|
return (deps.lodJ2000Seconds / lod) * p0() * term;
|
|
116
144
|
};
|
|
117
145
|
/** @param {number} tMa */
|
|
146
|
+
const torquePeriodYearsAtAge = (tMa) => {
|
|
147
|
+
const r = torqueRateArcsecPerYrAtAge(tMa);
|
|
148
|
+
return r === null ? null : 1296000 / r;
|
|
149
|
+
};
|
|
150
|
+
/** THE PRECESSION RATE OF DATE ψ̇(t), ″/yr — the constant × cos ε̄(t)/cos ε̄(0):
|
|
151
|
+
* the published rate (T_p(t) = 1,296,000/ψ̇, the obliquity beat, the tropical
|
|
152
|
+
* year of date, the paleo referees' precession constant k).
|
|
153
|
+
* @param {number} tMa */
|
|
154
|
+
const composedRateArcsecPerYrAtAge = (tMa) => {
|
|
155
|
+
const r = torqueRateArcsecPerYrAtAge(tMa);
|
|
156
|
+
if (r === null) return null;
|
|
157
|
+
const f = obliquityFactorAtAge(tMa);
|
|
158
|
+
return f === null ? null : r * f;
|
|
159
|
+
};
|
|
160
|
+
/** @param {number} tMa */
|
|
118
161
|
const composedPeriodYearsAtAge = (tMa) => {
|
|
119
162
|
const r = composedRateArcsecPerYrAtAge(tMa);
|
|
120
163
|
return r === null ? null : 1296000 / r;
|
|
@@ -134,6 +177,9 @@ function createComposedPrecession(deps) {
|
|
|
134
177
|
composedRateArcsecPerYrAtYear: (year) => composedRateArcsecPerYrAtAge(deps.yearToTMa(year)),
|
|
135
178
|
composedPeriodYearsAtYear: (year) => composedPeriodYearsAtAge(deps.yearToTMa(year)),
|
|
136
179
|
composedRateRatioAtAge,
|
|
180
|
+
torqueRateArcsecPerYrAtAge,
|
|
181
|
+
torquePeriodYearsAtAge,
|
|
182
|
+
obliquityFactorAtAge,
|
|
137
183
|
torqueTermAtAge,
|
|
138
184
|
lunarTorqueFactorAtAge,
|
|
139
185
|
solarShare: fS,
|
package/src/index.js
CHANGED
|
@@ -106,6 +106,20 @@ export { createDerivedViews } from './layer1/index.js';
|
|
|
106
106
|
// file via the exports-map subpath; re-exported here so bundled ESM
|
|
107
107
|
// consumers need only the package root.
|
|
108
108
|
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.
|
|
112
|
+
export { GREGORIAN_START, GREGORIAN_START_JD, calendarToJD, jdToCalendar, jdToDecimalYear, dayFractionToHMS, julianCalendarToJD, jdToJulianCalendar } from './time/calendar.cjs';
|
|
113
|
+
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.
|
|
118
|
+
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.
|
|
121
|
+
export { computeMassChainJ2000, computeMoonPeriodsJ2000 } from './earth/mass-chain.cjs';
|
|
122
|
+
export { SECONDS_PER_DAY, DAYS_PER_JULIAN_YEAR, JULIAN_CENTURY_DAYS, SECONDS_PER_JULIAN_YEAR } from './constants/units.cjs';
|
|
109
123
|
// D4b: the one-source cardinal structure — the EoC layer (year lengths,
|
|
110
124
|
// crossing offsets, the e(t)-proportional spread) on the movement's own
|
|
111
125
|
// e(t)/ϖ(t). Absolute dates deliberately excluded (per-renderer mean chain).
|
|
@@ -156,6 +170,9 @@ export { createYearLengths, computeMeanTropicalYearJ2000Days, ONE_FAMILY_WINDOW_
|
|
|
156
170
|
// (spin ω(t) × [solar torque + lunar torque on the recession history]) —
|
|
157
171
|
// leg-1's physical rate; the structural H(t)/13 clock is its named diagnostic.
|
|
158
172
|
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.
|
|
175
|
+
export { createMeanObliquityHistory } from './earth/mean-obliquity-history.cjs';
|
|
159
176
|
// (planets/predict.cjs — the planet predictive-precession feature basis — was
|
|
160
177
|
// retired at plan 06 R8 with PREDICT_COEFFS_PHYSICAL.)
|
|
161
178
|
// L10 — the composition front door: one law set, N body records. Thin by
|
package/src/layer0/index.js
CHANGED
|
@@ -54,18 +54,21 @@
|
|
|
54
54
|
* @property {(year: number) => number|null} moonDistanceMetres - null beyond the cited history's span
|
|
55
55
|
* @property {(year: number) => number|null} lodSeconds
|
|
56
56
|
* @property {(year: number) => number} siderealYearSeconds
|
|
57
|
-
* @property {(year: number) => number} tropicalYearSeconds sidereal less one equinox turn per T_p(t) (the composed precession period)
|
|
57
|
+
* @property {(year: number) => number} tropicalYearSeconds sidereal less one equinox turn per T_p(t) (the composed precession period on the RATE of date)
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* @param {{params: EpochParams, alphaAtAgeMa: (tMa: number) => number,
|
|
62
|
-
* moonDistanceMetresAtAge: (tMa: number) => number|null
|
|
62
|
+
* moonDistanceMetresAtAge: (tMa: number) => number|null,
|
|
63
|
+
* meanObliquityCosRatioAtAge?: (tMa: number) => number|null}} deps —
|
|
63
64
|
* moonDistanceMetresAtAge is the engine's cited distance history
|
|
64
65
|
* (deltat/moon-distance-history: Farhat et al. 2022 as a shape on the
|
|
65
|
-
* J2000 anchor; plan 12 option A — the layer0 quartic twin is deleted)
|
|
66
|
+
* J2000 anchor; plan 12 option A — the layer0 quartic twin is deleted);
|
|
67
|
+
* meanObliquityCosRatioAtAge the cited mean obliquity's cos ε̄(t)/cos ε̄(0)
|
|
68
|
+
* (earth/mean-obliquity-history, plan 12 §8 option (a)) — OPTIONAL, absent → 1.
|
|
66
69
|
* @returns {EpochPrimitives}
|
|
67
70
|
*/
|
|
68
|
-
export const createEpochPrimitives = ({ params: p, alphaAtAgeMa, moonDistanceMetresAtAge }) => {
|
|
71
|
+
export const createEpochPrimitives = ({ params: p, alphaAtAgeMa, moonDistanceMetresAtAge, meanObliquityCosRatioAtAge }) => {
|
|
69
72
|
/**
|
|
70
73
|
* Years before the epoch, in Ma. The ONE place this conversion lives.
|
|
71
74
|
* @param {number} year
|
|
@@ -80,6 +83,14 @@ export const createEpochPrimitives = ({ params: p, alphaAtAgeMa, moonDistanceMet
|
|
|
80
83
|
*/
|
|
81
84
|
const moonDistanceMetresCore = (t) => moonDistanceMetresAtAge(t);
|
|
82
85
|
|
|
86
|
+
/**
|
|
87
|
+
* cos ε̄(t)/cos ε̄(0) of the cited mean obliquity — the precession RATE's
|
|
88
|
+
* factor on the constant (plan 12 §8); 1 when no history is injected.
|
|
89
|
+
* @param {number} t age in Ma
|
|
90
|
+
* @returns {number|null}
|
|
91
|
+
*/
|
|
92
|
+
const meanObliquityCosRatioCore = (t) => (meanObliquityCosRatioAtAge ? meanObliquityCosRatioAtAge(t) : 1);
|
|
93
|
+
|
|
83
94
|
/**
|
|
84
95
|
* Length of day from angular-momentum conservation: as the Moon recedes it
|
|
85
96
|
* takes orbital angular momentum and Earth's spin slows to compensate.
|
|
@@ -122,7 +133,9 @@ export const createEpochPrimitives = ({ params: p, alphaAtAgeMa, moonDistanceMet
|
|
|
122
133
|
* Tropical year of date — the sidereal year less the equinox's own motion
|
|
123
134
|
* over one year: one turn per the composed lunisolar precession period
|
|
124
135
|
* T_p(t), i.e. 1/T_trop = 1/T_sid + ψ̇(t)/(1,296,000″ · Julian-year s) with
|
|
125
|
-
* ψ̇(t)
|
|
136
|
+
* ψ̇(t) the RATE of date, spelled as (LOD₀/LOD(t))·p₀·[f_S + (1 − f_S)(a₀/a_M)³]
|
|
137
|
+
* × cos ε̄(t)/cos ε̄(0) — the cited mean obliquity's factor (plan 12 §8 option (a);
|
|
138
|
+
* injected, 1 when absent).
|
|
126
139
|
* Plan 09 step 5d: it was the unit's calendar convention sid·(1 − 13/H(t))
|
|
127
140
|
* (plan 06 D2 kept it as a named device), 0.086 % slow on the equinox term
|
|
128
141
|
* — 1.0 s of year at J2000, integrated by the deep JD↔year calendar. The
|
|
@@ -142,7 +155,8 @@ export const createEpochPrimitives = ({ params: p, alphaAtAgeMa, moonDistanceMet
|
|
|
142
155
|
const lf = (a === null || !(a > 0)) ? null : Math.pow(p.moonDistanceNowM / a, 3);
|
|
143
156
|
const term = lf === null ? null : p.precessionSolarShareJ2000 + (1 - p.precessionSolarShareJ2000) * lf;
|
|
144
157
|
const p0 = p.precessionRateJ2000ArcsecPerYr;
|
|
145
|
-
const
|
|
158
|
+
const f = meanObliquityCosRatioCore(t);
|
|
159
|
+
const rate = (lod === null || !(lod > 0) || term === null || f === null) ? p0 : (p.lodNowH13Seconds / lod) * p0 * term * f;
|
|
146
160
|
return 1 / (1 / sid + rate / (1296000 * 365.25 * 86400));
|
|
147
161
|
};
|
|
148
162
|
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Angles — ONE home for the degree ↔ radian constants and the wraps
|
|
3
|
+
* (holisticuniverse plan 13 B1). Before B1 the browser carried 27 local
|
|
4
|
+
* `D2R`-style constants and twelve local wrap helpers in three ±180 forms;
|
|
5
|
+
* the package itself a dozen private `D2R`s.
|
|
6
|
+
*
|
|
7
|
+
* The two ±180 forms in use differ only AT the boundary: `wrap180` maps
|
|
8
|
+
* +180 to −180 (the half-open [−180, 180) the longitude-difference sites
|
|
9
|
+
* use), `wrap180Closed` keeps +180 (the (−180, 180] of the residual
|
|
10
|
+
* printers). A site keeps the form it had — B1 moves the formula, never
|
|
11
|
+
* the convention.
|
|
12
|
+
*
|
|
13
|
+
* Pure, no model dependencies.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
/** π/180 — degrees to radians. */
|
|
19
|
+
const DEG2RAD = Math.PI / 180;
|
|
20
|
+
/** 180/π — radians to degrees. */
|
|
21
|
+
const RAD2DEG = 180 / Math.PI;
|
|
22
|
+
/** Arcseconds in a full turn. */
|
|
23
|
+
const ARCSEC_PER_TURN = 1296000;
|
|
24
|
+
/** Arcseconds per radian, 206264.806… */
|
|
25
|
+
const ARCSEC_PER_RAD = (180 / Math.PI) * 3600;
|
|
26
|
+
|
|
27
|
+
/** @param {number} x degrees @returns {number} the same angle in [0, 360) */
|
|
28
|
+
const wrap360 = (x) => ((x % 360) + 360) % 360;
|
|
29
|
+
/** @param {number} x degrees @returns {number} the same angle in [−180, 180) */
|
|
30
|
+
const wrap180 = (x) => ((x + 540) % 360 + 360) % 360 - 180;
|
|
31
|
+
/** @param {number} x degrees @returns {number} the same angle in (−180, 180] */
|
|
32
|
+
const wrap180Closed = (x) => { const w = ((x % 360) + 360) % 360; return w > 180 ? w - 360 : w; };
|
|
33
|
+
/** @param {number} x radians @returns {number} the same angle in [0, 2π) */
|
|
34
|
+
const wrap2pi = (x) => { const tau = 2 * Math.PI; return ((x % tau) + tau) % tau; };
|
|
35
|
+
/** @param {number} x radians @returns {number} the same angle in [−π, π) */
|
|
36
|
+
const wrapPi = (x) => { const tau = 2 * Math.PI; return ((x + Math.PI) % tau + tau) % tau - Math.PI; };
|
|
37
|
+
|
|
38
|
+
module.exports = { DEG2RAD, RAD2DEG, ARCSEC_PER_TURN, ARCSEC_PER_RAD, wrap360, wrap180, wrap180Closed, wrap2pi, wrapPi };
|