Keep every star the naked eye sees, Rigel, Deneb and Alnilam among them
The 250 pc cutoff took 1 543 of HYG's 8 920 stars of V 6.5 or brighter:
1 339 that both surveys put past it and 204 HYG has no distance for. Five
of the fifty brightest stars in the sky were gone (Rigel, Deneb, Alnilam,
gamma-2 Vel, Wezen), and Naos, Sadr, Aludra and Arneb with them, while
11th-magnitude Gaia stars at the same distance were drawn. The cutoff
bounds a download, not what the sky shows.
placementDistancePc now keeps a star of V 6.5 or brighter at any distance,
at the better of its two distances as before: Gaia's where the archive's
Hipparcos cross-match has a usable parallax, Hipparcos's otherwise. Gaia
saturates on the brightest, so Rigel (264.6 pc), Deneb (432.9), Alnilam
(606.1), Wezen (492.6), Naos, Sadr, Aludra and Arneb sit at their
Hipparcos distance. 1 502 HYG rows come back, 165 of the 206 without a
Hipparcos distance among them because Gaia measured them; 36 fold into a
Gaia entry. 41 naked-eye stars stay out because neither survey gives them
a distance: beta Phe, Polis, Mu Cep, Rho Cas, Eta Car, Alp Cam, Phi Cas,
Chi Aur, Psi-1 Aur, theta-1 Ori, Omi-1 Cen, 66 Ori, 16 Sgr, 10 Sge and 27
HD stars.
Measured on the rebuilt catalogue: 425 117 stars (+1 466), 8 301 of them
past 250 pc (+1 466), the same 336 within 10 pc and 3 652 within 25 pc.
Merge gate: 12 352 HYG rows without a Gaia counterpart (was 10 886; the
ceiling of 15 000 is unchanged, and its comment now counts the naked-eye
stars among the survivors) and the same 23 cross-catalogue pairs under an
arcsecond. Five more exoplanets find their host: HD 81817 b and c,
HD 158996 b, HD 208527 b, HD 220074 b. gzip -9 sizes: stars.bin
4 711 922 -> 4 728 315 B, stars-meta.bin 2 576 213 -> 2 587 977 B,
stars-index.json 3 724 855 -> 3 731 763 B.
The brief behind this also asked to cut once on the best distance, which
would drop the 6 835 stars Hipparcos puts inside 250 pc and Gaia outside.
Those already sit at Gaia's distance (4eb61ff), so nothing is misplaced,
and they stay.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
|
|||||||
|
|
||||||
import { raDegDecDistanceToXyz } from './coordinates';
|
import { raDegDecDistanceToXyz } from './coordinates';
|
||||||
import { StarRecord } from '../models/star.model';
|
import { StarRecord } from '../models/star.model';
|
||||||
import { directionCosine, isSameStar, MERGE_ANGULAR_TOLERANCE_DEG, mergeStarCatalogues, placementDistancePc } from './star-merge';
|
import { directionCosine, isSameStar, MERGE_ANGULAR_TOLERANCE_DEG, mergeStarCatalogues, NAKED_EYE_MAGNITUDE, placementDistancePc } from './star-merge';
|
||||||
|
|
||||||
/** A star at a given sky position and distance, which is how catalogues actually report them. */
|
/** A star at a given sky position and distance, which is how catalogues actually report them. */
|
||||||
function at(id: number, raDeg: number, decDeg: number, distancePc: number, overrides: Partial<StarRecord> = {}): StarRecord {
|
function at(id: number, raDeg: number, decDeg: number, distancePc: number, overrides: Partial<StarRecord> = {}): StarRecord {
|
||||||
@@ -240,32 +240,44 @@ describe('mergeStarCatalogues', () => {
|
|||||||
|
|
||||||
describe('placementDistancePc', () => {
|
describe('placementDistancePc', () => {
|
||||||
it("draws a star both surveys measured at Gaia's distance", () => {
|
it("draws a star both surveys measured at Gaia's distance", () => {
|
||||||
expect(placementDistancePc(120, 118.4, 250)).toBe(118.4);
|
expect(placementDistancePc(120, 118.4, 8, 250)).toBe(118.4);
|
||||||
});
|
});
|
||||||
|
|
||||||
// The case the old cut got wrong: Hipparcos inside, Gaia outside. Kept, at the distance Gaia
|
// The case the old cut got wrong: Hipparcos inside, Gaia outside. Kept, at the distance Gaia
|
||||||
// gives, rather than at one a third short or dropped for having been misplaced.
|
// gives, rather than at one a third short or dropped for having been misplaced.
|
||||||
it('keeps a star Hipparcos put inside the cutoff, where Gaia puts it, even past the cutoff', () => {
|
it('keeps a star Hipparcos put inside the cutoff, where Gaia puts it, even past the cutoff', () => {
|
||||||
expect(placementDistancePc(200, 306, 250)).toBe(306);
|
expect(placementDistancePc(200, 306, 8, 250)).toBe(306);
|
||||||
});
|
});
|
||||||
|
|
||||||
// The mirror image: Hipparcos outside, Gaia inside. The Gaia download already holds the star,
|
// The mirror image: Hipparcos outside, Gaia inside. The Gaia download already holds the star,
|
||||||
// and keeping the HYG row is what lets the merge give that entry its name.
|
// and keeping the HYG row is what lets the merge give that entry its name.
|
||||||
it('keeps a star only Gaia puts inside the cutoff', () => {
|
it('keeps a star only Gaia puts inside the cutoff', () => {
|
||||||
expect(placementDistancePc(262, 241, 250)).toBe(241);
|
expect(placementDistancePc(262, 241, 8, 250)).toBe(241);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('keeps a star Gaia measured and Hipparcos gave no distance for', () => {
|
it('keeps a star Gaia measured and Hipparcos gave no distance for', () => {
|
||||||
expect(placementDistancePc(undefined, 180, 250)).toBe(180);
|
expect(placementDistancePc(undefined, 180, 8, 250)).toBe(180);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('falls back to Hipparcos where Gaia has no usable distance', () => {
|
it('falls back to Hipparcos where Gaia has no usable distance', () => {
|
||||||
expect(placementDistancePc(90, undefined, 250)).toBe(90);
|
expect(placementDistancePc(90, undefined, 8, 250)).toBe(90);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('drops a star both surveys put outside, or neither measured', () => {
|
it('drops a star both surveys put outside, or neither measured', () => {
|
||||||
expect(placementDistancePc(300, 410, 250)).toBeNull();
|
expect(placementDistancePc(300, 410, 8, 250)).toBeNull();
|
||||||
expect(placementDistancePc(300, undefined, 250)).toBeNull();
|
expect(placementDistancePc(300, undefined, 8, 250)).toBeNull();
|
||||||
expect(placementDistancePc(undefined, undefined, 250)).toBeNull();
|
expect(placementDistancePc(undefined, undefined, 8, 250)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rigel: Hipparcos 265 pc, and no Gaia distance, since Gaia saturates on it. The cutoff bounds a
|
||||||
|
// download, not what the sky shows, and a map without the middle of Orion's belt is not the sky.
|
||||||
|
it('keeps a star the naked eye sees at any distance, at the better one', () => {
|
||||||
|
expect(placementDistancePc(265, undefined, 0.18, 250)).toBe(265);
|
||||||
|
expect(placementDistancePc(433, 802, NAKED_EYE_MAGNITUDE, 250)).toBe(802);
|
||||||
|
expect(placementDistancePc(433, 802, NAKED_EYE_MAGNITUDE + 0.01, 250)).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('still drops a naked-eye star no survey gives a distance for', () => {
|
||||||
|
expect(placementDistancePc(undefined, undefined, 3.3, 250)).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ export const MERGE_BRIGHTER_TOLERANCE = 1;
|
|||||||
*/
|
*/
|
||||||
export const MERGE_DISTANCE_RATIO_TOLERANCE = 0.5;
|
export const MERGE_DISTANCE_RATIO_TOLERANCE = 0.5;
|
||||||
|
|
||||||
|
/** The faintest star, in V, the naked eye sees under a dark sky: the traditional limit of 6.5. */
|
||||||
|
export const NAKED_EYE_MAGNITUDE = 6.5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Where to draw a star Hipparcos and Gaia both measured, and whether the map keeps it at all.
|
* Where to draw a star Hipparcos and Gaia both measured, and whether the map keeps it at all.
|
||||||
*
|
*
|
||||||
@@ -77,15 +80,18 @@ export const MERGE_DISTANCE_RATIO_TOLERANCE = 0.5;
|
|||||||
* Gaia counterpart, and at the median Hipparcos had them at two-thirds of Gaia's distance.
|
* Gaia counterpart, and at the median Hipparcos had them at two-thirds of Gaia's distance.
|
||||||
*
|
*
|
||||||
* Now a star either survey places inside `cutoffPc` is kept, and every kept star sits where the
|
* Now a star either survey places inside `cutoffPc` is kept, and every kept star sits where the
|
||||||
* better measurement puts it, inside the cutoff or not. `null` for a star neither survey places
|
* better measurement puts it, inside the cutoff or not. So is every star the naked eye sees, at
|
||||||
* inside, or that no survey gives a distance for.
|
* any distance: the cutoff took 1 543 of HYG's 8 920 stars of V 6.5 or brighter, Rigel, Deneb
|
||||||
|
* and Alnilam among them, while 11th-magnitude Gaia stars at the same distance were drawn. Gaia
|
||||||
|
* saturates on the brightest of them, so those sit at their Hipparcos distance. `null` for a star
|
||||||
|
* kept by neither rule, or that no survey gives a distance for.
|
||||||
*/
|
*/
|
||||||
export function placementDistancePc(hipparcosPc: number | undefined, gaiaPc: number | undefined, cutoffPc: number): number | null {
|
export function placementDistancePc(hipparcosPc: number | undefined, gaiaPc: number | undefined, magnitude: number, cutoffPc: number): number | null {
|
||||||
const best = gaiaPc ?? hipparcosPc;
|
const best = gaiaPc ?? hipparcosPc;
|
||||||
if (best === undefined) {
|
if (best === undefined) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const inside = best <= cutoffPc || (hipparcosPc !== undefined && hipparcosPc <= cutoffPc);
|
const inside = magnitude <= NAKED_EYE_MAGNITUDE || best <= cutoffPc || (hipparcosPc !== undefined && hipparcosPc <= cutoffPc);
|
||||||
return inside ? best : null;
|
return inside ? best : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
+10
-9
@@ -66,18 +66,19 @@ function validateStars(stars: StarRecord[]): void {
|
|||||||
* The other failure leaves no close pair at all, because proper motion had already carried the
|
* The other failure leaves no close pair at all, because proper motion had already carried the
|
||||||
* two entries tens of arcseconds apart — the 2026-08-24 refresh, where HYG sat at epoch 2000.0
|
* two entries tens of arcseconds apart — the 2026-08-24 refresh, where HYG sat at epoch 2000.0
|
||||||
* and Gaia at J2016.0. What it does leave is HYG rows that found no counterpart: 36 056 of them
|
* and Gaia at J2016.0. What it does leave is HYG rows that found no counterpart: 36 056 of them
|
||||||
* against the 10 886 today, and no counterpart was possible for most of those. Two thirds of them,
|
* against the 12 352 today, and no counterpart was possible for most of those. 8 301 of them are
|
||||||
* 6 835, are the stars Gaia measures but the main query never downloads, because Gaia's parallax
|
* every star in the published catalogue beyond 250 pc, which the main query never downloads: 6 835
|
||||||
* puts them past `ETL_GAIA_DISTANCE_PC` while Hipparcos put them inside `ETL_STAR_DISTANCE_PC`;
|
* that Gaia's parallax puts past `ETL_GAIA_DISTANCE_PC` while Hipparcos put them inside
|
||||||
* they are every star in the published catalogue beyond 250 pc. The rest are what Gaia genuinely
|
* `ETL_STAR_DISTANCE_PC`, and 1 466 naked-eye stars kept at any distance. The rest are what Gaia
|
||||||
* lacks: bright stars it saturates on, red dwarfs past its magnitude cut. So the headroom left to
|
* genuinely lacks: bright stars it saturates on, red dwarfs past its magnitude cut. So the headroom
|
||||||
* the ceiling tracks the gap between those two cutoffs as much as Gaia's completeness.
|
* left to the ceiling tracks the gap between those two cutoffs as much as Gaia's completeness.
|
||||||
*
|
*
|
||||||
* This bounds a merge that went wrong, and — loosely — a Gaia download that came back short: a
|
* This bounds a merge that went wrong, and — loosely — a Gaia download that came back short: a
|
||||||
* truncated answer leaves the HYG rows whose counterpart it dropped without one, so survivors go
|
* truncated answer leaves the HYG rows whose counterpart it dropped without one, so survivors go
|
||||||
* *up*, not down. Measured against the published catalogue: 10 886 today, 11 004 at nine tenths of
|
* *up*, not down. Measured before the naked-eye stars joined, which add about 1 466 to each
|
||||||
* the rows, 12 711 at half, 16 258 at a third. So this ceiling only catches a truncation past about
|
* figure: 10 886, 11 004 at nine tenths of the rows, 12 711 at half, 16 258 at a third. So this
|
||||||
* two thirds, and `fetchGaiaStars` catches the shallower ones with its own row floor.
|
* ceiling only catches a deep truncation, and `fetchGaiaStars` catches the shallower ones with its
|
||||||
|
* own row floor.
|
||||||
*/
|
*/
|
||||||
const MAX_UNMERGED_TWINS = 100;
|
const MAX_UNMERGED_TWINS = 100;
|
||||||
const MAX_HYG_SURVIVORS = 15_000;
|
const MAX_HYG_SURVIVORS = 15_000;
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ const UNKNOWN_MAGNITUDE = 15;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Stars either survey places within this distance (parsecs) of the Sun are kept for the galaxy
|
* Stars either survey places within this distance (parsecs) of the Sun are kept for the galaxy
|
||||||
* view; `placementDistancePc` decides which distance a kept star is drawn at.
|
* view, and every naked-eye star wherever it is; `placementDistancePc` decides which distance a
|
||||||
|
* kept star is drawn at.
|
||||||
*
|
*
|
||||||
* Set at the range Hipparcos's own measurements reach rather than at a round number: its
|
* Set at the range Hipparcos's own measurements reach rather than at a round number: its
|
||||||
* parallaxes are good to roughly a milliarcsecond, so at 250 pc (4 mas) a distance is uncertain
|
* parallaxes are good to roughly a milliarcsecond, so at 250 pc (4 mas) a distance is uncertain
|
||||||
@@ -87,7 +88,8 @@ export async function fetchStars(): Promise<StarRecord[]> {
|
|||||||
const hygPc = Number(row['dist']);
|
const hygPc = Number(row['dist']);
|
||||||
const hipparcosPc = Number.isFinite(hygPc) && hygPc > 0 && hygPc < HYG_UNKNOWN_DISTANCE_PC ? hygPc : undefined;
|
const hipparcosPc = Number.isFinite(hygPc) && hygPc > 0 && hygPc < HYG_UNKNOWN_DISTANCE_PC ? hygPc : undefined;
|
||||||
const gaiaPc = row['hip'] ? gaiaPcByHip.get(Number(row['hip'])) : undefined;
|
const gaiaPc = row['hip'] ? gaiaPcByHip.get(Number(row['hip'])) : undefined;
|
||||||
const distancePc = placementDistancePc(hipparcosPc, gaiaPc, DISTANCE_CUTOFF_PC);
|
const magnitude = parseOptionalNumber(row['mag']) ?? UNKNOWN_MAGNITUDE;
|
||||||
|
const distancePc = placementDistancePc(hipparcosPc, gaiaPc, magnitude, DISTANCE_CUTOFF_PC);
|
||||||
if (distancePc === null) {
|
if (distancePc === null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -123,7 +125,7 @@ export async function fetchStars(): Promise<StarRecord[]> {
|
|||||||
x: x * scale,
|
x: x * scale,
|
||||||
y: y * scale,
|
y: y * scale,
|
||||||
z: z * scale,
|
z: z * scale,
|
||||||
magnitude: parseOptionalNumber(row['mag']) ?? UNKNOWN_MAGNITUDE,
|
magnitude,
|
||||||
spectralType: row['spect'] || 'Unknown',
|
spectralType: row['spect'] || 'Unknown',
|
||||||
colorIndex: parseOptionalNumber(row['ci']) ?? null
|
colorIndex: parseOptionalNumber(row['ci']) ?? null
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user