caelus 0.10.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 +79 -0
- package/dist/src/compiler.js +152 -0
- 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 +88 -0
- package/dist/src/features.js +119 -0
- package/dist/src/houses.d.ts +13 -4
- package/dist/src/houses.js +13 -4
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- 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/events.js
CHANGED
|
@@ -44,8 +44,29 @@ function bisect(f, a, b, iters = 45) {
|
|
|
44
44
|
}
|
|
45
45
|
return (a + b) / 2;
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
48
|
-
*
|
|
47
|
+
/**
|
|
48
|
+
* The next rise, set, or meridian transit of a body after `jdStart`, as a
|
|
49
|
+
* Julian Day (UT). Accounts for the body's apparent radius, atmospheric
|
|
50
|
+
* refraction, and observer altitude.
|
|
51
|
+
*
|
|
52
|
+
* @param engine The engine used to evaluate positions.
|
|
53
|
+
* @param body A body id from {@link Engine.bodies}.
|
|
54
|
+
* @param jdStart Search start, Julian Day (UT). The result is the first event
|
|
55
|
+
* strictly after this instant.
|
|
56
|
+
* @param latDeg Observer latitude in degrees, north positive.
|
|
57
|
+
* @param lonDeg Observer longitude in degrees, east positive.
|
|
58
|
+
* @param kind `"rise"`, `"set"`, `"mtransit"` (upper/meridian transit), or
|
|
59
|
+
* `"itransit"` (lower transit). Defaults to `"rise"`.
|
|
60
|
+
* @param opts `altM` (observer altitude, m), `pressure` (hPa), `tempC`, and
|
|
61
|
+
* `searchDays` (how far ahead to look; defaults to 2).
|
|
62
|
+
* @returns The event time as a Julian Day (UT), or `null` when it does not
|
|
63
|
+
* occur in the window (e.g. polar day or night).
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* // Next sunrise over London after 2025-06-01
|
|
67
|
+
* const jd = riseSet(engine, "sun", julianDay(2025, 6, 1), 51.5, -0.13, "rise");
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
49
70
|
export function riseSet(engine, body, jdStart, latDeg, lonDeg, kind = "rise", opts = {}) {
|
|
50
71
|
const altM = opts.altM ?? 0.0;
|
|
51
72
|
const pressure = opts.pressure ?? 1013.25;
|
|
@@ -110,7 +131,23 @@ export function crossings(engine, body, targetLon, jdStart, jdEnd, zodiac = "tro
|
|
|
110
131
|
}
|
|
111
132
|
return out;
|
|
112
133
|
}
|
|
113
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* Every principal lunar phase (new, first quarter, full, last quarter) within
|
|
136
|
+
* `[jdStart, jdEnd]`, sorted by time. Found from the Sun–Moon elongation
|
|
137
|
+
* crossing 0°/90°/180°/270°.
|
|
138
|
+
*
|
|
139
|
+
* @param engine The engine used to evaluate positions.
|
|
140
|
+
* @param jdStart Start of the window, Julian Day (UT).
|
|
141
|
+
* @param jdEnd End of the window, Julian Day (UT).
|
|
142
|
+
* @param maxHits Cap on the number of phases returned. Defaults to 60.
|
|
143
|
+
* @returns Sorted `[jdUt, phase]` pairs, where `phase` is one of
|
|
144
|
+
* {@link PhaseName}.
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const phases = lunarPhases(engine, julianDay(2025, 1, 1), julianDay(2025, 2, 1));
|
|
148
|
+
* // [[jd, "new"], [jd, "first_quarter"], ...]
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
114
151
|
export function lunarPhases(engine, jdStart, jdEnd, maxHits = 60) {
|
|
115
152
|
const elong = (t) => mod(engine.longitude("moon", t) - engine.longitude("sun", t), 360);
|
|
116
153
|
const names = [
|
|
@@ -154,10 +191,19 @@ export function stations(engine, body, jdStart, jdEnd, maxHits = 30) {
|
|
|
154
191
|
}
|
|
155
192
|
return out;
|
|
156
193
|
}
|
|
157
|
-
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
194
|
+
/**
|
|
195
|
+
* The Gauquelin sector of a body (1–36, fractional) from the rise/set times of
|
|
196
|
+
* the disc centre with refraction (Swiss Ephemeris method 3). Sectors run from
|
|
197
|
+
* rise: 1–18 above the horizon, 19–36 below.
|
|
198
|
+
*
|
|
199
|
+
* @param engine The engine used to evaluate positions.
|
|
200
|
+
* @param body A body id from {@link Engine.bodies}.
|
|
201
|
+
* @param jdUt Julian Day (UT).
|
|
202
|
+
* @param latDeg Observer latitude in degrees, north positive.
|
|
203
|
+
* @param lonDeg Observer longitude in degrees, east positive.
|
|
204
|
+
* @returns The sector in `[1, 37)`, or `null` in polar no-rise/no-set
|
|
205
|
+
* conditions.
|
|
206
|
+
*/
|
|
161
207
|
export function gauquelinSector(engine, body, jdUt, latDeg, lonDeg) {
|
|
162
208
|
const surrounding = (kind) => {
|
|
163
209
|
let t = riseSet(engine, body, jdUt - 1.3, latDeg, lonDeg, kind, { discCenter: true });
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Engine, BodyId, Zodiac } from "./chart.js";
|
|
2
|
+
import { RankedMoment } from "./scan.js";
|
|
3
|
+
export declare const DEFAULT_BODIES: string[];
|
|
4
|
+
/**
|
|
5
|
+
* Build a feature vector from explicit `(longitude, weight)` pairs: each pair
|
|
6
|
+
* contributes a weighted unit-circle point `[w·cos(lon), w·sin(lon)]`. The
|
|
7
|
+
* low-level primitive behind {@link chartFeatures}; most callers want that.
|
|
8
|
+
*
|
|
9
|
+
* @param weightedLons `[longitudeDeg, weight]` pairs, in the order they should
|
|
10
|
+
* appear in the vector.
|
|
11
|
+
* @returns A flat vector, two entries per pair.
|
|
12
|
+
*/
|
|
13
|
+
export declare function featureVector(weightedLons: [number, number][]): number[];
|
|
14
|
+
/**
|
|
15
|
+
* Cosine similarity of two feature vectors, in `[-1, 1]`. For vectors from
|
|
16
|
+
* {@link chartFeatures} this is a weighted mean of `cos(Δlongitude)` per body:
|
|
17
|
+
* `1` when the configurations coincide, falling off as bodies diverge.
|
|
18
|
+
*
|
|
19
|
+
* @param a First feature vector.
|
|
20
|
+
* @param b Second feature vector (compared over the shorter length).
|
|
21
|
+
* @returns Similarity in `[-1, 1]`; `0` if either vector is all zeros.
|
|
22
|
+
*/
|
|
23
|
+
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
24
|
+
export interface FeatureOptions {
|
|
25
|
+
bodies?: BodyId[];
|
|
26
|
+
weights?: Record<string, number>;
|
|
27
|
+
zodiac?: Zodiac;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Encode the sky at an instant as a feature vector: each body's ecliptic
|
|
31
|
+
* longitude becomes a weighted unit-circle point. The deterministic substrate
|
|
32
|
+
* for matching and searching chart configurations — compare two with
|
|
33
|
+
* {@link cosineSimilarity}, or rank a time range against one with
|
|
34
|
+
* {@link searchConfigurations}.
|
|
35
|
+
*
|
|
36
|
+
* @param engine The engine used to evaluate positions.
|
|
37
|
+
* @param jdUt Julian Day in UT.
|
|
38
|
+
* @param opts `bodies` (ordered; defaults to the ten major bodies), per-body
|
|
39
|
+
* `weights`, and `zodiac` (tropical by default).
|
|
40
|
+
* @returns A flat vector `[w·cos(lon), w·sin(lon), ...]`, two entries per body
|
|
41
|
+
* in `bodies` order.
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const target = chartFeatures(engine, julianDay(2000, 1, 1));
|
|
45
|
+
* const now = chartFeatures(engine, julianDay(2025, 6, 1));
|
|
46
|
+
* cosineSimilarity(now, target); // 1 = identical configuration
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function chartFeatures(engine: Engine, jdUt: number, opts?: FeatureOptions): number[];
|
|
50
|
+
/**
|
|
51
|
+
* Similarity between the sky at `jdUt` and a target feature vector — shorthand
|
|
52
|
+
* for `cosineSimilarity(chartFeatures(engine, jdUt, opts), target)`. The scoring
|
|
53
|
+
* function {@link searchConfigurations} maximizes.
|
|
54
|
+
*
|
|
55
|
+
* @param engine The engine used to evaluate positions.
|
|
56
|
+
* @param jdUt Julian Day in UT.
|
|
57
|
+
* @param target A target feature vector from {@link chartFeatures}.
|
|
58
|
+
* @param opts {@link FeatureOptions} — must match those used to build `target`.
|
|
59
|
+
* @returns Cosine similarity in `[-1, 1]`.
|
|
60
|
+
*/
|
|
61
|
+
export declare function configurationFit(engine: Engine, jdUt: number, target: number[], opts?: FeatureOptions): number;
|
|
62
|
+
export interface SearchConfigOptions extends FeatureOptions {
|
|
63
|
+
start: number;
|
|
64
|
+
end: number;
|
|
65
|
+
step: number;
|
|
66
|
+
limit?: number;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Rank the instants in `[start, end]` by how closely the sky resembles a
|
|
70
|
+
* `target` feature vector, best first — a realization search over the feature
|
|
71
|
+
* space. Build `target` with {@link chartFeatures} (e.g. from a natal chart).
|
|
72
|
+
*
|
|
73
|
+
* @param engine The engine used to evaluate positions.
|
|
74
|
+
* @param target A target feature vector from {@link chartFeatures}.
|
|
75
|
+
* @param opts `start`/`end` (Julian Days, UT) and `step` (days) define the
|
|
76
|
+
* scan, `limit` caps the results, plus the {@link FeatureOptions} (`bodies`,
|
|
77
|
+
* `weights`, `zodiac`) — which must match those used to build `target`.
|
|
78
|
+
* @returns Ranked `{ jd, score }` moments, highest similarity first.
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const natal = chartFeatures(engine, julianDay(1990, 6, 10, 14, 30));
|
|
82
|
+
* const matches = searchConfigurations(engine, natal, {
|
|
83
|
+
* start: julianDay(2025, 1, 1), end: julianDay(2026, 1, 1), step: 1, limit: 5,
|
|
84
|
+
* });
|
|
85
|
+
* matches[0].jd; // best-matching instant
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export declare function searchConfigurations(engine: Engine, target: number[], opts: SearchConfigOptions): RankedMoment[];
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine features -- a chart as a feature vector, similarity between
|
|
3
|
+
* charts, and search for when the sky most resembles a target configuration.
|
|
4
|
+
*
|
|
5
|
+
* Each body's ecliptic longitude is circular, so it contributes a unit-circle
|
|
6
|
+
* point (cos, sin), optionally weighted. Cosine similarity between two such
|
|
7
|
+
* vectors is a weighted mean of cos(delta-longitude) per body: 1 when the
|
|
8
|
+
* configurations coincide, falling off as bodies diverge. The deterministic
|
|
9
|
+
* substrate for matching, retrieving, and searching chart configurations.
|
|
10
|
+
* Mirrors the Python reference (astroengine/features.py); the golden pins them.
|
|
11
|
+
*/
|
|
12
|
+
import { DEG } from "./core.js";
|
|
13
|
+
import { rankMoments } from "./scan.js";
|
|
14
|
+
export const DEFAULT_BODIES = ["sun", "moon", "mercury", "venus", "mars",
|
|
15
|
+
"jupiter", "saturn", "uranus", "neptune", "pluto"];
|
|
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
|
+
*/
|
|
25
|
+
export function featureVector(weightedLons) {
|
|
26
|
+
const out = [];
|
|
27
|
+
for (const [lon, w] of weightedLons) {
|
|
28
|
+
const r = lon * DEG;
|
|
29
|
+
out.push(w * Math.cos(r), w * Math.sin(r));
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
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
|
+
*/
|
|
42
|
+
export function cosineSimilarity(a, b) {
|
|
43
|
+
let dot = 0, na = 0, nb = 0;
|
|
44
|
+
const n = Math.min(a.length, b.length);
|
|
45
|
+
for (let i = 0; i < n; i++) {
|
|
46
|
+
dot += a[i] * b[i];
|
|
47
|
+
na += a[i] * a[i];
|
|
48
|
+
nb += b[i] * b[i];
|
|
49
|
+
}
|
|
50
|
+
if (na === 0 || nb === 0)
|
|
51
|
+
return 0;
|
|
52
|
+
return dot / (Math.sqrt(na) * Math.sqrt(nb));
|
|
53
|
+
}
|
|
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
|
+
*/
|
|
74
|
+
export function chartFeatures(engine, jdUt, opts = {}) {
|
|
75
|
+
const bodies = opts.bodies ?? DEFAULT_BODIES;
|
|
76
|
+
const zodiac = opts.zodiac ?? "tropical";
|
|
77
|
+
const wl = bodies.map((b) => [
|
|
78
|
+
engine.longitude(b, jdUt, { zodiac }),
|
|
79
|
+
opts.weights?.[b] ?? 1.0,
|
|
80
|
+
]);
|
|
81
|
+
return featureVector(wl);
|
|
82
|
+
}
|
|
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
|
+
*/
|
|
94
|
+
export function configurationFit(engine, jdUt, target, opts = {}) {
|
|
95
|
+
return cosineSimilarity(chartFeatures(engine, jdUt, opts), target);
|
|
96
|
+
}
|
|
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
|
+
*/
|
|
117
|
+
export function searchConfigurations(engine, target, opts) {
|
|
118
|
+
return rankMoments({ start: opts.start, end: opts.end, step: opts.step, limit: opts.limit }, (jd) => configurationFit(engine, jd, target, opts));
|
|
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/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
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)
|