caelus 0.11.0 → 0.12.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/dist/src/chart.d.ts +193 -13
- package/dist/src/chart.js +163 -13
- package/dist/src/compiler.d.ts +44 -3
- package/dist/src/compiler.js +44 -3
- package/dist/src/core.d.ts +33 -2
- package/dist/src/core.js +33 -2
- package/dist/src/derived.d.ts +91 -2
- package/dist/src/derived.js +91 -2
- package/dist/src/eclipses.d.ts +17 -1
- package/dist/src/eclipses.js +17 -1
- package/dist/src/events.d.ts +53 -7
- package/dist/src/events.js +53 -7
- package/dist/src/features.d.ts +69 -7
- package/dist/src/features.js +69 -7
- package/dist/src/houses.d.ts +13 -4
- package/dist/src/houses.js +13 -4
- package/dist/src/pheno.d.ts +16 -2
- package/dist/src/pheno.js +16 -2
- package/dist/src/query.d.ts +47 -6
- package/dist/src/query.js +47 -6
- package/dist/src/turbo.d.ts +35 -1
- package/dist/src/turbo.js +35 -1
- package/package.json +1 -1
package/dist/src/features.js
CHANGED
|
@@ -13,8 +13,15 @@ import { DEG } from "./core.js";
|
|
|
13
13
|
import { rankMoments } from "./scan.js";
|
|
14
14
|
export const DEFAULT_BODIES = ["sun", "moon", "mercury", "venus", "mars",
|
|
15
15
|
"jupiter", "saturn", "uranus", "neptune", "pluto"];
|
|
16
|
-
/**
|
|
17
|
-
*
|
|
16
|
+
/**
|
|
17
|
+
* Build a feature vector from explicit `(longitude, weight)` pairs: each pair
|
|
18
|
+
* contributes a weighted unit-circle point `[w·cos(lon), w·sin(lon)]`. The
|
|
19
|
+
* low-level primitive behind {@link chartFeatures}; most callers want that.
|
|
20
|
+
*
|
|
21
|
+
* @param weightedLons `[longitudeDeg, weight]` pairs, in the order they should
|
|
22
|
+
* appear in the vector.
|
|
23
|
+
* @returns A flat vector, two entries per pair.
|
|
24
|
+
*/
|
|
18
25
|
export function featureVector(weightedLons) {
|
|
19
26
|
const out = [];
|
|
20
27
|
for (const [lon, w] of weightedLons) {
|
|
@@ -23,7 +30,15 @@ export function featureVector(weightedLons) {
|
|
|
23
30
|
}
|
|
24
31
|
return out;
|
|
25
32
|
}
|
|
26
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* Cosine similarity of two feature vectors, in `[-1, 1]`. For vectors from
|
|
35
|
+
* {@link chartFeatures} this is a weighted mean of `cos(Δlongitude)` per body:
|
|
36
|
+
* `1` when the configurations coincide, falling off as bodies diverge.
|
|
37
|
+
*
|
|
38
|
+
* @param a First feature vector.
|
|
39
|
+
* @param b Second feature vector (compared over the shorter length).
|
|
40
|
+
* @returns Similarity in `[-1, 1]`; `0` if either vector is all zeros.
|
|
41
|
+
*/
|
|
27
42
|
export function cosineSimilarity(a, b) {
|
|
28
43
|
let dot = 0, na = 0, nb = 0;
|
|
29
44
|
const n = Math.min(a.length, b.length);
|
|
@@ -36,7 +51,26 @@ export function cosineSimilarity(a, b) {
|
|
|
36
51
|
return 0;
|
|
37
52
|
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
38
53
|
}
|
|
39
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Encode the sky at an instant as a feature vector: each body's ecliptic
|
|
56
|
+
* longitude becomes a weighted unit-circle point. The deterministic substrate
|
|
57
|
+
* for matching and searching chart configurations — compare two with
|
|
58
|
+
* {@link cosineSimilarity}, or rank a time range against one with
|
|
59
|
+
* {@link searchConfigurations}.
|
|
60
|
+
*
|
|
61
|
+
* @param engine The engine used to evaluate positions.
|
|
62
|
+
* @param jdUt Julian Day in UT.
|
|
63
|
+
* @param opts `bodies` (ordered; defaults to the ten major bodies), per-body
|
|
64
|
+
* `weights`, and `zodiac` (tropical by default).
|
|
65
|
+
* @returns A flat vector `[w·cos(lon), w·sin(lon), ...]`, two entries per body
|
|
66
|
+
* in `bodies` order.
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const target = chartFeatures(engine, julianDay(2000, 1, 1));
|
|
70
|
+
* const now = chartFeatures(engine, julianDay(2025, 6, 1));
|
|
71
|
+
* cosineSimilarity(now, target); // 1 = identical configuration
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
40
74
|
export function chartFeatures(engine, jdUt, opts = {}) {
|
|
41
75
|
const bodies = opts.bodies ?? DEFAULT_BODIES;
|
|
42
76
|
const zodiac = opts.zodiac ?? "tropical";
|
|
@@ -46,12 +80,40 @@ export function chartFeatures(engine, jdUt, opts = {}) {
|
|
|
46
80
|
]);
|
|
47
81
|
return featureVector(wl);
|
|
48
82
|
}
|
|
49
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Similarity between the sky at `jdUt` and a target feature vector — shorthand
|
|
85
|
+
* for `cosineSimilarity(chartFeatures(engine, jdUt, opts), target)`. The scoring
|
|
86
|
+
* function {@link searchConfigurations} maximizes.
|
|
87
|
+
*
|
|
88
|
+
* @param engine The engine used to evaluate positions.
|
|
89
|
+
* @param jdUt Julian Day in UT.
|
|
90
|
+
* @param target A target feature vector from {@link chartFeatures}.
|
|
91
|
+
* @param opts {@link FeatureOptions} — must match those used to build `target`.
|
|
92
|
+
* @returns Cosine similarity in `[-1, 1]`.
|
|
93
|
+
*/
|
|
50
94
|
export function configurationFit(engine, jdUt, target, opts = {}) {
|
|
51
95
|
return cosineSimilarity(chartFeatures(engine, jdUt, opts), target);
|
|
52
96
|
}
|
|
53
|
-
/**
|
|
54
|
-
*
|
|
97
|
+
/**
|
|
98
|
+
* Rank the instants in `[start, end]` by how closely the sky resembles a
|
|
99
|
+
* `target` feature vector, best first — a realization search over the feature
|
|
100
|
+
* space. Build `target` with {@link chartFeatures} (e.g. from a natal chart).
|
|
101
|
+
*
|
|
102
|
+
* @param engine The engine used to evaluate positions.
|
|
103
|
+
* @param target A target feature vector from {@link chartFeatures}.
|
|
104
|
+
* @param opts `start`/`end` (Julian Days, UT) and `step` (days) define the
|
|
105
|
+
* scan, `limit` caps the results, plus the {@link FeatureOptions} (`bodies`,
|
|
106
|
+
* `weights`, `zodiac`) — which must match those used to build `target`.
|
|
107
|
+
* @returns Ranked `{ jd, score }` moments, highest similarity first.
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const natal = chartFeatures(engine, julianDay(1990, 6, 10, 14, 30));
|
|
111
|
+
* const matches = searchConfigurations(engine, natal, {
|
|
112
|
+
* start: julianDay(2025, 1, 1), end: julianDay(2026, 1, 1), step: 1, limit: 5,
|
|
113
|
+
* });
|
|
114
|
+
* matches[0].jd; // best-matching instant
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
55
117
|
export function searchConfigurations(engine, target, opts) {
|
|
56
118
|
return rankMoments({ start: opts.start, end: opts.end, step: opts.step, limit: opts.limit }, (jd) => configurationFit(engine, jd, target, opts));
|
|
57
119
|
}
|
package/dist/src/houses.d.ts
CHANGED
|
@@ -41,9 +41,18 @@ export declare function housesPolichPage(armc: number, phi: number, eps: number)
|
|
|
41
41
|
/** Vehlow: equal houses with the ASC at the middle of house 1. */
|
|
42
42
|
export declare function housesVehlow(armc: number, phi: number, eps: number): number[];
|
|
43
43
|
/**
|
|
44
|
-
* Placidus cusps via the classic iterative
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
44
|
+
* Placidus house cusps via the classic iterative semi-arc scheme: for all four
|
|
45
|
+
* intermediate cusps RA = ARMC + offset + f·AD with AD = asin(tan φ · tan δ);
|
|
46
|
+
* offsets 30/60/120/150, f = 1/3, 2/3, 2/3, 1/3. Undefined above the polar
|
|
47
|
+
* circles, as Placidus itself is.
|
|
48
|
+
*
|
|
49
|
+
* Low-level: {@link Engine.chart} calls this for you when the house system is
|
|
50
|
+
* `"placidus"`, falling back to whole-sign near the poles. Inputs and outputs
|
|
51
|
+
* are in **radians**.
|
|
52
|
+
*
|
|
53
|
+
* @param armc Right ascension of the MC, in radians.
|
|
54
|
+
* @param phi Geographic latitude, in radians.
|
|
55
|
+
* @param eps Obliquity of the ecliptic, in radians.
|
|
56
|
+
* @returns The twelve cusp longitudes in radians, house 1 (Ascendant) first.
|
|
48
57
|
*/
|
|
49
58
|
export declare function housesPlacidus(armc: number, phi: number, eps: number): number[];
|
package/dist/src/houses.js
CHANGED
|
@@ -257,10 +257,19 @@ export function housesVehlow(armc, phi, eps) {
|
|
|
257
257
|
return Array.from({ length: 12 }, (_, i) => mod(asc - 15 * DEG + i * 30 * DEG, TWO_PI));
|
|
258
258
|
}
|
|
259
259
|
/**
|
|
260
|
-
* Placidus cusps via the classic iterative
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
260
|
+
* Placidus house cusps via the classic iterative semi-arc scheme: for all four
|
|
261
|
+
* intermediate cusps RA = ARMC + offset + f·AD with AD = asin(tan φ · tan δ);
|
|
262
|
+
* offsets 30/60/120/150, f = 1/3, 2/3, 2/3, 1/3. Undefined above the polar
|
|
263
|
+
* circles, as Placidus itself is.
|
|
264
|
+
*
|
|
265
|
+
* Low-level: {@link Engine.chart} calls this for you when the house system is
|
|
266
|
+
* `"placidus"`, falling back to whole-sign near the poles. Inputs and outputs
|
|
267
|
+
* are in **radians**.
|
|
268
|
+
*
|
|
269
|
+
* @param armc Right ascension of the MC, in radians.
|
|
270
|
+
* @param phi Geographic latitude, in radians.
|
|
271
|
+
* @param eps Obliquity of the ecliptic, in radians.
|
|
272
|
+
* @returns The twelve cusp longitudes in radians, house 1 (Ascendant) first.
|
|
264
273
|
*/
|
|
265
274
|
export function housesPlacidus(armc, phi, eps) {
|
|
266
275
|
const cusp = (offsetDeg, f) => {
|
package/dist/src/pheno.d.ts
CHANGED
|
@@ -19,8 +19,22 @@ export interface Pheno {
|
|
|
19
19
|
diameter: number;
|
|
20
20
|
magnitude: number;
|
|
21
21
|
}
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
22
|
+
/**
|
|
23
|
+
* Photometric and apparent-geometry quantities for a body at an instant: its
|
|
24
|
+
* phase angle, illuminated fraction, elongation from the Sun, apparent disc
|
|
25
|
+
* diameter, and apparent visual magnitude.
|
|
26
|
+
*
|
|
27
|
+
* @param engine The engine used to evaluate positions.
|
|
28
|
+
* @param body A body with known physical dimensions (Sun, Moon, the planets).
|
|
29
|
+
* @param jdUt Julian Day (UT).
|
|
30
|
+
* @returns A {@link Pheno}: `phaseAngle` (deg), `phase` (lit fraction `0`–`1`),
|
|
31
|
+
* `elongation` (deg), `diameter` (deg), and `magnitude`.
|
|
32
|
+
* @throws Error if `body` has no photometric data.
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* pheno(engine, "venus", julianDay(2025, 6, 1)).phase; // illuminated fraction
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
24
38
|
export declare function pheno(engine: Engine, body: BodyId, jdUt: number): Pheno;
|
|
25
39
|
/** Apparent minus mean solar time, minutes (Meeus ch. 28). */
|
|
26
40
|
export declare function equationOfTime(engine: Engine, jdUt: number): number;
|
package/dist/src/pheno.js
CHANGED
|
@@ -66,8 +66,22 @@ function magnitude(body, a, r, dlt, jde, lonDeg, latDeg) {
|
|
|
66
66
|
return x - 1.01;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
69
|
+
/**
|
|
70
|
+
* Photometric and apparent-geometry quantities for a body at an instant: its
|
|
71
|
+
* phase angle, illuminated fraction, elongation from the Sun, apparent disc
|
|
72
|
+
* diameter, and apparent visual magnitude.
|
|
73
|
+
*
|
|
74
|
+
* @param engine The engine used to evaluate positions.
|
|
75
|
+
* @param body A body with known physical dimensions (Sun, Moon, the planets).
|
|
76
|
+
* @param jdUt Julian Day (UT).
|
|
77
|
+
* @returns A {@link Pheno}: `phaseAngle` (deg), `phase` (lit fraction `0`–`1`),
|
|
78
|
+
* `elongation` (deg), `diameter` (deg), and `magnitude`.
|
|
79
|
+
* @throws Error if `body` has no photometric data.
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* pheno(engine, "venus", julianDay(2025, 6, 1)).phase; // illuminated fraction
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
71
85
|
export function pheno(engine, body, jdUt) {
|
|
72
86
|
if (DIAMETER_KM[body] === undefined) {
|
|
73
87
|
throw new Error(`pheno not available for '${body}'`);
|
package/dist/src/query.d.ts
CHANGED
|
@@ -6,8 +6,26 @@ export interface Predicate {
|
|
|
6
6
|
(engine: Engine, t: number): number;
|
|
7
7
|
bodies: Set<string>;
|
|
8
8
|
}
|
|
9
|
-
/**
|
|
10
|
-
*
|
|
9
|
+
/**
|
|
10
|
+
* A {@link Predicate} that holds while `body` is within `orb` degrees of an
|
|
11
|
+
* exact aspect to `target`. Feed it to {@link when} to find the time windows,
|
|
12
|
+
* or compose it with {@link allOf}/{@link anyOf}.
|
|
13
|
+
*
|
|
14
|
+
* @param body The transiting body.
|
|
15
|
+
* @param kind Aspect name, e.g. `"conjunction"`, `"square"`, `"trine"`,
|
|
16
|
+
* `"opposition"`, `"sextile"`.
|
|
17
|
+
* @param target The aspect target: a fixed ecliptic longitude in degrees (e.g.
|
|
18
|
+
* a natal point) or another body id (a mutual aspect).
|
|
19
|
+
* @param orb Half-width of the window in degrees. Defaults to `1.0`.
|
|
20
|
+
* @param zodiac Zodiac for the longitudes. Defaults to tropical.
|
|
21
|
+
* @returns A predicate, true while within orb of the exact aspect.
|
|
22
|
+
* @throws Error if `kind` is not a known aspect.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const natalSun = 79.3;
|
|
26
|
+
* when(engine, aspect("saturn", "square", natalSun, 1), jd0, jd1); // Saturn squares
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
11
29
|
export declare function aspect(body: BodyId, kind: string, target: number | BodyId, orb?: number, zodiac?: Zodiac): Predicate;
|
|
12
30
|
/** True while `body` is in `sign` (index 0=Aries..11=Pisces, or name). */
|
|
13
31
|
export declare function inSign(body: BodyId, sign: number | string, zodiac?: Zodiac): Predicate;
|
|
@@ -25,8 +43,31 @@ export interface WhenOptions {
|
|
|
25
43
|
step?: number;
|
|
26
44
|
maxIntervals?: number;
|
|
27
45
|
}
|
|
28
|
-
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
46
|
+
/**
|
|
47
|
+
* Solve for the time intervals within `[jdStart, jdEnd]` (UT Julian Days) where
|
|
48
|
+
* a {@link Predicate} holds. Predicates compose from {@link aspect},
|
|
49
|
+
* {@link inSign}, {@link retrograde}, {@link notRetrograde}, and the
|
|
50
|
+
* {@link allOf}/{@link anyOf} combinators, so one call answers questions like
|
|
51
|
+
* "when is Venus in Taurus while Mercury is direct?".
|
|
52
|
+
*
|
|
53
|
+
* Returned intervals are sorted and disjoint; endpoints touching the range
|
|
54
|
+
* bounds are clamped. The scan step defaults to 0.125 d when a fast body (Moon,
|
|
55
|
+
* nodes, Lilith) is involved and 1 d otherwise — override it with `opts.step`.
|
|
56
|
+
*
|
|
57
|
+
* @param engine The engine used to evaluate positions.
|
|
58
|
+
* @param predicate A celestial predicate (see {@link aspect}, {@link inSign}).
|
|
59
|
+
* @param jdStart Start of the search window, Julian Day (UT).
|
|
60
|
+
* @param jdEnd End of the search window, Julian Day (UT).
|
|
61
|
+
* @param opts `step` (scan resolution in days) and `maxIntervals`.
|
|
62
|
+
* @returns Sorted, disjoint `[startUt, endUt]` intervals where the predicate is
|
|
63
|
+
* true.
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const windows = when(
|
|
67
|
+
* engine,
|
|
68
|
+
* allOf(inSign("venus", "Taurus"), notRetrograde("mercury")),
|
|
69
|
+
* julianDay(2025, 1, 1), julianDay(2026, 1, 1),
|
|
70
|
+
* );
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
32
73
|
export declare function when(engine: Engine, predicate: Predicate, jdStart: number, jdEnd: number, opts?: WhenOptions): Interval[];
|
package/dist/src/query.js
CHANGED
|
@@ -35,8 +35,26 @@ function mk(fn, bodies) {
|
|
|
35
35
|
return p;
|
|
36
36
|
}
|
|
37
37
|
// ---------------------------------------------------------------- predicates
|
|
38
|
-
/**
|
|
39
|
-
*
|
|
38
|
+
/**
|
|
39
|
+
* A {@link Predicate} that holds while `body` is within `orb` degrees of an
|
|
40
|
+
* exact aspect to `target`. Feed it to {@link when} to find the time windows,
|
|
41
|
+
* or compose it with {@link allOf}/{@link anyOf}.
|
|
42
|
+
*
|
|
43
|
+
* @param body The transiting body.
|
|
44
|
+
* @param kind Aspect name, e.g. `"conjunction"`, `"square"`, `"trine"`,
|
|
45
|
+
* `"opposition"`, `"sextile"`.
|
|
46
|
+
* @param target The aspect target: a fixed ecliptic longitude in degrees (e.g.
|
|
47
|
+
* a natal point) or another body id (a mutual aspect).
|
|
48
|
+
* @param orb Half-width of the window in degrees. Defaults to `1.0`.
|
|
49
|
+
* @param zodiac Zodiac for the longitudes. Defaults to tropical.
|
|
50
|
+
* @returns A predicate, true while within orb of the exact aspect.
|
|
51
|
+
* @throws Error if `kind` is not a known aspect.
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* const natalSun = 79.3;
|
|
55
|
+
* when(engine, aspect("saturn", "square", natalSun, 1), jd0, jd1); // Saturn squares
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
40
58
|
export function aspect(body, kind, target, orb = 1.0, zodiac = "tropical") {
|
|
41
59
|
const ang = QUERY_ASPECTS[kind];
|
|
42
60
|
if (ang === undefined)
|
|
@@ -117,10 +135,33 @@ function bisect(f, a, b, tol = 1e-6) {
|
|
|
117
135
|
}
|
|
118
136
|
return 0.5 * (a + b);
|
|
119
137
|
}
|
|
120
|
-
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
138
|
+
/**
|
|
139
|
+
* Solve for the time intervals within `[jdStart, jdEnd]` (UT Julian Days) where
|
|
140
|
+
* a {@link Predicate} holds. Predicates compose from {@link aspect},
|
|
141
|
+
* {@link inSign}, {@link retrograde}, {@link notRetrograde}, and the
|
|
142
|
+
* {@link allOf}/{@link anyOf} combinators, so one call answers questions like
|
|
143
|
+
* "when is Venus in Taurus while Mercury is direct?".
|
|
144
|
+
*
|
|
145
|
+
* Returned intervals are sorted and disjoint; endpoints touching the range
|
|
146
|
+
* bounds are clamped. The scan step defaults to 0.125 d when a fast body (Moon,
|
|
147
|
+
* nodes, Lilith) is involved and 1 d otherwise — override it with `opts.step`.
|
|
148
|
+
*
|
|
149
|
+
* @param engine The engine used to evaluate positions.
|
|
150
|
+
* @param predicate A celestial predicate (see {@link aspect}, {@link inSign}).
|
|
151
|
+
* @param jdStart Start of the search window, Julian Day (UT).
|
|
152
|
+
* @param jdEnd End of the search window, Julian Day (UT).
|
|
153
|
+
* @param opts `step` (scan resolution in days) and `maxIntervals`.
|
|
154
|
+
* @returns Sorted, disjoint `[startUt, endUt]` intervals where the predicate is
|
|
155
|
+
* true.
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* const windows = when(
|
|
159
|
+
* engine,
|
|
160
|
+
* allOf(inSign("venus", "Taurus"), notRetrograde("mercury")),
|
|
161
|
+
* julianDay(2025, 1, 1), julianDay(2026, 1, 1),
|
|
162
|
+
* );
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
124
165
|
export function when(engine, predicate, jdStart, jdEnd, opts = {}) {
|
|
125
166
|
let step = opts.step;
|
|
126
167
|
if (step === undefined) {
|
package/dist/src/turbo.d.ts
CHANGED
|
@@ -9,12 +9,46 @@ export interface TurboPack {
|
|
|
9
9
|
zodiac: string;
|
|
10
10
|
bodies: Record<string, TurboBody>;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Runtime evaluator for a **turbo pack** — a segmented Chebyshev fit of the
|
|
14
|
+
* engine's apparent longitude over a fixed range and body set. Evaluating a
|
|
15
|
+
* longitude costs a couple dozen multiply-adds, so a century-scale transit scan
|
|
16
|
+
* that calls it tens of thousands of times runs in milliseconds. Construct one
|
|
17
|
+
* from a pack you minted offline; it does no fitting, no I/O, and needs no
|
|
18
|
+
* {@link Engine}.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const turbo = new Turbo(pack); // a TurboPack generated for your range/bodies
|
|
23
|
+
* if (turbo.has("mars")) turbo.longitude("mars", jd);
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
12
26
|
export declare class Turbo {
|
|
27
|
+
/** Start of the pack's valid Julian Day (UT) range. */
|
|
13
28
|
readonly jd0: number;
|
|
29
|
+
/** End of the pack's valid Julian Day (UT) range. */
|
|
14
30
|
readonly jd1: number;
|
|
15
31
|
private readonly bodies;
|
|
32
|
+
/**
|
|
33
|
+
* @param pack A {@link TurboPack}: the fitted segments plus its `jd0`/`jd1`
|
|
34
|
+
* range, minted offline for your bodies and span.
|
|
35
|
+
*/
|
|
16
36
|
constructor(pack: TurboPack);
|
|
37
|
+
/**
|
|
38
|
+
* Whether this pack can evaluate a given body.
|
|
39
|
+
*
|
|
40
|
+
* @param body Body id to test.
|
|
41
|
+
* @returns `true` if {@link Turbo.longitude} accepts `body`.
|
|
42
|
+
*/
|
|
17
43
|
has(body: string): boolean;
|
|
18
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Apparent ecliptic longitude (degrees) of a body from the turbo pack, in the
|
|
46
|
+
* pack's own zodiac. The hot path for bulk scans.
|
|
47
|
+
*
|
|
48
|
+
* @param body A body id the pack contains (see {@link Turbo.has}).
|
|
49
|
+
* @param jd Julian Day (UT), within `[jd0, jd1]`.
|
|
50
|
+
* @returns Ecliptic longitude in degrees, `[0, 360)`.
|
|
51
|
+
* @throws Error if the pack lacks `body`, or `jd` is outside `[jd0, jd1]`.
|
|
52
|
+
*/
|
|
19
53
|
longitude(body: string, jd: number): number;
|
|
20
54
|
}
|
package/dist/src/turbo.js
CHANGED
|
@@ -22,19 +22,53 @@ function clenshaw(coeffs, x) {
|
|
|
22
22
|
}
|
|
23
23
|
return x * b0 - b1 + coeffs[0];
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Runtime evaluator for a **turbo pack** — a segmented Chebyshev fit of the
|
|
27
|
+
* engine's apparent longitude over a fixed range and body set. Evaluating a
|
|
28
|
+
* longitude costs a couple dozen multiply-adds, so a century-scale transit scan
|
|
29
|
+
* that calls it tens of thousands of times runs in milliseconds. Construct one
|
|
30
|
+
* from a pack you minted offline; it does no fitting, no I/O, and needs no
|
|
31
|
+
* {@link Engine}.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* const turbo = new Turbo(pack); // a TurboPack generated for your range/bodies
|
|
36
|
+
* if (turbo.has("mars")) turbo.longitude("mars", jd);
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
25
39
|
export class Turbo {
|
|
40
|
+
/** Start of the pack's valid Julian Day (UT) range. */
|
|
26
41
|
jd0;
|
|
42
|
+
/** End of the pack's valid Julian Day (UT) range. */
|
|
27
43
|
jd1;
|
|
28
44
|
bodies;
|
|
45
|
+
/**
|
|
46
|
+
* @param pack A {@link TurboPack}: the fitted segments plus its `jd0`/`jd1`
|
|
47
|
+
* range, minted offline for your bodies and span.
|
|
48
|
+
*/
|
|
29
49
|
constructor(pack) {
|
|
30
50
|
this.jd0 = pack.jd0;
|
|
31
51
|
this.jd1 = pack.jd1;
|
|
32
52
|
this.bodies = pack.bodies;
|
|
33
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether this pack can evaluate a given body.
|
|
56
|
+
*
|
|
57
|
+
* @param body Body id to test.
|
|
58
|
+
* @returns `true` if {@link Turbo.longitude} accepts `body`.
|
|
59
|
+
*/
|
|
34
60
|
has(body) {
|
|
35
61
|
return body in this.bodies;
|
|
36
62
|
}
|
|
37
|
-
/**
|
|
63
|
+
/**
|
|
64
|
+
* Apparent ecliptic longitude (degrees) of a body from the turbo pack, in the
|
|
65
|
+
* pack's own zodiac. The hot path for bulk scans.
|
|
66
|
+
*
|
|
67
|
+
* @param body A body id the pack contains (see {@link Turbo.has}).
|
|
68
|
+
* @param jd Julian Day (UT), within `[jd0, jd1]`.
|
|
69
|
+
* @returns Ecliptic longitude in degrees, `[0, 360)`.
|
|
70
|
+
* @throws Error if the pack lacks `body`, or `jd` is outside `[jd0, jd1]`.
|
|
71
|
+
*/
|
|
38
72
|
longitude(body, jd) {
|
|
39
73
|
const b = this.bodies[body];
|
|
40
74
|
if (!b)
|