@essrt/physics 13.0.0 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -5
- package/src/constants/generated.js +1 -1
- package/src/index.js +5 -4
- package/src/model.js +68 -38
- package/src/planets/model.cjs +23 -49
- package/types/index.d.ts +0 -3
- package/types/planets/model.d.cts +1 -16
- package/src/planets/asc-node-integrator.cjs +0 -120
- package/src/planets/fibonacci-laws.cjs +0 -95
- package/src/planets/orientation.cjs +0 -142
- package/types/planets/asc-node-integrator.d.cts +0 -30
- package/types/planets/fibonacci-laws.d.cts +0 -27
- package/types/planets/orientation.d.cts +0 -67
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@essrt/physics",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.0.0",
|
|
4
4
|
"description": "ESSRT (Expanding Solar System Resonance Theory) physics core — pure, injectable-constants, no I/O, no globals, no DOM. The complete model incl. fitted coefficients; every published version immutably ships one recorded model identity.",
|
|
5
5
|
"essrt": {
|
|
6
|
-
"modelVersion": "
|
|
6
|
+
"modelVersion": "v18.0",
|
|
7
7
|
"_note": "The model identity this package version ships (IP-unified-architecture §10: package semver tracks the API axis; the model version + CONSTANTS_HASH/COEFFICIENTS_HASH in src/constants/ carry the scientific identity). The version-pinning gate enforces this pairing against public/input/model-version.json."
|
|
8
8
|
},
|
|
9
9
|
"type": "module",
|
|
@@ -50,10 +50,7 @@
|
|
|
50
50
|
"./moon/series-extension": { "types": "./types/moon/series-extension.d.cts", "default": "./src/moon/series-extension.cjs" },
|
|
51
51
|
"./moon/apparent": { "types": "./types/moon/apparent.d.cts", "default": "./src/moon/apparent.cjs" },
|
|
52
52
|
"./planets/geometry": { "types": "./types/planets/geometry.d.cts", "default": "./src/planets/geometry.cjs" },
|
|
53
|
-
"./planets/fibonacci-laws": { "types": "./types/planets/fibonacci-laws.d.cts", "default": "./src/planets/fibonacci-laws.cjs" },
|
|
54
53
|
"./planets/ecc-channel": { "types": "./types/planets/ecc-channel.d.cts", "default": "./src/planets/ecc-channel.cjs" },
|
|
55
|
-
"./planets/orientation": { "types": "./types/planets/orientation.d.cts", "default": "./src/planets/orientation.cjs" },
|
|
56
|
-
"./planets/asc-node-integrator": { "types": "./types/planets/asc-node-integrator.d.cts", "default": "./src/planets/asc-node-integrator.cjs" },
|
|
57
54
|
"./planets/orbit-chain": { "types": "./types/planets/orbit-chain.d.cts", "default": "./src/planets/orbit-chain.cjs" },
|
|
58
55
|
"./planets/keplerian-chain": { "types": "./types/planets/keplerian-chain.d.cts", "default": "./src/planets/keplerian-chain.cjs" },
|
|
59
56
|
"./planets/spin-channel": { "types": "./types/planets/spin-channel.d.cts", "default": "./src/planets/spin-channel.cjs" },
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
export const CONSTANTS_HASH = "726b10e23d8ace09";
|
|
37
37
|
|
|
38
38
|
/** Model version label — single source: public/input/model-version.json (§10 two-axis scheme). */
|
|
39
|
-
export const MODEL_VERSION = "
|
|
39
|
+
export const MODEL_VERSION = "v18.0";
|
|
40
40
|
|
|
41
41
|
/** Canonical preprint DOI — single source: public/input/model-version.json. */
|
|
42
42
|
export const PREPRINT_DOI = "10.21203/rs.3.rs-8758810/v4";
|
package/src/index.js
CHANGED
|
@@ -122,12 +122,13 @@ export { createMoonApparent } from './moon/apparent.cjs';
|
|
|
122
122
|
// sample) and the offset-circle wheel-angle solver: the scene twins' one placement.
|
|
123
123
|
export { computeEarthFrameOfDate, solveWheelAngleForLongitude } from './earth/frame-of-date.cjs';
|
|
124
124
|
// Phase 8.3 — the planet machinery, extracted by LAW over body records
|
|
125
|
-
// (survey order: geometry →
|
|
125
|
+
// (survey order: geometry → channels → chains). The ψ/K amplitude laws
|
|
126
|
+
// (planets/fibonacci-laws), the record-based orientation forms
|
|
127
|
+
// (planets/orientation) and the ascending-node integrator
|
|
128
|
+
// (planets/asc-node-integrator) are DELETED at plan 07 R5/R6: the planets'
|
|
129
|
+
// elements of date have one home, the N-body chain; docs/retired-record.md.
|
|
126
130
|
export { derivePlanetGeometry } from './planets/geometry.cjs';
|
|
127
|
-
export * as planetFibonacciLaws from './planets/fibonacci-laws.cjs';
|
|
128
131
|
export { eccentricityFromCycles, computeEccentricityIntegrated } from './planets/ecc-channel.cjs';
|
|
129
|
-
export * as planetOrientation from './planets/orientation.cjs';
|
|
130
|
-
export { integrateAscendingNode } from './planets/asc-node-integrator.cjs';
|
|
131
132
|
export * as planetOrbitChain from './planets/orbit-chain.cjs';
|
|
132
133
|
// P5/K4.6c — the engine-D Keplerian chain (pure evaluator + the embedded
|
|
133
134
|
// governed artifact; the browser flag path consumes exactly these).
|
package/src/model.js
CHANGED
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
* which itself mirrors tools/lib/constants.js §9.
|
|
19
19
|
*/
|
|
20
20
|
import { deriveEpochParams } from './layer0/derive-params.js';
|
|
21
|
-
import * as FL from './planets/fibonacci-laws.cjs';
|
|
22
21
|
import { buildPlanetChainsFromArtifactData, computePlanetElementsAtYear } from './planets/keplerian-chain.cjs';
|
|
23
22
|
import { createSecularSeriesOverride } from './planets/secular-series.cjs';
|
|
24
23
|
import { computeEquatorNodeOriginSFrameDeg, convertNodeSFrameToEquatorOriginDeg } from './planets/inv-plane-frame.cjs';
|
|
@@ -97,14 +96,12 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
97
96
|
const meanAnomalisticYearDays = (meanSolarYearDays * (H / 16)) / (H / 16 - 1);
|
|
98
97
|
const meanTropicalYearJ2000Seconds = meanSolarYearDays * meanLengthOfDay;
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
// retired nothing in this module reads
|
|
104
|
-
// the
|
|
105
|
-
|
|
106
|
-
- earthInclAmplitude * Math.cos(((C.earthOrbital.earthPerihelionLongitudeJ2000
|
|
107
|
-
- C.earthOrbital.earthInclinationCycleAnchor) * Math.PI) / 180);
|
|
99
|
+
// Plan 07 R5/R6/R9: `earthtiltMean`, `earthInvPlaneInclinationAmplitude`
|
|
100
|
+
// and `eccentricityAmplitude` were read here only to invert the K and ψ
|
|
101
|
+
// constants from Earth's calibration and to build the H/3 inclination
|
|
102
|
+
// device. With both laws retired nothing in this module reads them — they
|
|
103
|
+
// remain on C.earth as the K device's J2000 pose inputs (the scene's wheel
|
|
104
|
+
// geometry at the chain anchor epoch) and for the registry's record keys.
|
|
108
105
|
const solsticeObliquityMean = F.SOLSTICE_OBLIQUITY_MEAN_FITTED;
|
|
109
106
|
|
|
110
107
|
const G_CONSTANT = C.physicalConstants.G_CONSTANT;
|
|
@@ -429,14 +426,9 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
429
426
|
/** de/dyear of the Sun's e — the cardinal braid's equation-of-centre
|
|
430
427
|
* derivative rides it (±0.5-yr central difference; the constant offset
|
|
431
428
|
* cancels). @param {number} year @returns {number} */
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
/** @param {number} year @returns {number} */
|
|
436
|
-
const ascendingNodeDeg = (year) => {
|
|
437
|
-
const period = -H / 5;
|
|
438
|
-
return (((C.earthOrbital.earthAscendingNodeInvPlane + (360.0 * (year - 2000)) / period) % 360) + 360) % 360;
|
|
439
|
-
};
|
|
429
|
+
// (Plan 07 R5/R9: Earth's H/3 inclination cosine and −H/5 linear node — the
|
|
430
|
+
// K device — stood here; `inclinationDeg`/`ascendingNodeDeg` are now the
|
|
431
|
+
// one-source construction defined with the planets' chain evaluators below.)
|
|
440
432
|
|
|
441
433
|
// ── Year/day lengths ──────────────────────────────────────────────────────
|
|
442
434
|
/** @param {number} year @param {number} base @param {Array<[number, number, number]>} harmonics @returns {number} */
|
|
@@ -617,6 +609,8 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
617
609
|
});
|
|
618
610
|
return {
|
|
619
611
|
yearLengths,
|
|
612
|
+
/** The one-source sample at a decimal year (the engine year) — ε, e, ϖ of date, the Earth-orbit normal (the fields the frame of date and the invariable-plane elements read). @param {number} year */
|
|
613
|
+
sampleAt,
|
|
620
614
|
/** EXPERIMENT accessors: the series' e and equinox-referenced ϖ of date. @param {number} year @returns {number} */
|
|
621
615
|
eAt: (year) => sampleAt(year).e,
|
|
622
616
|
/** @param {number} year @returns {number} */
|
|
@@ -716,14 +710,11 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
716
710
|
for (const k of PLANET_KEYS) massFraction[k] = 1 / C.physicalConstants.massRatioDE440[k];
|
|
717
711
|
massFraction.earth = massEarthAlone / M_SUN;
|
|
718
712
|
|
|
719
|
-
const PSI = FL.computePsiConstant({
|
|
720
|
-
earthInvPlaneInclinationAmplitude: earthInclAmplitude,
|
|
721
|
-
massEarthAlone,
|
|
722
|
-
massSun: M_SUN,
|
|
723
|
-
});
|
|
724
713
|
// (plan 07 R6: eccentricityAmplitudeK — the K constant inverted from
|
|
725
714
|
// Earth's calibration — and the t2000 phase offset it fed went with the
|
|
726
|
-
// eccentricity law
|
|
715
|
+
// eccentricity law; plan 07 R5: PSI — ψ = 3·A_earth·√(m_E/m_☉) — and the
|
|
716
|
+
// inclination law it fed went the same way. systemResetN is kept where
|
|
717
|
+
// other consumers read it.)
|
|
727
718
|
|
|
728
719
|
/** @param {[number, number]|null} frac @returns {number|null} */
|
|
729
720
|
const fractionToYears = (frac) => (frac === null ? null : (H * frac[0]) / frac[1]);
|
|
@@ -743,14 +734,6 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
743
734
|
// obliquity of the spin channel (the IAU pole against the chain's J2000
|
|
744
735
|
// plane, acute form) — both from the governed artifacts, no fractions.
|
|
745
736
|
const wobble = computeSecularShape(/** @type {any} */ (CHAIN_ARTIFACT), k).beatYears;
|
|
746
|
-
const il = FL.computeInclinationLaw({
|
|
747
|
-
fibonacciD: mp.fibonacciD,
|
|
748
|
-
massFrac: massFraction[k],
|
|
749
|
-
invPlaneInclinationJ2000: ar.invPlaneInclinationJ2000,
|
|
750
|
-
longitudePerihelion: ar.longitudePerihelion,
|
|
751
|
-
inclinationCycleAnchor: mp.inclinationCycleAnchor,
|
|
752
|
-
antiPhase: mp.antiPhase || false,
|
|
753
|
-
}, PSI);
|
|
754
737
|
const obliquityDerived = computeObliquityJ2000Deg({
|
|
755
738
|
spin: C.planetSpinPhysical[k],
|
|
756
739
|
anchorInclEclipticDeg: /** @type {any} */ (CHAIN_ARTIFACT).j2000AnchorElements[k].inclEclipticDeg,
|
|
@@ -770,8 +753,6 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
770
753
|
ascendingNodeInvPlane: mp.ascendingNodeInvPlane,
|
|
771
754
|
inclinationCycleAnchor: mp.inclinationCycleAnchor,
|
|
772
755
|
invPlaneInclinationJ2000: ar.invPlaneInclinationJ2000,
|
|
773
|
-
invPlaneInclinationAmplitude: il.amplitude,
|
|
774
|
-
invPlaneInclinationMean: il.mean,
|
|
775
756
|
obliquityMean,
|
|
776
757
|
orbitalEccentricityJ2000: ar.orbitalEccentricityJ2000,
|
|
777
758
|
solarYearInput: ar.solarYearInput,
|
|
@@ -779,8 +760,9 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
779
760
|
});
|
|
780
761
|
// R8 (plan 07): what `model.planets.record()` PUBLISHES is not the record
|
|
781
762
|
// above. The internal record kept the ψ/K law outputs for the fitting
|
|
782
|
-
// pipeline; at R6 the K half and both fitter steps that read it
|
|
783
|
-
//
|
|
763
|
+
// pipeline; at R6 the K half and both fitter steps that read it went, at
|
|
764
|
+
// R5 the ψ half (invPlaneInclinationAmplitude/Mean) — what remains above
|
|
765
|
+
// is the structural inputs and the derived J2000 obliquity.
|
|
784
766
|
// The separation stands for the same reason it was made —
|
|
785
767
|
// but nothing outside needs the device, and serving it made /v1/bodies
|
|
786
768
|
// contradict the model's own chain on the SAME quantities: Mercury's node
|
|
@@ -878,13 +860,15 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
878
860
|
};
|
|
879
861
|
/** Ecliptic longitude of perihelion, J2000 ecliptic and equinox (the chain's ϖ). @param {string} k @param {number} year @returns {number} */
|
|
880
862
|
const planetPerihelionDeg = (k, year) => planetChainElementsAt(k, year).lonPeriEclipticDeg;
|
|
881
|
-
/**
|
|
882
|
-
const
|
|
863
|
+
/** The S&S longitude origin as an s-frame longitude (J2000-fixed, derived). @returns {number} */
|
|
864
|
+
const nodeOriginSSDeg = () => {
|
|
883
865
|
if (planetNodeOriginSSDeg === null) {
|
|
884
866
|
planetNodeOriginSSDeg = computeEquatorNodeOriginSFrameDeg(/** @type {any} */ (CHAIN_ARTIFACT).invariablePlane, C.earthOrbital.obliquityJ2000_deg);
|
|
885
867
|
}
|
|
886
|
-
return
|
|
868
|
+
return planetNodeOriginSSDeg;
|
|
887
869
|
};
|
|
870
|
+
/** Ascending node on the model's invariable plane, from the plane's ascending node on the ICRF equator (the Souami & Souchay 2012 origin; derived conversion, inv-plane-frame). @param {string} k @param {number} year @returns {number} */
|
|
871
|
+
const planetAscNodeDeg = (k, year) => convertNodeSFrameToEquatorOriginDeg(planetChainElementsAt(k, year).ascNodeInvPlaneDeg, nodeOriginSSDeg());
|
|
888
872
|
/** Inclination to the model's invariable plane (exact orbit-normal rotation). @param {string} k @param {number} year @returns {number} */
|
|
889
873
|
const planetInclinationDeg = (k, year) => planetChainElementsAt(k, year).inclInvPlaneDeg;
|
|
890
874
|
/** Orbital eccentricity of date, from the same chain elements (R8): the
|
|
@@ -893,6 +877,52 @@ export function assembleModel(C, F, laws = {}, secularSeriesArtifact = /** @type
|
|
|
893
877
|
* e-vector does not have. @param {string} k @param {number} year @returns {number} */
|
|
894
878
|
const planetEccentricity = (k, year) => planetChainElementsAt(k, year).e;
|
|
895
879
|
|
|
880
|
+
// ── Earth's invariable-plane elements of date (plan 07 R5/R9) ─────────────
|
|
881
|
+
// ONE published i_inv / Ω_inv everywhere — the mirror of the browser's
|
|
882
|
+
// inclInvPlaneModel / ascNodeInvPlaneModel (identical ops): the engine's
|
|
883
|
+
// own Earth-orbit normal of date (the one-source sampler — the banked
|
|
884
|
+
// secular series inside ±10 Myr, the mode tail beyond) against the
|
|
885
|
+
// artifact's invariable plane, the node expressed in the Souami & Souchay
|
|
886
|
+
// longitude origin through the same derived conversion the planets' node
|
|
887
|
+
// takes. The H/3 cosine on the fixed apsidal carrier and the −H/5 linear
|
|
888
|
+
// node that served here until R5 were the K device: 1.578677° against
|
|
889
|
+
// 1.578422° at J2000, 1.24° against 1.91° at −100 kyr, and 112° against
|
|
890
|
+
// 94° of node there. Doc 05 banks the one-source reading at rms 0.003°
|
|
891
|
+
// vs La2010 over −500 kyr. Argument: the engine year (dynamical time,
|
|
892
|
+
// Julian from J2000 TT — the sampler's own coordinate, as the chain's).
|
|
893
|
+
const invPlaneGeometry = (() => {
|
|
894
|
+
const ip = /** @type {{ inclEclipticDeg: number, ascNodeEclipticDeg: number }} */ (/** @type {any} */ (CHAIN_ARTIFACT).invariablePlane);
|
|
895
|
+
const D2R = Math.PI / 180;
|
|
896
|
+
const si = Math.sin(ip.inclEclipticDeg * D2R), ci = Math.cos(ip.inclEclipticDeg * D2R);
|
|
897
|
+
const nInv = [si * Math.sin(ip.ascNodeEclipticDeg * D2R), -si * Math.cos(ip.ascNodeEclipticDeg * D2R), ci];
|
|
898
|
+
const xIp = [Math.cos(ip.ascNodeEclipticDeg * D2R), Math.sin(ip.ascNodeEclipticDeg * D2R), 0];
|
|
899
|
+
const yIp = [nInv[1] * xIp[2] - nInv[2] * xIp[1], nInv[2] * xIp[0] - nInv[0] * xIp[2], nInv[0] * xIp[1] - nInv[1] * xIp[0]];
|
|
900
|
+
return { ascNodeEclipticDeg: ip.ascNodeEclipticDeg, nInv, xIp, yIp };
|
|
901
|
+
})();
|
|
902
|
+
/** The engine Earth-orbit normal of date, J2000 ecliptic frame. @param {number} year @returns {number[]} */
|
|
903
|
+
const earthOrbitNormalJ2000At = (year) => {
|
|
904
|
+
const s = oneSourceM.sampleAt(year);
|
|
905
|
+
return [s.orbitNormalX, s.orbitNormalY, Math.sqrt(Math.max(0, 1 - s.orbitNormalX * s.orbitNormalX - s.orbitNormalY * s.orbitNormalY))];
|
|
906
|
+
};
|
|
907
|
+
/** Earth's inclination of date to the model's invariable plane, degrees. @param {number} year @returns {number} */
|
|
908
|
+
const inclinationDeg = (year) => {
|
|
909
|
+
const nE = earthOrbitNormalJ2000At(year), nInv = invPlaneGeometry.nInv;
|
|
910
|
+
const d = nE[0] * nInv[0] + nE[1] * nInv[1] + nE[2] * nInv[2];
|
|
911
|
+
return Math.acos(Math.min(1, Math.max(-1, d))) / (Math.PI / 180);
|
|
912
|
+
};
|
|
913
|
+
/** Earth's ascending node of date on the invariable plane, S&S origin, degrees in [0, 360). @param {number} year @returns {number} */
|
|
914
|
+
const ascendingNodeDeg = (year) => {
|
|
915
|
+
const D2R = Math.PI / 180;
|
|
916
|
+
const { ascNodeEclipticDeg, nInv, xIp, yIp } = invPlaneGeometry;
|
|
917
|
+
const nE = earthOrbitNormalJ2000At(year);
|
|
918
|
+
let N = [nInv[1] * nE[2] - nInv[2] * nE[1], nInv[2] * nE[0] - nInv[0] * nE[2], nInv[0] * nE[1] - nInv[1] * nE[0]];
|
|
919
|
+
const L = Math.hypot(N[0], N[1], N[2]);
|
|
920
|
+
N = [N[0] / L, N[1] / L, N[2] / L];
|
|
921
|
+
const sFrameDeg = ((Math.atan2(N[0] * yIp[0] + N[1] * yIp[1] + N[2] * yIp[2],
|
|
922
|
+
N[0] * xIp[0] + N[1] * xIp[1] + N[2] * xIp[2]) / D2R + ascNodeEclipticDeg) % 360 + 360) % 360;
|
|
923
|
+
return convertNodeSFrameToEquatorOriginDeg(sFrameDeg, nodeOriginSSDeg());
|
|
924
|
+
};
|
|
925
|
+
|
|
896
926
|
// ── Time axis: exact JD ↔ model-year conversion ───────────────────────────
|
|
897
927
|
// The model's `year` inputs live on the SI axis (the axis the fits were
|
|
898
928
|
// anchored on — tools/lib `_jdToSIyear`): linear in SI 86400-s days from the
|
package/src/planets/model.cjs
CHANGED
|
@@ -2,31 +2,29 @@
|
|
|
2
2
|
* createPlanetModel — the planet composition front door (Phase 8.3, L10).
|
|
3
3
|
*
|
|
4
4
|
* ONE law set, N body records: this factory binds an environment once and
|
|
5
|
-
* runs the certified derivation chain over every body record
|
|
6
|
-
* the chain requires (each step feeds the next):
|
|
5
|
+
* runs the certified derivation chain over every body record:
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
7
|
+
* inputs the chain's g-mode beat (wobble) and the spin channel's
|
|
8
|
+
* derived J2000 obliquity, carried on the record since plan 06
|
|
9
|
+
* Phase 7 commit 2
|
|
10
|
+
* geometry (the type-branched ellipse family on the OBSERVED J2000
|
|
11
|
+
* eccentricity; minor bodies use their record's base)
|
|
12
|
+
*
|
|
13
|
+
* The ψ and K amplitude laws that opened this chain (ψ constant →
|
|
14
|
+
* inclination amplitude/mean; K constant → eccentricity amplitude/base/
|
|
15
|
+
* phase) are DELETED — K at plan 07 R6, ψ at plan 07 R5. A planet's
|
|
16
|
+
* inclination and eccentricity of date have one home, the N-body chain
|
|
17
|
+
* (model.js planetChainElementsAt); docs/retired-record.md is the record.
|
|
15
18
|
*
|
|
16
19
|
* THIN BY DESIGN. This is the composition surface, not a rewiring: both
|
|
17
|
-
* engines keep their existing direct call sites
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* minor-body placeholder note in geometry.cjs (Phase 18 perturbation
|
|
24
|
-
* types land the same way).
|
|
20
|
+
* engines keep their existing direct call sites, and the runtime channels
|
|
21
|
+
* stay direct module calls because they consume engine-owned state (scene
|
|
22
|
+
* JD, epoch machinery, fitted tables). What this factory adds is the seam
|
|
23
|
+
* future bodies plug into: a new body is a record + (at most) one new
|
|
24
|
+
* geometry branch — see the minor-body placeholder note in geometry.cjs
|
|
25
|
+
* (Phase 18 perturbation types land the same way).
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
-
* run only where the record carries the required fields (fibonacciD +
|
|
28
|
-
* mass fraction for the ψ/K families, perihelion + axial periods for
|
|
29
|
-
* wobble); geometry runs for every body. The identity gate
|
|
27
|
+
* Geometry runs for every body. The identity gate
|
|
30
28
|
* (test/planet-model-identity.test.mjs) holds this factory bit-exact
|
|
31
29
|
* against the shipped Node derivation.
|
|
32
30
|
*/
|
|
@@ -34,7 +32,6 @@
|
|
|
34
32
|
'use strict';
|
|
35
33
|
|
|
36
34
|
const { derivePlanetGeometry } = require('./geometry.cjs');
|
|
37
|
-
const FL = require('./fibonacci-laws.cjs');
|
|
38
35
|
|
|
39
36
|
/**
|
|
40
37
|
* @typedef {Object} PlanetModelBody
|
|
@@ -66,15 +63,10 @@ const FL = require('./fibonacci-laws.cjs');
|
|
|
66
63
|
* @property {number} currentAUDistanceKm
|
|
67
64
|
* @property {number} earthEccentricityJ2000
|
|
68
65
|
* @property {number} earthPerihelionLongitudeJ2000Deg
|
|
69
|
-
* @property {{ earthInvPlaneInclinationAmplitude: number,
|
|
70
|
-
* massEarthAlone: number, massSun: number }} calibration
|
|
71
|
-
* @property {Record<string, number>} massFractions
|
|
72
66
|
*/
|
|
73
67
|
|
|
74
68
|
/**
|
|
75
69
|
* @typedef {Object} PlanetModelRecord
|
|
76
|
-
* @property {number} [invPlaneInclinationAmplitude]
|
|
77
|
-
* @property {number} [invPlaneInclinationMean]
|
|
78
70
|
* @property {number} [wobblePeriodYears]
|
|
79
71
|
* @property {number} [obliquityMeanDeg]
|
|
80
72
|
* @property {ReturnType<typeof derivePlanetGeometry>} geometry
|
|
@@ -87,18 +79,13 @@ const FL = require('./fibonacci-laws.cjs');
|
|
|
87
79
|
* @param {Record<string, PlanetModelBody>} bodies - keyed by body name
|
|
88
80
|
* (the key selects the body-unique geometry branches: mercury, pluto,
|
|
89
81
|
* halleys, ceres)
|
|
90
|
-
* @returns {{
|
|
91
|
-
* bodies: Record<string, PlanetModelRecord> }}
|
|
82
|
+
* @returns {{ bodies: Record<string, PlanetModelRecord> }}
|
|
92
83
|
*/
|
|
93
84
|
function createPlanetModel(env, bodies) {
|
|
94
|
-
const psiConstant = FL.computePsiConstant({
|
|
95
|
-
earthInvPlaneInclinationAmplitude: env.calibration.earthInvPlaneInclinationAmplitude,
|
|
96
|
-
massEarthAlone: env.calibration.massEarthAlone,
|
|
97
|
-
massSun: env.calibration.massSun,
|
|
98
|
-
});
|
|
99
85
|
// Plan 07 R6: kConstant, the System-Reset eccentricityAnchor
|
|
100
86
|
// (balancedYear − systemResetN·H) and the t2000 phase it fed went with the
|
|
101
|
-
// eccentricity law
|
|
87
|
+
// eccentricity law; plan 07 R5: psiConstant (ψ = 3·A_earth·√(m_E/m_☉),
|
|
88
|
+
// from env.calibration) went with the inclination law.
|
|
102
89
|
|
|
103
90
|
const geomEnv = {
|
|
104
91
|
holisticYears: env.holisticYears,
|
|
@@ -111,22 +98,9 @@ function createPlanetModel(env, bodies) {
|
|
|
111
98
|
/** @type {Record<string, PlanetModelRecord>} */
|
|
112
99
|
const out = {};
|
|
113
100
|
for (const [key, b] of Object.entries(bodies)) {
|
|
114
|
-
const massFrac = env.massFractions[key];
|
|
115
101
|
/** @type {PlanetModelRecord} */
|
|
116
102
|
const rec = /** @type {PlanetModelRecord} */ ({});
|
|
117
103
|
|
|
118
|
-
if (b.fibonacciD && massFrac && b.invPlaneInclinationJ2000 !== undefined) {
|
|
119
|
-
const il = FL.computeInclinationLaw({
|
|
120
|
-
fibonacciD: b.fibonacciD, massFrac,
|
|
121
|
-
invPlaneInclinationJ2000: b.invPlaneInclinationJ2000,
|
|
122
|
-
longitudePerihelion: /** @type {number} */ (b.longitudePerihelion),
|
|
123
|
-
inclinationCycleAnchor: /** @type {number} */ (b.inclinationCycleAnchor),
|
|
124
|
-
antiPhase: /** @type {boolean} */ (b.antiPhase),
|
|
125
|
-
}, psiConstant);
|
|
126
|
-
rec.invPlaneInclinationAmplitude = il.amplitude;
|
|
127
|
-
rec.invPlaneInclinationMean = il.mean;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
104
|
// Plan 06 Phase 7 commit 2: the K law's cycle period and obliquity input
|
|
131
105
|
// are INPUTS of the record now — the chain's own g-mode beat
|
|
132
106
|
// (keplerian-chain computeSecularShape) and the derived J2000 obliquity
|
|
@@ -156,7 +130,7 @@ function createPlanetModel(env, bodies) {
|
|
|
156
130
|
out[key] = rec;
|
|
157
131
|
}
|
|
158
132
|
|
|
159
|
-
return {
|
|
133
|
+
return { bodies: out };
|
|
160
134
|
}
|
|
161
135
|
|
|
162
136
|
module.exports = { createPlanetModel };
|
package/types/index.d.ts
CHANGED
|
@@ -12,9 +12,6 @@ export { createMoonArguments } from "./moon/arguments.cjs";
|
|
|
12
12
|
export { createMoonSeries } from "./moon/series.cjs";
|
|
13
13
|
export { createMoonApparent } from "./moon/apparent.cjs";
|
|
14
14
|
export { derivePlanetGeometry } from "./planets/geometry.cjs";
|
|
15
|
-
export * as planetFibonacciLaws from "./planets/fibonacci-laws.cjs";
|
|
16
|
-
export * as planetOrientation from "./planets/orientation.cjs";
|
|
17
|
-
export { integrateAscendingNode } from "./planets/asc-node-integrator.cjs";
|
|
18
15
|
export * as planetOrbitChain from "./planets/orbit-chain.cjs";
|
|
19
16
|
export { computeSecularShape } from "./planets/secular-shape.cjs";
|
|
20
17
|
export { createSecularSeriesOverride } from "./planets/secular-series.cjs";
|
|
@@ -37,16 +37,8 @@ export type PlanetModelEnv = {
|
|
|
37
37
|
currentAUDistanceKm: number;
|
|
38
38
|
earthEccentricityJ2000: number;
|
|
39
39
|
earthPerihelionLongitudeJ2000Deg: number;
|
|
40
|
-
calibration: {
|
|
41
|
-
earthInvPlaneInclinationAmplitude: number;
|
|
42
|
-
massEarthAlone: number;
|
|
43
|
-
massSun: number;
|
|
44
|
-
};
|
|
45
|
-
massFractions: Record<string, number>;
|
|
46
40
|
};
|
|
47
41
|
export type PlanetModelRecord = {
|
|
48
|
-
invPlaneInclinationAmplitude?: number | undefined;
|
|
49
|
-
invPlaneInclinationMean?: number | undefined;
|
|
50
42
|
wobblePeriodYears?: number | undefined;
|
|
51
43
|
obliquityMeanDeg?: number | undefined;
|
|
52
44
|
geometry: ReturnType<typeof derivePlanetGeometry>;
|
|
@@ -80,14 +72,9 @@ export type PlanetModelRecord = {
|
|
|
80
72
|
* @property {number} currentAUDistanceKm
|
|
81
73
|
* @property {number} earthEccentricityJ2000
|
|
82
74
|
* @property {number} earthPerihelionLongitudeJ2000Deg
|
|
83
|
-
* @property {{ earthInvPlaneInclinationAmplitude: number,
|
|
84
|
-
* massEarthAlone: number, massSun: number }} calibration
|
|
85
|
-
* @property {Record<string, number>} massFractions
|
|
86
75
|
*/
|
|
87
76
|
/**
|
|
88
77
|
* @typedef {Object} PlanetModelRecord
|
|
89
|
-
* @property {number} [invPlaneInclinationAmplitude]
|
|
90
|
-
* @property {number} [invPlaneInclinationMean]
|
|
91
78
|
* @property {number} [wobblePeriodYears]
|
|
92
79
|
* @property {number} [obliquityMeanDeg]
|
|
93
80
|
* @property {ReturnType<typeof derivePlanetGeometry>} geometry
|
|
@@ -99,11 +86,9 @@ export type PlanetModelRecord = {
|
|
|
99
86
|
* @param {Record<string, PlanetModelBody>} bodies - keyed by body name
|
|
100
87
|
* (the key selects the body-unique geometry branches: mercury, pluto,
|
|
101
88
|
* halleys, ceres)
|
|
102
|
-
* @returns {{
|
|
103
|
-
* bodies: Record<string, PlanetModelRecord> }}
|
|
89
|
+
* @returns {{ bodies: Record<string, PlanetModelRecord> }}
|
|
104
90
|
*/
|
|
105
91
|
export function createPlanetModel(env: PlanetModelEnv, bodies: Record<string, PlanetModelBody>): {
|
|
106
|
-
psiConstant: number;
|
|
107
92
|
bodies: Record<string, PlanetModelRecord>;
|
|
108
93
|
};
|
|
109
94
|
import { derivePlanetGeometry } from "./geometry.cjs";
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dynamic ascending node — rate-based segment integration (Phase 8.3, L5).
|
|
3
|
-
*
|
|
4
|
-
* dΩ/dε = −sin(Ω)/tan(i), integrated over obliquity change with segment
|
|
5
|
-
* handling at obliquity extrema and Earth-inclination crossovers (the
|
|
6
|
-
* inclination DIRECTION flips the sign of the effect per segment).
|
|
7
|
-
*
|
|
8
|
-
* Extracted from tools/lib/orbital-engine.js
|
|
9
|
-
* calculateDynamicAscendingNodeFromTilts (itself the mirror of the
|
|
10
|
-
* browser's 6-arg variant — S-P5). The BROWSER variant remains engine-side
|
|
11
|
-
* this slice: neither copy is fixture-pinned, so the signature unification
|
|
12
|
-
* is deferred to the factory pass, WITH probes first (recorded follow-up).
|
|
13
|
-
*
|
|
14
|
-
* §2h BOUNDARY: this module takes {ascendingNodeDeg, inclinationDeg} — the
|
|
15
|
-
* Tychosium `orbitTilta/orbitTiltb` scheme names never enter the package;
|
|
16
|
-
* the engines own the atan2/hypot decomposition at their edge.
|
|
17
|
-
*
|
|
18
|
-
* All time-dependent inputs are INJECTED per call: the engine's obliquity
|
|
19
|
-
* and Earth-inclination evaluators, the precomputed obliquity-extrema
|
|
20
|
-
* lookup, the inclination-crossing finder, and (optionally) the per-planet
|
|
21
|
-
* dynamic ecliptic inclination.
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
'use strict';
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @param {{ ascendingNodeDeg: number, inclinationDeg: number }} tilt —
|
|
28
|
-
* static node and inclination (engine-decomposed from its scene scheme)
|
|
29
|
-
* @param {number} currentYear
|
|
30
|
-
* @param {{
|
|
31
|
-
* obliquityAt: (year: number) => number,
|
|
32
|
-
* earthInclinationAt: (year: number) => number,
|
|
33
|
-
* obliquityExtremaInRange: (yearMin: number, yearMax: number) => number[],
|
|
34
|
-
* inclinationCrossingsInRange: (inclinationDeg: number, yearMin: number, yearMax: number) => number[],
|
|
35
|
-
* eclipticInclinationAt: ((year: number) => number) | null,
|
|
36
|
-
* earthInclinationMeanDeg: number,
|
|
37
|
-
* earthInclinationAmplitudeDeg: number,
|
|
38
|
-
* epochYear?: number,
|
|
39
|
-
* }} deps — eclipticInclinationAt non-null enables the dynamic-inclination
|
|
40
|
-
* crossover search and per-segment rates (the planetName path).
|
|
41
|
-
* @returns {number} dynamic ascending node longitude, degrees 0–360
|
|
42
|
-
*/
|
|
43
|
-
function integrateAscendingNode(tilt, currentYear, deps) {
|
|
44
|
-
const DEG2RAD = Math.PI / 180;
|
|
45
|
-
const RAD2DEG = 180 / Math.PI;
|
|
46
|
-
|
|
47
|
-
const staticOmega = ((tilt.ascendingNodeDeg % 360) + 360) % 360;
|
|
48
|
-
const planetInclination = tilt.inclinationDeg;
|
|
49
|
-
|
|
50
|
-
if (planetInclination < 1e-6) return staticOmega;
|
|
51
|
-
|
|
52
|
-
const i = planetInclination * DEG2RAD;
|
|
53
|
-
const OmegaRad = staticOmega * DEG2RAD;
|
|
54
|
-
const tanI = Math.tan(i);
|
|
55
|
-
if (Math.abs(tanI) < 1e-10) return staticOmega;
|
|
56
|
-
|
|
57
|
-
const sinOmega = Math.sin(OmegaRad);
|
|
58
|
-
const EPOCH_YEAR = deps.epochYear !== undefined ? deps.epochYear : 2000;
|
|
59
|
-
|
|
60
|
-
/** @param {number} fromYear @param {number} toYear @returns {number} */
|
|
61
|
-
const integrateEffect = (fromYear, toYear) => {
|
|
62
|
-
if (Math.abs(toYear - fromYear) < 0.1) return 0;
|
|
63
|
-
|
|
64
|
-
const yearMin = Math.min(fromYear, toYear);
|
|
65
|
-
const yearMax = Math.max(fromYear, toYear);
|
|
66
|
-
const dir = toYear >= fromYear ? 1 : -1; // integration direction — signs the total
|
|
67
|
-
|
|
68
|
-
/** @type {number[]} */
|
|
69
|
-
let criticalYears = [yearMin, yearMax];
|
|
70
|
-
|
|
71
|
-
criticalYears.push(...deps.obliquityExtremaInRange(yearMin, yearMax));
|
|
72
|
-
|
|
73
|
-
// Find ALL inclination crossings
|
|
74
|
-
const minEarthIncl = deps.earthInclinationMeanDeg - deps.earthInclinationAmplitudeDeg;
|
|
75
|
-
const maxEarthIncl = deps.earthInclinationMeanDeg + deps.earthInclinationAmplitudeDeg;
|
|
76
|
-
|
|
77
|
-
// With a dynamic ecliptic inclination the planet can enter Earth's range
|
|
78
|
-
// even if the static value is outside — always search for crossovers.
|
|
79
|
-
if (deps.eclipticInclinationAt || (planetInclination >= minEarthIncl && planetInclination <= maxEarthIncl)) {
|
|
80
|
-
const crossIncl = deps.eclipticInclinationAt
|
|
81
|
-
? deps.eclipticInclinationAt((yearMin + yearMax) / 2)
|
|
82
|
-
: planetInclination;
|
|
83
|
-
criticalYears.push(...deps.inclinationCrossingsInRange(crossIncl, yearMin, yearMax));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
criticalYears = [...new Set(criticalYears)].sort((a, b) => a - b);
|
|
87
|
-
|
|
88
|
-
// Integrate over segments
|
|
89
|
-
let effect = 0;
|
|
90
|
-
for (let idx = 0; idx < criticalYears.length - 1; idx++) {
|
|
91
|
-
const segStart = criticalYears[idx];
|
|
92
|
-
const segEnd = criticalYears[idx + 1];
|
|
93
|
-
|
|
94
|
-
const oblStart = deps.obliquityAt(segStart);
|
|
95
|
-
const oblEnd = deps.obliquityAt(segEnd);
|
|
96
|
-
const deltaObl = (oblEnd - oblStart) * DEG2RAD;
|
|
97
|
-
|
|
98
|
-
const midYear = (segStart + segEnd) / 2;
|
|
99
|
-
const earthInclAtMid = deps.earthInclinationAt(midYear);
|
|
100
|
-
|
|
101
|
-
const dynIncl = deps.eclipticInclinationAt
|
|
102
|
-
? deps.eclipticInclinationAt(midYear)
|
|
103
|
-
: planetInclination;
|
|
104
|
-
const inclDirection = earthInclAtMid > dynIncl ? 1 : -1;
|
|
105
|
-
const dynTanI = Math.tan(dynIncl * DEG2RAD);
|
|
106
|
-
if (Math.abs(dynTanI) < 1e-10) continue; // skip near-zero inclination
|
|
107
|
-
const segRate = -sinOmega / dynTanI;
|
|
108
|
-
|
|
109
|
-
effect += segRate * inclDirection * deltaObl * RAD2DEG;
|
|
110
|
-
}
|
|
111
|
-
return effect * dir;
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
const effectFromEpoch = integrateEffect(EPOCH_YEAR, currentYear);
|
|
115
|
-
|
|
116
|
-
const newOmega = staticOmega + effectFromEpoch;
|
|
117
|
-
return ((newOmega % 360) + 360) % 360;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
module.exports = { integrateAscendingNode };
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The ψ/K amplitude relations + the retired law-loop constructions —
|
|
3
|
-
* THE shared implementation (Phase 8.3, layer L2). Status per relation
|
|
4
|
-
* (doc 10 "The Six Fibonacci Relations"; the restatement: the N-body
|
|
5
|
-
* chain is the planet path):
|
|
6
|
-
* - ψ (computePsiConstant/computeInclinationLaw) and K (computeKConstant/
|
|
7
|
-
* computeEccentricityLaw's amplitude) are OPEN PREDICTIONS — untested
|
|
8
|
-
* empirical amplitude laws, derived from Earth alone, kept as stated.
|
|
9
|
-
* - The wobble beat (computeWobblePeriodYears) is kinematic frame
|
|
10
|
-
* arithmetic — the permanent class.
|
|
11
|
-
* - The obliquity-mean snapshot and the eccentricity base/phase
|
|
12
|
-
* (System-Reset construction) belong to the RETIRED law framework —
|
|
13
|
-
* today serving the legacy scene scaffolding, the no-chain bodies
|
|
14
|
-
* (Pluto/Halley/Eros) and the o.fib* diagnostics (doc 72 — the closed
|
|
15
|
-
* loop; docs/37 is archived, see docs/retired-record.md).
|
|
16
|
-
*
|
|
17
|
-
* Extracted VERBATIM in the BROWSER's expression forms from src/script.js
|
|
18
|
-
* (the ψ loop, calcWobblePeriod, the obliquity-cycle aliases,
|
|
19
|
-
* calcObliquityMean's load-time snapshot branch, the K loop), which
|
|
20
|
-
* tools/lib/constants.js + constants/utils.js hand-mirrored with last-ulp
|
|
21
|
-
* operation-order variants (measured: 32/42 law outputs bit-exact, 10 at
|
|
22
|
-
* the 1e-11..1e-15 relative class) — those variants dissolve here.
|
|
23
|
-
*
|
|
24
|
-
* LOAD-BEARING conventions:
|
|
25
|
-
* - ψ = 3·A_earth·√(M_EARTH_ALONE/M_SUN): the ALONE/SYSTEM mass asymmetry
|
|
26
|
-
* is calibration convention (doc 24) — switching Earth to SYSTEM shifts
|
|
27
|
-
* ψ by 0.612% and would require re-calibrating A_earth.
|
|
28
|
-
* - Wobble = beat of |axial| and |ICRF| RATES (sign-free — Venus's
|
|
29
|
-
* prograde-axial/retrograde-ICRF case); |axial| > 8H ⇒ frozen ⇒
|
|
30
|
-
* wobble = |ICRF| exactly.
|
|
31
|
-
* - The obliquity-mean law here is the SNAPSHOT form (the browser's
|
|
32
|
-
* module-load TDZ fallback — the value both engines actually ship at
|
|
33
|
-
* load); the browser's runtime integrated path stays engine-side with
|
|
34
|
-
* its Phase-8 anchors. Note it uses 1/(H/13), where the runtime
|
|
35
|
-
* integrated form uses 13/H — historical operation orders, preserved.
|
|
36
|
-
* - K-law phase offset: 90° in-phase, 270° anti-phase (Saturn) — the n=7
|
|
37
|
-
* System Reset state (all planets at mean e, Saturn falling).
|
|
38
|
-
* - The Node mirror carried an `else` branch for bodies without a wobble
|
|
39
|
-
* period — DEAD code (the loop is fibonacciD-guarded and all seven
|
|
40
|
-
* carriers have wobble periods); dropped here, recorded in the commit.
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
'use strict';
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* ψ constant from Earth's calibration. @param {{
|
|
47
|
-
* earthInvPlaneInclinationAmplitude: number,
|
|
48
|
-
* massEarthAlone: number, massSun: number }} c @returns {number} */
|
|
49
|
-
function computePsiConstant(c) {
|
|
50
|
-
return 3 * c.earthInvPlaneInclinationAmplitude * Math.sqrt(c.massEarthAlone / c.massSun);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* ψ law: invariable-plane inclination amplitude and mean.
|
|
55
|
-
* @param {{ fibonacciD: number, massFrac: number,
|
|
56
|
-
* invPlaneInclinationJ2000: number, longitudePerihelion: number,
|
|
57
|
-
* inclinationCycleAnchor: number, antiPhase: boolean }} b
|
|
58
|
-
* @param {number} psiConstant
|
|
59
|
-
* @returns {{ amplitude: number, mean: number }} */
|
|
60
|
-
function computeInclinationLaw(b, psiConstant) {
|
|
61
|
-
const amplitude = psiConstant / (b.fibonacciD * Math.sqrt(b.massFrac));
|
|
62
|
-
const antiPhase = b.antiPhase ? -1 : 1;
|
|
63
|
-
const mean = b.invPlaneInclinationJ2000
|
|
64
|
-
- antiPhase * amplitude * Math.cos((b.longitudePerihelion - b.inclinationCycleAnchor) * Math.PI / 180);
|
|
65
|
-
return { amplitude, mean };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// (The device's wobble beat of integer axial and obliquity fractions, the
|
|
69
|
-
// Venus/Neptune |ICRF| obliquity-cycle fallback and the snapshot "mean
|
|
70
|
-
// obliquity" left with plan 06 Phase 7 commit 2: the K law's cycle period is
|
|
71
|
-
// the chain's own g-mode beat (keplerian-chain computeSecularShape) and its
|
|
72
|
-
// obliquity input the derived J2000 obliquity (spin-channel
|
|
73
|
-
// computeObliquityJ2000Deg). docs/retired-record.md carries the record.)
|
|
74
|
-
|
|
75
|
-
// Plan 07 R6: computeKConstant and computeEccentricityLaw stood here — the
|
|
76
|
-
// K relation (K = e_amp·√m·a^1.5 / (sin(tilt)·√d), inverted per planet) and
|
|
77
|
-
// the System-Reset eccentricity construction it fed
|
|
78
|
-
// (base = A·cosθ + √(e_J2000² − A²sin²θ) at the J2000 phase, θ measured on
|
|
79
|
-
// the wobble beat with a 90°/270° anti-phase offset).
|
|
80
|
-
//
|
|
81
|
-
// They are DELETED, not reclassified. Measured first (plan 07 §9e): scaling
|
|
82
|
-
// their outputs by 1.10 moved no scene position and no published record
|
|
83
|
-
// field — both twins place planets from the N-body chain, which overwrites
|
|
84
|
-
// the construction entirely — and the registry keys built on them had no
|
|
85
|
-
// consumer in the docs, on the website or in the paper. The nine balance and
|
|
86
|
-
// Fibonacci-law instruments that computed from them are retired with them;
|
|
87
|
-
// docs/retired-record.md is the record.
|
|
88
|
-
//
|
|
89
|
-
// A planet's eccentricity of date now has one home: the chain
|
|
90
|
-
// (`model.planets.eccentricity(k, year)`), and its long-term shape is the
|
|
91
|
-
// chain's own g-mode structure.
|
|
92
|
-
|
|
93
|
-
module.exports = {
|
|
94
|
-
computePsiConstant, computeInclinationLaw,
|
|
95
|
-
};
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Planet orientation channel — THE shared implementation (Phase 8.3, L4):
|
|
3
|
-
* invariable-plane inclination, ascending nodes, and the scene ecliptic
|
|
4
|
-
* inclination (the balanced-year dot-product form canonicalized at S-P4).
|
|
5
|
-
*
|
|
6
|
-
* Time is EXPLICIT here (yearsSinceBalanced / calendar year). A finding
|
|
7
|
-
* from extraction, preserved not fixed: the browser's
|
|
8
|
-
* computePlanetInvPlaneInclinationDynamic(planet, currentYear) IGNORED its
|
|
9
|
-
* currentYear parameter and read the live scene JD — the 8.3-0 fixtures
|
|
10
|
-
* recorded identical values at every probed epoch. The browser wrapper
|
|
11
|
-
* keeps that scene-coupling (visibly, at the wrapper); the Node engine
|
|
12
|
-
* honors the year as before. Unifying them is a measured decision for the
|
|
13
|
-
* factory layer, not a silent side effect.
|
|
14
|
-
*
|
|
15
|
-
* Two ascending-node conventions exist and BOTH are quantities (the S-P4
|
|
16
|
-
* lesson): the year-2000-anchored linear node here
|
|
17
|
-
* (ascendingNodeInvPlaneLinearAt — the node-integrator mirror)
|
|
18
|
-
* and the balanced-year −8H/N node inside the scene tilt
|
|
19
|
-
* (eclipticInclinationFromBalanced). Do not merge them.
|
|
20
|
-
*
|
|
21
|
-
* SCOPE SINCE v16.2 (owner-found audit): these record-based forms — the
|
|
22
|
-
* planet record's linear lattice rates, the −8H/N node period, the
|
|
23
|
-
* balanced-year inclination oscillation — are the RETIRED device. They serve
|
|
24
|
-
* the structural record and the browser's no-chain bodies (Pluto, Halley,
|
|
25
|
-
* Eros) only. The seven planets' elements of date on every published surface
|
|
26
|
-
* (the simulator, the API's /v1/bodies, the MCP essrt_bodies) ride the N-body
|
|
27
|
-
* Keplerian chain with the series handover (model.js planetChainElementsAt;
|
|
28
|
-
* src/script.js _kcElementsOfDate).
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
'use strict';
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Invariable-plane inclination at explicit time (browser form): the ICRF
|
|
35
|
-
* perihelion-linked oscillation i(t) = mean + s·A·cos(ϖ_ICRF(t) − anchor).
|
|
36
|
-
* @param {{ key?: string, isEarth?: boolean,
|
|
37
|
-
* invPlaneInclinationJ2000: number, invPlaneInclinationMean: number,
|
|
38
|
-
* invPlaneInclinationAmplitude: number, inclinationCycleAnchor: number,
|
|
39
|
-
* longitudePerihelion: number, perihelionEclipticYears: number,
|
|
40
|
-
* antiPhase?: boolean }} body
|
|
41
|
-
* @param {number} yearsSinceBalanced
|
|
42
|
-
* @param {{ H: number, yearsFromBalancedToJ2000: number }} env
|
|
43
|
-
* @returns {number} degrees */
|
|
44
|
-
function invPlaneInclinationAt(body, yearsSinceBalanced, env) {
|
|
45
|
-
const iJ2000 = body.invPlaneInclinationJ2000;
|
|
46
|
-
const amplitude = body.invPlaneInclinationAmplitude;
|
|
47
|
-
if (iJ2000 === undefined || amplitude === undefined) return iJ2000 || 0;
|
|
48
|
-
if (amplitude === 0) return iJ2000;
|
|
49
|
-
|
|
50
|
-
// ICRF period: Earth = H/3 directly; others = 1/(1/eclP − 1/(H/13)).
|
|
51
|
-
const genPrecRate = 1 / (env.H / 13);
|
|
52
|
-
const icrfPeriod = body.isEarth
|
|
53
|
-
? env.H / 3
|
|
54
|
-
: 1 / (1 / body.perihelionEclipticYears - genPrecRate);
|
|
55
|
-
const icrfRate = 360 / icrfPeriod;
|
|
56
|
-
|
|
57
|
-
const periAtBalanced = body.longitudePerihelion - icrfRate * env.yearsFromBalancedToJ2000;
|
|
58
|
-
const periCurrent = periAtBalanced + icrfRate * yearsSinceBalanced;
|
|
59
|
-
const currentPhaseRad = (periCurrent - body.inclinationCycleAnchor) * Math.PI / 180;
|
|
60
|
-
const antiPhaseSign = body.antiPhase ? -1 : 1;
|
|
61
|
-
return body.invPlaneInclinationMean + antiPhaseSign * amplitude * Math.cos(currentPhaseRad);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Ascending node on the invariable plane — the LINEAR year-2000-anchored
|
|
66
|
-
* convention (node-integrator; see the header).
|
|
67
|
-
* @param {{ ascendingNodeInvPlane?: number, ascendingNodePeriod?: number,
|
|
68
|
-
* perihelionEclipticYears: number }} body
|
|
69
|
-
* @param {number} year @returns {number} degrees 0–360 */
|
|
70
|
-
function ascendingNodeInvPlaneLinearAt(body, year) {
|
|
71
|
-
if (!body.ascendingNodeInvPlane) return 0;
|
|
72
|
-
const period = body.ascendingNodePeriod || body.perihelionEclipticYears;
|
|
73
|
-
const rate = 360 / period;
|
|
74
|
-
return ((body.ascendingNodeInvPlane + rate * (year - 2000)) % 360 + 360) % 360;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Scene ecliptic inclination — normal-vector dot product, balanced-year
|
|
79
|
-
* anchoring, planet Ω on the −8H/N assignment (canonicalized at S-P4; the
|
|
80
|
-
* mirror of src/script.js updateDynamicInclinations).
|
|
81
|
-
* @param {{ perihelionEclipticYears: number, longitudePerihelion: number,
|
|
82
|
-
* inclinationCycleAnchor: number, antiPhase?: boolean,
|
|
83
|
-
* invPlaneInclinationMean: number, invPlaneInclinationAmplitude: number,
|
|
84
|
-
* ascendingNodeInvPlane: number, ascendingNodeCyclesIn8H?: number }} body
|
|
85
|
-
* @param {{ invPlanePrecessionYears: number, inclinationMean: number,
|
|
86
|
-
* inclinationAmplitude: number, ascendingNodeInvPlane: number }} earth
|
|
87
|
-
* @param {number} yearsSinceBalanced
|
|
88
|
-
* @param {{ H: number, yearsFromBalancedToJ2000: number }} env
|
|
89
|
-
* @returns {number} degrees */
|
|
90
|
-
function eclipticInclinationFromBalanced(body, earth, yearsSinceBalanced, env) {
|
|
91
|
-
const d2r = Math.PI / 180;
|
|
92
|
-
const genPrecRate = 1 / (env.H / 13);
|
|
93
|
-
|
|
94
|
-
// --- Earth's orbital plane ---
|
|
95
|
-
const earthPhaseRad = (yearsSinceBalanced / earth.invPlanePrecessionYears) * 2 * Math.PI;
|
|
96
|
-
const earthI = (earth.inclinationMean
|
|
97
|
-
- earth.inclinationAmplitude * Math.cos(earthPhaseRad)) * d2r;
|
|
98
|
-
|
|
99
|
-
// Earth Ω regresses at -H/5 (ecliptic precession rate), NOT at H/3.
|
|
100
|
-
const earthAscNodePeriod = -env.H / 5;
|
|
101
|
-
const earthOmegaRate = 360 / earthAscNodePeriod;
|
|
102
|
-
const earthOmega = (earth.ascendingNodeInvPlane
|
|
103
|
-
- earthOmegaRate * env.yearsFromBalancedToJ2000
|
|
104
|
-
+ earthOmegaRate * yearsSinceBalanced) * d2r;
|
|
105
|
-
|
|
106
|
-
// --- Planet's orbital plane ---
|
|
107
|
-
const eclRate = 1 / body.perihelionEclipticYears;
|
|
108
|
-
const icrfRate = (eclRate - genPrecRate) * 360; // deg/yr
|
|
109
|
-
const periICRFDeg = body.longitudePerihelion
|
|
110
|
-
- icrfRate * env.yearsFromBalancedToJ2000
|
|
111
|
-
+ icrfRate * yearsSinceBalanced;
|
|
112
|
-
|
|
113
|
-
const planetPhaseDeg = periICRFDeg - body.inclinationCycleAnchor;
|
|
114
|
-
const antiPhaseSign = body.antiPhase ? -1 : 1;
|
|
115
|
-
const planetI = (body.invPlaneInclinationMean
|
|
116
|
-
+ antiPhaseSign * body.invPlaneInclinationAmplitude * Math.cos(planetPhaseDeg * d2r)) * d2r;
|
|
117
|
-
|
|
118
|
-
// Planet Ω advances at the asc-node period (-8H/N), NOT the ecliptic
|
|
119
|
-
// perihelion period — they are different angles.
|
|
120
|
-
const planetAscNodePeriod = body.ascendingNodeCyclesIn8H
|
|
121
|
-
? -(8 * env.H) / body.ascendingNodeCyclesIn8H
|
|
122
|
-
: body.perihelionEclipticYears;
|
|
123
|
-
const planetOmegaRate = 360 / planetAscNodePeriod;
|
|
124
|
-
const planetOmegaDeg = body.ascendingNodeInvPlane
|
|
125
|
-
- planetOmegaRate * env.yearsFromBalancedToJ2000
|
|
126
|
-
+ planetOmegaRate * yearsSinceBalanced;
|
|
127
|
-
const planetOmega = planetOmegaDeg * d2r;
|
|
128
|
-
|
|
129
|
-
// --- Dot product of normal vectors → angle between orbital planes ---
|
|
130
|
-
const eNx = Math.sin(earthI) * Math.sin(earthOmega);
|
|
131
|
-
const eNy = Math.sin(earthI) * Math.cos(earthOmega);
|
|
132
|
-
const eNz = Math.cos(earthI);
|
|
133
|
-
|
|
134
|
-
const pNx = Math.sin(planetI) * Math.sin(planetOmega);
|
|
135
|
-
const pNy = Math.sin(planetI) * Math.cos(planetOmega);
|
|
136
|
-
const pNz = Math.cos(planetI);
|
|
137
|
-
|
|
138
|
-
const cosAngle = eNx * pNx + eNy * pNy + eNz * pNz;
|
|
139
|
-
return Math.acos(Math.max(-1, Math.min(1, cosAngle))) * (180 / Math.PI);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
module.exports = { invPlaneInclinationAt, ascendingNodeInvPlaneLinearAt, eclipticInclinationFromBalanced };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param {{ ascendingNodeDeg: number, inclinationDeg: number }} tilt —
|
|
3
|
-
* static node and inclination (engine-decomposed from its scene scheme)
|
|
4
|
-
* @param {number} currentYear
|
|
5
|
-
* @param {{
|
|
6
|
-
* obliquityAt: (year: number) => number,
|
|
7
|
-
* earthInclinationAt: (year: number) => number,
|
|
8
|
-
* obliquityExtremaInRange: (yearMin: number, yearMax: number) => number[],
|
|
9
|
-
* inclinationCrossingsInRange: (inclinationDeg: number, yearMin: number, yearMax: number) => number[],
|
|
10
|
-
* eclipticInclinationAt: ((year: number) => number) | null,
|
|
11
|
-
* earthInclinationMeanDeg: number,
|
|
12
|
-
* earthInclinationAmplitudeDeg: number,
|
|
13
|
-
* epochYear?: number,
|
|
14
|
-
* }} deps — eclipticInclinationAt non-null enables the dynamic-inclination
|
|
15
|
-
* crossover search and per-segment rates (the planetName path).
|
|
16
|
-
* @returns {number} dynamic ascending node longitude, degrees 0–360
|
|
17
|
-
*/
|
|
18
|
-
export function integrateAscendingNode(tilt: {
|
|
19
|
-
ascendingNodeDeg: number;
|
|
20
|
-
inclinationDeg: number;
|
|
21
|
-
}, currentYear: number, deps: {
|
|
22
|
-
obliquityAt: (year: number) => number;
|
|
23
|
-
earthInclinationAt: (year: number) => number;
|
|
24
|
-
obliquityExtremaInRange: (yearMin: number, yearMax: number) => number[];
|
|
25
|
-
inclinationCrossingsInRange: (inclinationDeg: number, yearMin: number, yearMax: number) => number[];
|
|
26
|
-
eclipticInclinationAt: ((year: number) => number) | null;
|
|
27
|
-
earthInclinationMeanDeg: number;
|
|
28
|
-
earthInclinationAmplitudeDeg: number;
|
|
29
|
-
epochYear?: number;
|
|
30
|
-
}): number;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ψ constant from Earth's calibration. @param {{
|
|
3
|
-
* earthInvPlaneInclinationAmplitude: number,
|
|
4
|
-
* massEarthAlone: number, massSun: number }} c @returns {number} */
|
|
5
|
-
export function computePsiConstant(c: {
|
|
6
|
-
earthInvPlaneInclinationAmplitude: number;
|
|
7
|
-
massEarthAlone: number;
|
|
8
|
-
massSun: number;
|
|
9
|
-
}): number;
|
|
10
|
-
/**
|
|
11
|
-
* ψ law: invariable-plane inclination amplitude and mean.
|
|
12
|
-
* @param {{ fibonacciD: number, massFrac: number,
|
|
13
|
-
* invPlaneInclinationJ2000: number, longitudePerihelion: number,
|
|
14
|
-
* inclinationCycleAnchor: number, antiPhase: boolean }} b
|
|
15
|
-
* @param {number} psiConstant
|
|
16
|
-
* @returns {{ amplitude: number, mean: number }} */
|
|
17
|
-
export function computeInclinationLaw(b: {
|
|
18
|
-
fibonacciD: number;
|
|
19
|
-
massFrac: number;
|
|
20
|
-
invPlaneInclinationJ2000: number;
|
|
21
|
-
longitudePerihelion: number;
|
|
22
|
-
inclinationCycleAnchor: number;
|
|
23
|
-
antiPhase: boolean;
|
|
24
|
-
}, psiConstant: number): {
|
|
25
|
-
amplitude: number;
|
|
26
|
-
mean: number;
|
|
27
|
-
};
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Invariable-plane inclination at explicit time (browser form): the ICRF
|
|
3
|
-
* perihelion-linked oscillation i(t) = mean + s·A·cos(ϖ_ICRF(t) − anchor).
|
|
4
|
-
* @param {{ key?: string, isEarth?: boolean,
|
|
5
|
-
* invPlaneInclinationJ2000: number, invPlaneInclinationMean: number,
|
|
6
|
-
* invPlaneInclinationAmplitude: number, inclinationCycleAnchor: number,
|
|
7
|
-
* longitudePerihelion: number, perihelionEclipticYears: number,
|
|
8
|
-
* antiPhase?: boolean }} body
|
|
9
|
-
* @param {number} yearsSinceBalanced
|
|
10
|
-
* @param {{ H: number, yearsFromBalancedToJ2000: number }} env
|
|
11
|
-
* @returns {number} degrees */
|
|
12
|
-
export function invPlaneInclinationAt(body: {
|
|
13
|
-
key?: string;
|
|
14
|
-
isEarth?: boolean;
|
|
15
|
-
invPlaneInclinationJ2000: number;
|
|
16
|
-
invPlaneInclinationMean: number;
|
|
17
|
-
invPlaneInclinationAmplitude: number;
|
|
18
|
-
inclinationCycleAnchor: number;
|
|
19
|
-
longitudePerihelion: number;
|
|
20
|
-
perihelionEclipticYears: number;
|
|
21
|
-
antiPhase?: boolean;
|
|
22
|
-
}, yearsSinceBalanced: number, env: {
|
|
23
|
-
H: number;
|
|
24
|
-
yearsFromBalancedToJ2000: number;
|
|
25
|
-
}): number;
|
|
26
|
-
/**
|
|
27
|
-
* Ascending node on the invariable plane — the LINEAR year-2000-anchored
|
|
28
|
-
* convention (node-integrator; see the header).
|
|
29
|
-
* @param {{ ascendingNodeInvPlane?: number, ascendingNodePeriod?: number,
|
|
30
|
-
* perihelionEclipticYears: number }} body
|
|
31
|
-
* @param {number} year @returns {number} degrees 0–360 */
|
|
32
|
-
export function ascendingNodeInvPlaneLinearAt(body: {
|
|
33
|
-
ascendingNodeInvPlane?: number;
|
|
34
|
-
ascendingNodePeriod?: number;
|
|
35
|
-
perihelionEclipticYears: number;
|
|
36
|
-
}, year: number): number;
|
|
37
|
-
/**
|
|
38
|
-
* Scene ecliptic inclination — normal-vector dot product, balanced-year
|
|
39
|
-
* anchoring, planet Ω on the −8H/N assignment (canonicalized at S-P4; the
|
|
40
|
-
* mirror of src/script.js updateDynamicInclinations).
|
|
41
|
-
* @param {{ perihelionEclipticYears: number, longitudePerihelion: number,
|
|
42
|
-
* inclinationCycleAnchor: number, antiPhase?: boolean,
|
|
43
|
-
* invPlaneInclinationMean: number, invPlaneInclinationAmplitude: number,
|
|
44
|
-
* ascendingNodeInvPlane: number, ascendingNodeCyclesIn8H?: number }} body
|
|
45
|
-
* @param {{ invPlanePrecessionYears: number, inclinationMean: number,
|
|
46
|
-
* inclinationAmplitude: number, ascendingNodeInvPlane: number }} earth
|
|
47
|
-
* @param {number} yearsSinceBalanced
|
|
48
|
-
* @param {{ H: number, yearsFromBalancedToJ2000: number }} env
|
|
49
|
-
* @returns {number} degrees */
|
|
50
|
-
export function eclipticInclinationFromBalanced(body: {
|
|
51
|
-
perihelionEclipticYears: number;
|
|
52
|
-
longitudePerihelion: number;
|
|
53
|
-
inclinationCycleAnchor: number;
|
|
54
|
-
antiPhase?: boolean;
|
|
55
|
-
invPlaneInclinationMean: number;
|
|
56
|
-
invPlaneInclinationAmplitude: number;
|
|
57
|
-
ascendingNodeInvPlane: number;
|
|
58
|
-
ascendingNodeCyclesIn8H?: number;
|
|
59
|
-
}, earth: {
|
|
60
|
-
invPlanePrecessionYears: number;
|
|
61
|
-
inclinationMean: number;
|
|
62
|
-
inclinationAmplitude: number;
|
|
63
|
-
ascendingNodeInvPlane: number;
|
|
64
|
-
}, yearsSinceBalanced: number, env: {
|
|
65
|
-
H: number;
|
|
66
|
-
yearsFromBalancedToJ2000: number;
|
|
67
|
-
}): number;
|