@essrt/physics 7.0.0 → 9.1.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 +2 -2
- package/package.json +4 -2
- package/src/constants/coefficients.d.ts +1 -38
- package/src/constants/coefficients.js +2 -5
- package/src/constants/generated.d.ts +109 -25
- package/src/constants/generated.js +226 -96
- package/src/earth/deep-orbital-history.cjs +10 -0
- package/src/earth/frame-of-date.cjs +105 -0
- package/src/eclipse/besselian.cjs +41 -17
- package/src/eclipse/sun-planetary-completion.cjs +55 -14
- package/src/index.js +9 -1
- package/src/model.js +262 -124
- package/src/moon/apparent.cjs +45 -126
- package/src/moon/deep-ecc-channel.cjs +59 -12
- package/src/moon/deep-modes-artifact.cjs +4 -2
- package/src/moon/month-chain.cjs +21 -10
- package/src/moon/series-extension.cjs +2 -1
- package/src/moon/series.cjs +21 -4
- package/src/planets/chain-artifact.js +2 -2
- package/src/planets/fibonacci-laws.cjs +7 -42
- package/src/planets/model.cjs +10 -13
- package/src/planets/secular-shape.cjs +36 -0
- package/src/planets/spin-channel.cjs +391 -0
- package/types/constants/coefficients.d.ts +1 -38
- package/types/constants/generated.d.ts +109 -25
- package/types/earth/deep-orbital-history.d.cts +2 -0
- package/types/earth/frame-of-date.d.cts +37 -0
- package/types/eclipse/besselian.d.cts +5 -7
- package/types/eclipse/sun-planetary-completion.d.cts +14 -10
- package/types/index.d.ts +3 -1
- package/types/model.d.ts +26 -0
- package/types/moon/apparent.d.cts +7 -68
- package/types/moon/deep-ecc-channel.d.cts +31 -2
- package/types/moon/deep-modes-artifact.d.cts +2 -0
- package/types/moon/month-chain.d.cts +4 -0
- package/types/planets/fibonacci-laws.d.cts +0 -29
- package/types/planets/model.d.cts +10 -4
- package/types/planets/secular-shape.d.cts +30 -0
- package/types/planets/spin-channel.d.cts +193 -0
- package/src/planets/predict.cjs +0 -324
- package/types/planets/predict.d.cts +0 -88
package/src/model.js
CHANGED
|
@@ -21,11 +21,12 @@ import { deriveEpochParams } from './layer0/derive-params.js';
|
|
|
21
21
|
import * as FL from './planets/fibonacci-laws.cjs';
|
|
22
22
|
import * as planetOrientation from './planets/orientation.cjs';
|
|
23
23
|
import { createPhaseMachinery } from './phase/index.cjs';
|
|
24
|
-
import { createCardinalModel } from './cardinal/index.cjs';
|
|
25
24
|
import { createYearLengths, ONE_FAMILY_WINDOW_YEARS } from './earth/year-lengths.cjs';
|
|
26
25
|
import { createDeepOrbitalHistory } from './earth/deep-orbital-history.cjs';
|
|
27
26
|
import { CHAIN_ARTIFACT } from './planets/chain-artifact.js';
|
|
28
27
|
import { buildPlanetChainsFromArtifactData, computeApsidalSecularDegPerYr } from './planets/keplerian-chain.cjs';
|
|
28
|
+
import { computeSecularShape } from './planets/secular-shape.cjs';
|
|
29
|
+
import { createPlanetSpinChannelFromArtifacts, computeObliquityJ2000Deg } from './planets/spin-channel.cjs';
|
|
29
30
|
import { createDeltaTCycles } from './deltat/cycles.cjs';
|
|
30
31
|
import { createDeepTimeLod } from './deltat/deep-time.cjs';
|
|
31
32
|
import { createMoonRecessionHistory, createSolarChannelBudget } from './deltat/recession-history.cjs';
|
|
@@ -37,7 +38,6 @@ import { createChainCycleIntegrator } from './chain-cycles/index.cjs';
|
|
|
37
38
|
import { createMoonArguments, jdToDecimalYear } from './moon/arguments.cjs';
|
|
38
39
|
import { createMoonSeries } from './moon/series.cjs';
|
|
39
40
|
import { createSunPlanetaryCompletion } from './eclipse/sun-planetary-completion.cjs';
|
|
40
|
-
import { moonSeriesExtensionDeg } from './moon/series-extension.cjs';
|
|
41
41
|
import { createEclipseFinders } from './eclipse/finders.cjs';
|
|
42
42
|
import { createBesselian } from './eclipse/besselian.cjs';
|
|
43
43
|
import { driver2PeriodSecondsAtAge } from './planets/orbit-chain.cjs';
|
|
@@ -102,7 +102,6 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
102
102
|
// wobble-marker distance). It is the K calibration input ONLY — Earth's
|
|
103
103
|
// eccentricity law does not use it; see eccentricityAt (base' derived) below.
|
|
104
104
|
const eccentricityAmplitude = C.earth.eccentricityAmplitude;
|
|
105
|
-
const earthRAAngle = 2 * earthInclAmplitude - (earthInclAmplitude * earthInclAmplitude) / earthtiltMean;
|
|
106
105
|
const earthInclMean = C.earthOrbital.earthInclinationJ2000_deg
|
|
107
106
|
- earthInclAmplitude * Math.cos(((C.earthOrbital.earthPerihelionLongitudeJ2000
|
|
108
107
|
- C.earthOrbital.earthInclinationCycleAnchor) * Math.PI) / 180);
|
|
@@ -426,7 +425,6 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
426
425
|
/** de/dyear of the Sun's e — the cardinal braid's equation-of-centre
|
|
427
426
|
* derivative rides it (±0.5-yr central difference; the constant offset
|
|
428
427
|
* cancels). @param {number} year @returns {number} */
|
|
429
|
-
const sunEccentricityRateAt = laws.eccentricityRateAt ?? ((year) => oneSourceM.eAt(year + 0.5) - oneSourceM.eAt(year - 0.5));
|
|
430
428
|
/** @param {number} year @returns {number} */
|
|
431
429
|
const inclinationDeg = (year) => earthInclMean
|
|
432
430
|
- earthInclAmplitude * Math.cos(phaseRadians(balancedYear, year, 3));
|
|
@@ -502,39 +500,13 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
502
500
|
+ RA_DAY_OFFSET_ECC_MS * Math.cos(phaseRadians(balancedYear, year, 16))
|
|
503
501
|
+ RA_DAY_OFFSET_OBLIQ_MS * Math.cos(phaseRadians(balancedYear, year, 8));
|
|
504
502
|
|
|
505
|
-
// ── Cardinal
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
jointTerms: F.CARDINAL_POINT_JOINT_TERMS,
|
|
513
|
-
derived: F.CARDINAL_POINT_DERIVED,
|
|
514
|
-
tropicalHarmonics: F.TROPICAL_YEAR_HARMONICS,
|
|
515
|
-
balancedYear,
|
|
516
|
-
meanSolarYearDays,
|
|
517
|
-
hJ2000: H,
|
|
518
|
-
tiltMeanDeg: earthtiltMean,
|
|
519
|
-
raAngleDeg: earthRAAngle,
|
|
520
|
-
inclAmplitudeDeg: earthInclAmplitude,
|
|
521
|
-
},
|
|
522
|
-
fns: {
|
|
523
|
-
cyclesBetween: (a, b, n) => phase().cyclesBetween(a, b, n),
|
|
524
|
-
// The frozen era clock's deps ride ITS convention H_era (plan 06 D8):
|
|
525
|
-
// drift integrand, dc/dY and the real-LOD convention were fitted on it.
|
|
526
|
-
analyticTropicalDays: (year) => {
|
|
527
|
-
const tMa = (startmodelYear - year) / 1e6;
|
|
528
|
-
const Ht = deepLod.eraClockHAtAge(tMa);
|
|
529
|
-
if (Ht === null) return null;
|
|
530
|
-
return (deepLod.siderealYearSecondsAtAge(tMa) / 86400) * (1 - 13 / Ht);
|
|
531
|
-
},
|
|
532
|
-
meanHAtAgeMa: (tMa) => deepLod.eraClockHAtAge(tMa),
|
|
533
|
-
meanYearRealLodDays: (tMa) => deepLod.eraClockYearInDaysAtAge(tMa),
|
|
534
|
-
eccentricityAt: sunEccentricityAt,
|
|
535
|
-
eccentricityRateAt: sunEccentricityRateAt,
|
|
536
|
-
},
|
|
537
|
-
});
|
|
503
|
+
// ── Cardinal points (the fitted model retired, R1)──────────────────────────────────────────────────
|
|
504
|
+
// Plan 06 R1: the fitted cardinal-point model (CARDINAL_POINT_* — the §10
|
|
505
|
+
// derived form on the frozen era clock, fitted to the retired K scene's
|
|
506
|
+
// events; measured 60–140 min from Meeus ch. 27 at 0..−1000 and 6–25 min
|
|
507
|
+
// in 1500–2900) left this package. The instants are the CROSSINGS of the
|
|
508
|
+
// one Sun the scene renders and the eclipse chain certifies — see
|
|
509
|
+
// `cardinalCrossingJdUT` below the finders.
|
|
538
510
|
// ── One-source cardinal structure (D4b) ───────────────────────────────────
|
|
539
511
|
// The EoC layer (year lengths, crossing offsets, the e(t)-proportional
|
|
540
512
|
// spread) on the one-source movement's own e(t)/ϖ(t) — the MODE tier (the
|
|
@@ -646,9 +618,19 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
646
618
|
};
|
|
647
619
|
})();
|
|
648
620
|
const yearLengthsM = oneSourceM.yearLengths;
|
|
621
|
+
/** THE one-family tropical year of date in SI seconds: route B inside the
|
|
622
|
+
* one-family window, the tidal-chain year beyond (plan 06 R1 — the Sun's
|
|
623
|
+
* mean longitude, the cardinal instants and the published year lengths
|
|
624
|
+
* all ride this one function). @param {number} year @returns {number} */
|
|
625
|
+
const oneFamilyTropicalYearSeconds = (year) => (Math.abs(year - 2000) <= ONE_FAMILY_WINDOW_YEARS
|
|
626
|
+
? yearLengthsM.tropicalYearSecondsAtYear(year)
|
|
627
|
+
: (deepLod.tropicalYearSecondsAtAge(yearToTMa(year)) ?? meanSolarYearDays * 86400));
|
|
649
628
|
|
|
650
|
-
/** Tropical year
|
|
651
|
-
|
|
629
|
+
/** Tropical year of date in DAYS OF THE EPOCH (the kinematic day below) —
|
|
630
|
+
* the one-family SI year over the epoch's day length, so solarYearSeconds
|
|
631
|
+
* ≡ the one-family year. Plan 06 R1: formerly the fitted cardinal model's
|
|
632
|
+
* 4-mean. @param {number} year @returns {number} */
|
|
633
|
+
const tropicalYearDays = (year) => oneFamilyTropicalYearSeconds(year) / dayLengthSeconds(year);
|
|
652
634
|
/** @param {number} year @returns {number} */
|
|
653
635
|
const tropicalYearDirectDays = (year) => evalYearFourier(year, tropicalYearDaysBase(year), F.TROPICAL_YEAR_HARMONICS);
|
|
654
636
|
|
|
@@ -737,10 +719,13 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
737
719
|
const mp = C.planets[k];
|
|
738
720
|
const ar = C.planetOrbitalElements[k];
|
|
739
721
|
const ecl = /** @type {number} */ (fractionToYears(mp.perihelionEclipticFraction));
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
722
|
+
// Plan 06 Phase 7 commit 2: the K device's integer axial and obliquity
|
|
723
|
+
// fractions are retired. The eccentricity law's cycle period is the
|
|
724
|
+
// chain's OWN g-mode beat (the dominant mode × largest companion of the
|
|
725
|
+
// planet's eccentricity vector), its obliquity input the DERIVED J2000
|
|
726
|
+
// obliquity of the spin channel (the IAU pole against the chain's J2000
|
|
727
|
+
// plane, acute form) — both from the governed artifacts, no fractions.
|
|
728
|
+
const wobble = computeSecularShape(/** @type {any} */ (CHAIN_ARTIFACT), k).beatYears;
|
|
744
729
|
const il = FL.computeInclinationLaw({
|
|
745
730
|
fibonacciD: mp.fibonacciD,
|
|
746
731
|
massFrac: massFraction[k],
|
|
@@ -749,11 +734,13 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
749
734
|
inclinationCycleAnchor: mp.inclinationCycleAnchor,
|
|
750
735
|
antiPhase: mp.antiPhase || false,
|
|
751
736
|
}, PSI);
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
737
|
+
const obliquityDerived = computeObliquityJ2000Deg({
|
|
738
|
+
spin: C.planetSpinPhysical[k],
|
|
739
|
+
anchorInclEclipticDeg: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements[k].inclEclipticDeg,
|
|
740
|
+
anchorAscNodeEclipticDeg: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements[k].ascNodeEclipticDeg,
|
|
741
|
+
obliquityJ2000Deg: C.earthOrbital.obliquityJ2000_deg,
|
|
742
|
+
});
|
|
743
|
+
const obliquityMean = Math.min(obliquityDerived, 180 - obliquityDerived); // acute: the K law reads sin|ε|
|
|
757
744
|
const el = FL.computeEccentricityLaw({
|
|
758
745
|
fibonacciD: mp.fibonacciD,
|
|
759
746
|
massFrac: massFraction[k],
|
|
@@ -773,8 +760,6 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
773
760
|
longitudePerihelion: ar.longitudePerihelion,
|
|
774
761
|
ascendingNodeCyclesIn8H: mp.ascendingNodeCyclesIn8H,
|
|
775
762
|
ascendingNodePeriod: -(8 * H) / mp.ascendingNodeCyclesIn8H,
|
|
776
|
-
axialPrecessionYears: axial,
|
|
777
|
-
obliquityCycle,
|
|
778
763
|
wobblePeriod: wobble,
|
|
779
764
|
fibonacciD: mp.fibonacciD,
|
|
780
765
|
antiPhase: mp.antiPhase || false,
|
|
@@ -793,6 +778,32 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
793
778
|
});
|
|
794
779
|
}
|
|
795
780
|
|
|
781
|
+
// ── The planets' spin channel (plan 06 Phase 7): the precession constant
|
|
782
|
+
// from each planet's OWN torques (astro-reference planetSpinPhysical) on the
|
|
783
|
+
// model's OWN orbit — the chain's J2000 a/e/plane and the deep ζ table —
|
|
784
|
+
// integrated as dŝ/dt = α(ŝ·n̂)(ŝ×n̂) from the IAU J2000 pole. ONE home:
|
|
785
|
+
// planets/spin-channel.cjs; built lazily per planet, pure in `year`.
|
|
786
|
+
/** @type {Map<string, ReturnType<typeof createPlanetSpinChannelFromArtifacts>>} */
|
|
787
|
+
const spinChannels = new Map();
|
|
788
|
+
/** @param {string} k */
|
|
789
|
+
const planetSpin = (k) => {
|
|
790
|
+
if (!PLANET_KEYS.includes(k)) throw new Error(`planets.spin: unknown planet '${k}'`);
|
|
791
|
+
let ch = spinChannels.get(k);
|
|
792
|
+
if (!ch) {
|
|
793
|
+
ch = createPlanetSpinChannelFromArtifacts({
|
|
794
|
+
key: k,
|
|
795
|
+
planetSpinPhysical: C.planetSpinPhysical,
|
|
796
|
+
chainAnchorElements: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements,
|
|
797
|
+
planetZeta: /** @type {any} */ (DEEP_MODES_ARTIFACT).planetZeta,
|
|
798
|
+
massFractionOfSun: massFraction[k],
|
|
799
|
+
gmSunKm3S2: GM_SUN,
|
|
800
|
+
obliquityJ2000Deg: C.earthOrbital.obliquityJ2000_deg,
|
|
801
|
+
});
|
|
802
|
+
spinChannels.set(k, ch);
|
|
803
|
+
}
|
|
804
|
+
return ch;
|
|
805
|
+
};
|
|
806
|
+
|
|
796
807
|
/** Perihelion longitude (linear lattice rate). @param {string} k @param {number} year @returns {number} */
|
|
797
808
|
const planetPerihelionDeg = (k, year) => {
|
|
798
809
|
const p = PLANET_RECORDS[k];
|
|
@@ -858,6 +869,10 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
858
869
|
const nNodalEJ2000 = nNodalIJ2000 + 13;
|
|
859
870
|
const moonApsidalJ2000Seconds = (totalDaysInH / nApsidalEJ2000) * meanLengthOfDay;
|
|
860
871
|
const moonNodalJ2000Seconds = (totalDaysInH / nNodalEJ2000) * meanLengthOfDay;
|
|
872
|
+
// the OF-DATE anchors (the H² counter's J2000 period — the Meeus/IERS
|
|
873
|
+
// observables 3231.49 d / 6798.38 d)
|
|
874
|
+
const moonApsidalOfDateJ2000Seconds = (totalDaysInH / nApsidalIJ2000) * meanLengthOfDay;
|
|
875
|
+
const moonNodalOfDateJ2000Seconds = (totalDaysInH / nNodalIJ2000) * meanLengthOfDay;
|
|
861
876
|
const moonSiderealMonthJ2000Seconds = moonSiderealMonth * meanLengthOfDay;
|
|
862
877
|
|
|
863
878
|
// 8H-lattice derived months (constants.js §Moon derived months)
|
|
@@ -887,6 +902,8 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
887
902
|
nNodalOfDateJ2000: nNodalIJ2000,
|
|
888
903
|
moonApsidalJ2000Seconds,
|
|
889
904
|
moonNodalJ2000Seconds,
|
|
905
|
+
moonApsidalOfDateJ2000Seconds,
|
|
906
|
+
moonNodalOfDateJ2000Seconds,
|
|
890
907
|
moonSiderealMonthJ2000Seconds,
|
|
891
908
|
sPerigee: MOON_ECC_SENSITIVITY_PERIGEE,
|
|
892
909
|
sNode: MOON_ECC_SENSITIVITY_NODE,
|
|
@@ -1113,65 +1130,73 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
1113
1130
|
// same movement and is retired by the unification (measured identical on
|
|
1114
1131
|
// every modern gate).
|
|
1115
1132
|
const sunMeanLongitudeDegAt = (() => {
|
|
1116
|
-
//
|
|
1117
|
-
//
|
|
1118
|
-
//
|
|
1119
|
-
//
|
|
1120
|
-
//
|
|
1121
|
-
//
|
|
1122
|
-
//
|
|
1123
|
-
//
|
|
1124
|
-
//
|
|
1125
|
-
//
|
|
1126
|
-
//
|
|
1127
|
-
//
|
|
1128
|
-
//
|
|
1129
|
-
//
|
|
1130
|
-
//
|
|
1131
|
-
//
|
|
1132
|
-
//
|
|
1133
|
-
//
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1133
|
+
// Plan 06 R1 — the Sun's mean longitude of date is the INTEGRAL of the
|
|
1134
|
+
// one-source tropical year: L(t) = L0 + 360·∫_{2000}^{t} dt′/T_trop(t′),
|
|
1135
|
+
// T_trop the route-B tropical year of date in SI seconds (the ONE
|
|
1136
|
+
// year-length family; the frozen era clock's tropicalYearDaysBase × LOD
|
|
1137
|
+
// and its comb ripple + torque term left here). MEASURED before the
|
|
1138
|
+
// move (tools/explore r1 probes, plan 06 record): the route-B tropical
|
|
1139
|
+
// year equals the IAU/Laskar drift expression to 0.1 s over −1000..+3000
|
|
1140
|
+
// while the era-clock year carried NO secular drift (+1.09 s flat), so
|
|
1141
|
+
// the former mean longitude wandered +12 min around 500 AD and diverged
|
|
1142
|
+
// −3.3 min/cy after 2100 against both Meeus ch. 27 and the one-source
|
|
1143
|
+
// integral — outside every eclipse and JPL gate. MODERN-WINDOW COST,
|
|
1144
|
+
// stated (plan 06 I1 corrected an earlier misreading of the cache's
|
|
1145
|
+
// clock): against the JPL Sun cache (UT instants, verified; the registry
|
|
1146
|
+
// instrument's bridge) the one-source Sun read 1.29″ sd in 1970–2049
|
|
1147
|
+
// where the era-clock Sun read 0.80″ — both carried ~0.02–0.03″/yr
|
|
1148
|
+
// trends against JPL over 1900–2100; accepted because over millennia
|
|
1149
|
+
// the era-clock Sun is minutes off. Plan 06 I2 located the trend: the
|
|
1150
|
+
// Earth–Mars–Jupiter long inequality (1783 yr, 6.3″) the smooth year
|
|
1151
|
+
// cannot carry — derived on the model's own N-body and shipped in the
|
|
1152
|
+
// planetary completion, the instrument reads 1.03″ (Horizons ±3000 yr:
|
|
1153
|
+
// modern-window mean +8.4 → +0.8″, per-millennium sd roughly halved).
|
|
1154
|
+
// NUMERICS (rate vs point value): a cumulative trapezoid table of
|
|
1155
|
+
// cycles, yearly inside ±20,000 yr and per century beyond, grown on
|
|
1156
|
+
// demand from 2000 in both directions and interpolated inside a cell —
|
|
1157
|
+
// never a rate multiplied by a span. Beyond the one-family window the
|
|
1158
|
+
// tidal-chain year continues the integrand (the scene overlay ends at
|
|
1159
|
+
// 20,000 yr; the finders refuse out-of-domain epochs upstream).
|
|
1160
|
+
const JULIAN_YEAR_S = 365.25 * 86400;
|
|
1161
|
+
const tropSec = oneFamilyTropicalYearSeconds;
|
|
1162
|
+
const FINE_SPAN = 20000, COARSE_STEP = 100;
|
|
1163
|
+
/** cycles from 2000 to 2000 ± i·step (fwd/bwd tiers) */
|
|
1164
|
+
/** @type {number[]} */ const fwdFine = [0];
|
|
1165
|
+
/** @type {number[]} */ const bwdFine = [0];
|
|
1166
|
+
/** @type {number[]} */ const fwdCoarse = [];
|
|
1167
|
+
/** @type {number[]} */ const bwdCoarse = [];
|
|
1168
|
+
/** UNSIGNED trapezoid cycles over the span between two years (Julian
|
|
1169
|
+
* years → SI seconds over the one-family year); the caller applies the
|
|
1170
|
+
* direction sign. @param {number} ya @param {number} yb @returns {number} */
|
|
1171
|
+
const segAbs = (ya, yb) => 0.5 * (Math.abs(yb - ya) * JULIAN_YEAR_S) * (1 / tropSec(ya) + 1 / tropSec(yb));
|
|
1172
|
+
/** signed cycles from 2000 to `year` @param {number} year @returns {number} */
|
|
1173
|
+
const cyclesTo = (year) => {
|
|
1151
1174
|
const dy = year - 2000;
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
//
|
|
1155
|
-
//
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1175
|
+
const s = dy >= 0 ? 1 : -1, a = Math.abs(dy);
|
|
1176
|
+
// WARM THE SAMPLER TO THE TARGET FIRST (plan 06 R4, measured): the
|
|
1177
|
+
// table below grows outward in 1-yr / 100-yr steps, and every step
|
|
1178
|
+
// beyond ~1.6 Myr enlarged the one-family sampler's >2-Myr tier just
|
|
1179
|
+
// past its span, rebuilding the whole deep integration about every 32
|
|
1180
|
+
// steps — ~125 rebuilds and 22 s for the first deep-epoch call (the
|
|
1181
|
+
// scene's first jump to −5 Myr), 0.4 ms once built. One read at the
|
|
1182
|
+
// clamped target builds the tier at its final span; the grid stores
|
|
1183
|
+
// are endpoint-independent, so every value is bit-identical.
|
|
1184
|
+
tropSec(2000 + s * Math.min(a, ONE_FAMILY_WINDOW_YEARS));
|
|
1185
|
+
const fine = s > 0 ? fwdFine : bwdFine;
|
|
1186
|
+
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)); } };
|
|
1187
|
+
if (a <= FINE_SPAN) {
|
|
1188
|
+
const i = Math.floor(a), f = a - i;
|
|
1189
|
+
growFine(i + 1);
|
|
1190
|
+
return fine[i] + f * (fine[i + 1] - fine[i]);
|
|
1164
1191
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
drift += scale * ((Math.sin(ph) - Math.sin(ph0)) - Math.cos(ph0) * Math.sin(ph - ph0));
|
|
1172
|
-
}
|
|
1173
|
-
return sunL0Deg + sunTropicalRateDegPerCy * dy / 100 + drift;
|
|
1192
|
+
growFine(FINE_SPAN);
|
|
1193
|
+
const coarse = s > 0 ? fwdCoarse : bwdCoarse;
|
|
1194
|
+
if (coarse.length === 0) coarse.push(fine[FINE_SPAN]);
|
|
1195
|
+
const c = (a - FINE_SPAN) / COARSE_STEP, ci = Math.floor(c), cf = c - ci;
|
|
1196
|
+
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)); }
|
|
1197
|
+
return coarse[ci] + cf * (coarse[ci + 1] - coarse[ci]);
|
|
1174
1198
|
};
|
|
1199
|
+
return /** @param {number} year @returns {number} */ (year) => sunL0Deg + 360 * cyclesTo(year);
|
|
1175
1200
|
})();
|
|
1176
1201
|
|
|
1177
1202
|
// Eclipse finders — wired like the engine probe (tools/verify/
|
|
@@ -1213,20 +1238,34 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
1213
1238
|
// μ = 1/(1+M_E/M_M) — 6.4399″ at current constants, tracks them live.
|
|
1214
1239
|
const embWobbleArcsec = (moonDistanceKm / (MASS_RATIO_EARTH_MOON + 1) / currentAUDistance)
|
|
1215
1240
|
* (648000 / Math.PI);
|
|
1216
|
-
// FQ-5 N3 — the completion's carriers are FRAMEWORK-derived
|
|
1217
|
-
//
|
|
1218
|
-
//
|
|
1219
|
-
//
|
|
1220
|
-
//
|
|
1241
|
+
// FQ-5 N3 — the completion's carriers are FRAMEWORK-derived from the
|
|
1242
|
+
// model's own planet period records (the Moon-elongation rate from the
|
|
1243
|
+
// sidereal month/year identity). Plan 06 I2 — the carriers are SIDEREAL
|
|
1244
|
+
// (measured): the records' solarYearInput are OF-DATE periods (their
|
|
1245
|
+
// rates sit +1.39..1.62°/cy above the VSOP sidereal mean motions — the
|
|
1246
|
+
// framework precession plus input rounding), and a perturbation argument
|
|
1247
|
+
// is inertial (D'Alembert: only Σk = 0 arguments are frame-free), so on
|
|
1248
|
+
// of-date carriers every Σk ≠ 0 argument drifted by Σk·ψ(t) — 42..52° at
|
|
1249
|
+
// −3000 for the table's Σk = −1 terms (their ancient scatter against
|
|
1250
|
+
// Horizons 6.4 → 4.4″ on sidereal carriers), and 6 % of frequency for the
|
|
1251
|
+
// 1783-yr long inequality (1683 yr on the of-date carriers). Constant-free:
|
|
1252
|
+
// the record rate minus the model's own J2000 precession p₀ =
|
|
1253
|
+
// 360·36525·(1/T_trop − 1/T_sid) for the planets, the framework sidereal
|
|
1254
|
+
// year for Earth; identical to the N3 carriers at J2000 (same phase
|
|
1255
|
+
// anchors), ≤ 1.4°·|Σk| apart at the 200-yr extraction window's edges
|
|
1256
|
+
// (the composed table reproduces the N3 one there: JPL 1900–2100
|
|
1257
|
+
// all-phase sd unchanged to 0.01″). The parity gate's fingerprint mirrors
|
|
1258
|
+
// this arithmetic (test/create-model-parity.test.mjs).
|
|
1221
1259
|
const degPerCyOf = /** @param {number} cyclesPerDay */ (cyclesPerDay) => 360 * 36525 * cyclesPerDay;
|
|
1260
|
+
const carrierPrecessionDegPerCy = degPerCyOf(1 / meanSolarYearDays) - degPerCyOf(1 / meanSiderealYearDays);
|
|
1222
1261
|
const carrierRatesDegPerCy = {
|
|
1223
1262
|
planets: [
|
|
1224
|
-
degPerCyOf(1 / C.planetOrbitalElements.mercury.solarYearInput),
|
|
1225
|
-
degPerCyOf(1 / C.planetOrbitalElements.venus.solarYearInput),
|
|
1226
|
-
degPerCyOf(1 /
|
|
1227
|
-
degPerCyOf(1 / C.planetOrbitalElements.mars.solarYearInput),
|
|
1228
|
-
degPerCyOf(1 / C.planetOrbitalElements.jupiter.solarYearInput),
|
|
1229
|
-
degPerCyOf(1 / C.planetOrbitalElements.saturn.solarYearInput),
|
|
1263
|
+
degPerCyOf(1 / C.planetOrbitalElements.mercury.solarYearInput) - carrierPrecessionDegPerCy,
|
|
1264
|
+
degPerCyOf(1 / C.planetOrbitalElements.venus.solarYearInput) - carrierPrecessionDegPerCy,
|
|
1265
|
+
degPerCyOf(1 / meanSiderealYearDays),
|
|
1266
|
+
degPerCyOf(1 / C.planetOrbitalElements.mars.solarYearInput) - carrierPrecessionDegPerCy,
|
|
1267
|
+
degPerCyOf(1 / C.planetOrbitalElements.jupiter.solarYearInput) - carrierPrecessionDegPerCy,
|
|
1268
|
+
degPerCyOf(1 / C.planetOrbitalElements.saturn.solarYearInput) - carrierPrecessionDegPerCy,
|
|
1230
1269
|
],
|
|
1231
1270
|
moonElongation: degPerCyOf(1 / moonSiderealMonthInput - 1 / meanSiderealYearDays),
|
|
1232
1271
|
};
|
|
@@ -1238,7 +1277,10 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
1238
1277
|
},
|
|
1239
1278
|
sunLonDegAt: /** @param {number} jdUT */ (jdUT) => eclipseFinders.sunLonDegAt(jdUT),
|
|
1240
1279
|
sunCompletionDeg: sunPlanetaryCompletionDeg,
|
|
1241
|
-
|
|
1280
|
+
// plan 06 R3 item 1: the location tier on APPARENT places — the Sun's derived κ
|
|
1281
|
+
// (the same helper the cardinal instants use), the Moon's relative light-time
|
|
1282
|
+
// inside the besselian; the series-extension tail now lives in sceneEvalAt.
|
|
1283
|
+
sunAberrationDegAt: /** @param {number} year */ (year) => sunAberrationArcsecAt(year) / 3600,
|
|
1242
1284
|
deltaTSecondsAt: /** @param {number} jd */ (jd) => (jdTTFromUT(jd) - jd) * 86400,
|
|
1243
1285
|
obliquityDegAt: obliquityDeg,
|
|
1244
1286
|
eccentricityAt: sunEccentricityAt,
|
|
@@ -1256,6 +1298,7 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
1256
1298
|
gmstMeanSiderealT0Deg: C.physicalConstants.gmstMeanSiderealT0Deg,
|
|
1257
1299
|
gmstMeanSiderealRateDegPerDay: C.physicalConstants.gmstMeanSiderealRateDegPerDay,
|
|
1258
1300
|
gmstMeanSiderealT2Deg: C.physicalConstants.gmstMeanSiderealT2Deg,
|
|
1301
|
+
speedOfLightKmS: C.physicalConstants.speedOfLight,
|
|
1259
1302
|
},
|
|
1260
1303
|
});
|
|
1261
1304
|
|
|
@@ -1277,6 +1320,93 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
1277
1320
|
if (Math.abs(year - 2000) <= ONE_FAMILY_WINDOW_YEARS) return yearLengthsM.tropicalYearSecondsAtYear(year);
|
|
1278
1321
|
return deepLod.tropicalYearSecondsAtAge(yearToTMa(year));
|
|
1279
1322
|
};
|
|
1323
|
+
// ── Cardinal instants (plan 06 R1) ─────────────────────────────────────
|
|
1324
|
+
/** The completed certified Sun (finder Sun − the derived planetary
|
|
1325
|
+
* completion) at a UT model-JD — the same longitude the scene renders
|
|
1326
|
+
* inside the overlay window; MEAN GEOMETRIC, mean equinox of date.
|
|
1327
|
+
* @param {number} jdUT @returns {number} */
|
|
1328
|
+
const sunLonCompletedDegAtJdUT = (jdUT) => eclipseFinders.sunLonDegAt(jdUT)
|
|
1329
|
+
- sunPlanetaryCompletionDeg((jdTTFromUT(jdUT) - j2000JD) / julianCenturyDays);
|
|
1330
|
+
/** The APPARENT Sun the cardinal instants are defined on (an equinox is
|
|
1331
|
+
* the apparent Sun crossing the equator — the USNO/Meeus instants are
|
|
1332
|
+
* apparent): the completed geometric Sun minus the aberration constant,
|
|
1333
|
+
* plus the nutation in longitude. Both derived, zero new constants —
|
|
1334
|
+
* κ = 2π·a/(c·T_sid·√(1−e²)) from the AU, c, the one-family sidereal year
|
|
1335
|
+
* and the Sun's e (20.50″ at J2000); Δψ from the four IAU 1980 leading
|
|
1336
|
+
* terms on the model's OWN lunar node, mean Sun and mean Moon (the
|
|
1337
|
+
* framework arguments), the same family the registry's JPL Sun
|
|
1338
|
+
* instrument bridges with. @param {number} jdUT @returns {number} */
|
|
1339
|
+
/** The Sun's derived aberration constant of date, arcsec — κ = 2π·a/(c·T_sid·√(1−e²))
|
|
1340
|
+
* from the AU, c, the one-family sidereal year and the Sun's e (20.50″ at
|
|
1341
|
+
* J2000); ONE home for the cardinal instants and the eclipse location tier.
|
|
1342
|
+
* @param {number} year @returns {number} */
|
|
1343
|
+
const sunAberrationArcsecAt = (year) => {
|
|
1344
|
+
const e = sunEccentricityAt(year);
|
|
1345
|
+
return (2 * Math.PI * currentAUDistance
|
|
1346
|
+
/ (C.physicalConstants.speedOfLight * yearLengthsM.siderealYearSecondsAtYear(year) * Math.sqrt(1 - e * e)))
|
|
1347
|
+
* (648000 / Math.PI);
|
|
1348
|
+
};
|
|
1349
|
+
/** @param {number} jdUT @returns {number} */
|
|
1350
|
+
const sunApparentLonDegAtJdUT = (jdUT) => {
|
|
1351
|
+
const jdTT = jdTTFromUT(jdUT);
|
|
1352
|
+
const year = 2000 + (jdTT - j2000JD) / 365.25;
|
|
1353
|
+
const kappaArcsec = sunAberrationArcsecAt(year);
|
|
1354
|
+
const a = moonArgs.argsAt(jdTT);
|
|
1355
|
+
const d2r = Math.PI / 180;
|
|
1356
|
+
const Om = (a.Lp - a.F) * d2r, Ls = (a.Lp - a.D) * d2r, Lm = a.Lp * d2r;
|
|
1357
|
+
const NU = C.physicalConstants.nutationLeadingTermsArcsec;
|
|
1358
|
+
const dPsiArcsec = NU.psiOmega * Math.sin(Om) + NU.psi2Ls * Math.sin(2 * Ls)
|
|
1359
|
+
+ NU.psi2Lm * Math.sin(2 * Lm) + NU.psi2Omega * Math.sin(2 * Om);
|
|
1360
|
+
return sunLonCompletedDegAtJdUT(jdUT) + (dPsiArcsec - kappaArcsec) / 3600;
|
|
1361
|
+
};
|
|
1362
|
+
/** @param {string} type @returns {number} */
|
|
1363
|
+
const cardinalTargetDeg = (type) => {
|
|
1364
|
+
const t = { VE: 0, SS: 90, AE: 180, WS: 270 }[type];
|
|
1365
|
+
if (t === undefined) throw new RangeError(`cardinal type must be VE|SS|AE|WS, got ${type}`);
|
|
1366
|
+
return t;
|
|
1367
|
+
};
|
|
1368
|
+
const CARDINAL_SI_YEAR_D = 365.2422;
|
|
1369
|
+
/** The crossing NEAREST a seed instant — the unique root within ±½ tropical
|
|
1370
|
+
* year of the seed (the wrapped longitude difference is the Newton residual).
|
|
1371
|
+
* Plan 06 R4c: the seed is a JD because the caller's year may live on a
|
|
1372
|
+
* different axis than the model year — the simulator's cardinal panel
|
|
1373
|
+
* labels its year with the displayed CALENDAR date (the Julian calendar
|
|
1374
|
+
* before 1582, 365.25-d years) while `year` below is the model year (the SI
|
|
1375
|
+
* axis, 365.2422-d count from J2000); the two part by 0.0078 d/yr, 114 yr at
|
|
1376
|
+
* −5.34 Myr, where the panel showed the events of −5341772 for a date in
|
|
1377
|
+
* −5341886 (owner). Seeding at the calendar year's midpoint returns that
|
|
1378
|
+
* year's own events at every epoch. @param {number} jdSeedUT @param {string} type @returns {number} */
|
|
1379
|
+
const cardinalCrossingNearJdUT = (jdSeedUT, type) => {
|
|
1380
|
+
const target = cardinalTargetDeg(type);
|
|
1381
|
+
const RATE = 360 / CARDINAL_SI_YEAR_D;
|
|
1382
|
+
let jd = jdSeedUT;
|
|
1383
|
+
for (let i = 0; i < 20; i++) {
|
|
1384
|
+
const d = ((((sunApparentLonDegAtJdUT(jd) - target) + 540) % 360 + 360) % 360) - 180;
|
|
1385
|
+
jd -= d / RATE;
|
|
1386
|
+
if (Math.abs(d) < 1e-10) break;
|
|
1387
|
+
}
|
|
1388
|
+
return jd - C.earthOrbital.deltaTStart / 86400;
|
|
1389
|
+
};
|
|
1390
|
+
/** The TRUE-UT JD at which the APPARENT Sun's longitude of date equals
|
|
1391
|
+
* the cardinal target in the given year — Newton on the crossing (the
|
|
1392
|
+
* Sun's rate 360°/tropical year; a handful of steps from the tropical-year
|
|
1393
|
+
* seed). Replaces the fitted cardinal model's instants (R1). Plan 06 R3
|
|
1394
|
+
* item 2: the Newton root lives on the FINDER axis (the curve-only ΔT the
|
|
1395
|
+
* eclipse finders certify), and the returned instant is that root minus the
|
|
1396
|
+
* deltaTStart bridge — true UT = TT − (deltaTStart + curve), the same
|
|
1397
|
+
* bridge the besselian and the registry instruments apply. Before this the
|
|
1398
|
+
* published instants were 54.55 s (0.9 min) late. Against Horizons over
|
|
1399
|
+
* ±3000 yr the remaining offset is the Sun's (plan 06 I2 measured).
|
|
1400
|
+
* `year` is the MODEL year (the SI axis) — see cardinalCrossingNearJdUT.
|
|
1401
|
+
* @param {number} year @param {string} type @returns {number} */
|
|
1402
|
+
const cardinalCrossingJdUT = (year, type) => {
|
|
1403
|
+
const target = cardinalTargetDeg(type);
|
|
1404
|
+
// seed: Jan 1.5 of the year (J2000 = 2000 Jan 1.5) + the mean date of the
|
|
1405
|
+
// March equinox (day 79.3) + the quarter-turns to the target
|
|
1406
|
+
const seed = j2000JD + (year - 2000) * CARDINAL_SI_YEAR_D + 79.3 + (target / 360) * CARDINAL_SI_YEAR_D;
|
|
1407
|
+
return cardinalCrossingNearJdUT(seed, type);
|
|
1408
|
+
};
|
|
1409
|
+
|
|
1280
1410
|
return Object.freeze({
|
|
1281
1411
|
time: Object.freeze({
|
|
1282
1412
|
yearFromJD,
|
|
@@ -1399,13 +1529,18 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
1399
1529
|
measuredSolarDaySeconds,
|
|
1400
1530
|
raDayOffsetMs,
|
|
1401
1531
|
}),
|
|
1532
|
+
// Plan 06 R1: the instants are the crossings of the ONE Sun (the
|
|
1533
|
+
// certified completed Sun the scene renders), UT model-JD; the RA at a
|
|
1534
|
+
// crossing is the target longitude by construction (λ = 0/90/180/270 ⇒
|
|
1535
|
+
// RA = 0/90/180/270, any obliquity); the per-type year length is the
|
|
1536
|
+
// interval between successive crossings (SI days).
|
|
1402
1537
|
cardinal: Object.freeze({
|
|
1403
|
-
jd: /** @param {number} year @param {string} type @returns {number} */ (year, type) =>
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
},
|
|
1408
|
-
yearLengthDays: /** @param {number} year @param {string} type @returns {number} */ (year, type) =>
|
|
1538
|
+
jd: /** @param {number} year @param {string} type @returns {number} */ (year, type) => cardinalCrossingJdUT(year, type),
|
|
1539
|
+
// R4c: the crossing nearest a UT instant (a JD seed — for callers whose
|
|
1540
|
+
// year coordinate is not the model year, e.g. a calendar year's midpoint).
|
|
1541
|
+
jdNearUT: /** @param {number} jdUT @param {string} type @returns {number} */ (jdUT, type) => cardinalCrossingNearJdUT(jdUT, type),
|
|
1542
|
+
raDeg: /** @param {number} year @param {string} type @returns {number} */ (year, type) => { void year; return cardinalTargetDeg(type); },
|
|
1543
|
+
yearLengthDays: /** @param {number} year @param {string} type @returns {number} */ (year, type) => cardinalCrossingJdUT(year + 1, type) - cardinalCrossingJdUT(year, type),
|
|
1409
1544
|
}),
|
|
1410
1545
|
// D4b: the one-source cardinal STRUCTURE — the EoC layer on the
|
|
1411
1546
|
// movement's own e(t)/ϖ(t), valid at every epoch (mode tier). Absolute
|
|
@@ -1449,6 +1584,8 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
1449
1584
|
sunLonCompletedDegAtJD: /** @param {number} jd @returns {number} */ (jd) =>
|
|
1450
1585
|
eclipseFinders.sunLonDegAt(jd)
|
|
1451
1586
|
- sunPlanetaryCompletionDeg((jdTTFromUT(jd) - j2000JD) / julianCenturyDays),
|
|
1587
|
+
/** 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} */
|
|
1588
|
+
sunApparentLonDegAtJD: /** @param {number} jdUT @returns {number} */ (jdUT) => sunApparentLonDegAtJdUT(jdUT),
|
|
1452
1589
|
findLunarInRange: /** @param {number} jdStart @param {number} jdEnd */ (jdStart, jdEnd) => eclipseFinders.findLunarEclipsesInRange(jdStart, jdEnd),
|
|
1453
1590
|
findSolarInRange: /** @param {number} jdStart @param {number} jdEnd */ (jdStart, jdEnd) => eclipseFinders.findSolarEclipsesInRange(jdStart, jdEnd),
|
|
1454
1591
|
deltaTSecondsAtJD: frameworkDeltaTSecondsAtJD,
|
|
@@ -1477,6 +1614,7 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
1477
1614
|
perihelionLongitudeDeg: planetPerihelionDeg,
|
|
1478
1615
|
ascendingNodeInvPlaneDeg: planetAscNodeDeg,
|
|
1479
1616
|
invPlaneInclinationDeg: planetInclinationDeg,
|
|
1617
|
+
spin: planetSpin,
|
|
1480
1618
|
}),
|
|
1481
1619
|
});
|
|
1482
1620
|
}
|