From 206e88ae856bf46161b649a3f18793f73cf336a0 Mon Sep 17 00:00:00 2001 From: Senrokai Date: Wed, 30 Sep 2026 15:41:01 +0200 Subject: [PATCH] Read a dwarf with a type and no colour at its type's row of the dwarf sequence A non-giant with a spectral type but no colour took its temperature off the textbook colour spectralTypeToColorIndex gives its type, read on Pecaut & Mamajek's table, and its bolometric correction off the old textbook anchors. The table puts those colours elsewhere: M8's B-V 1.88 is M5-M5.5 there, 3 001 K where M8 V is 2 570, and the anchors give M8 -3.92 where the table has -5.65. GJ 3655 (M8, 14.35 pc) was drawn at 0.035 solar radii, a third of Jupiter, where its type's row gives 0.106 (Mamajek's M8 V: 0.114). Every O type came out B0's 31 400 K. Both now read dwarfSequenceAtType, which already existed for the giants, and a G magnitude is carried to V at the type's G-V too. On the published catalogue, of the 835 non-giant stars with a band, a type and no colour, those more than 200 K off their type's row go from 21 to 0, those with a radius more than 1.5 times off it from 7 to 1 and a luminosity from 10 to 1 (the one left, Oph 11, is a G-band star). GJ 3849 (dM9) goes from 0.030 to 0.089 solar radii, GJ 3855 (M6.5) from 0.040 to 0.087. Two tests pinned the textbook path and now read the table: M5Ve with no colour is 3 060 K, not 3 106, and K5 tints as B-V 1.15, its row, not 1.105. An O8 star is 35 100 K, its row, not B0's. Controls: reading the temperature through the textbook colour again fails "is drawn at its type's row of the dwarf sequence" (with the three updated tests); reading the correction off the anchors again fails that test alone. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../galaxy-system/star-field-renderer.spec.ts | 4 +-- src/app/shared/astro/stellar.spec.ts | 23 +++++++++++--- src/app/shared/astro/stellar.ts | 31 +++++++++---------- 3 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/app/features/galaxy-system/star-field-renderer.spec.ts b/src/app/features/galaxy-system/star-field-renderer.spec.ts index 2f0be2b..230733c 100644 --- a/src/app/features/galaxy-system/star-field-renderer.spec.ts +++ b/src/app/features/galaxy-system/star-field-renderer.spec.ts @@ -64,9 +64,9 @@ describe('colorIndexToRgb', () => { }); it('matches the colour the same spectral type would give explicitly', () => { - // K5 sits halfway between the K anchor (0.81) and the M anchor (1.40). + // K5's row of the dwarf sequence is at B−V 1.15. const derived = colorIndexToRgb(null, 'K5'); - const explicit = colorIndexToRgb(1.105); + const explicit = colorIndexToRgb(1.15); expect(derived.r).toBeCloseTo(explicit.r, 6); expect(derived.g).toBeCloseTo(explicit.g, 6); diff --git a/src/app/shared/astro/stellar.spec.ts b/src/app/shared/astro/stellar.spec.ts index b7d58ce..fd374e3 100644 --- a/src/app/shared/astro/stellar.spec.ts +++ b/src/app/shared/astro/stellar.spec.ts @@ -174,20 +174,20 @@ describe('effectiveTemperatureK', () => { }); it('reads a colour in its own system, and a spectral type where there is no colour', () => { - // An M5 dwarf is 3 060 K at B−V 1.83 or BP−RP 3.35. Its type alone goes through the colour - // `spectralTypeToColorIndex` gives it, B−V 1.70, and comes out a little warmer. + // An M5 dwarf is 3 060 K at B−V 1.83 or BP−RP 3.35, and at its type alone. expect(effectiveTemperatureK({ magnitude: 11, distancePc: 5, colorIndex: 3.35, colorSystem: 'BP-RP' })).toBeCloseTo(3060, 0); expect(effectiveTemperatureK({ magnitude: 11, distancePc: 5, colorIndex: 1.83, colorSystem: 'B-V' })).toBeCloseTo(3060, 0); - expect(effectiveTemperatureK({ magnitude: 11, distancePc: 5, spectralType: 'M5Ve', colorIndex: null })).toBeCloseTo(3106, 0); + expect(effectiveTemperatureK({ magnitude: 11, distancePc: 5, spectralType: 'M5Ve', colorIndex: null })).toBeCloseTo(3060, 0); expect(effectiveTemperatureK({ magnitude: 11, distancePc: 5, spectralType: 'Unknown', colorIndex: null })).toBeNull(); }); it('reads a colour past the table at its end where there is no type, and the type where there is', () => { // An ultracool dwarf redder than M8.5, a white dwarf bluer than B9 at the 19 012 K Gentile - // Fusillo et al. (2021) measure at its colour, not B9's 10 700, and an O star B−V puts at B0. + // Fusillo et al. (2021) measure at its colour, not B9's 10 700, and an O star at its type's + // 35 100 K, where B−V puts every O star at B0's 31 400. expect(effectiveTemperatureK({ magnitude: 14.005, distancePc: 4.005, spectralType: 'Unknown', magnitudeBand: 'G', colorIndex: 5.113, colorSystem: 'BP-RP' })).toBe(2420); expect(effectiveTemperatureK({ magnitude: 14, distancePc: 25, spectralType: 'Unknown', magnitudeBand: 'G', colorIndex: -0.25, colorSystem: 'BP-RP' })).toBeCloseTo(19012, 6); - expect(effectiveTemperatureK({ magnitude: 7, distancePc: 121, spectralType: 'O8', colorIndex: -0.31, colorSystem: 'B-V' })).toBe(31400); + expect(effectiveTemperatureK({ magnitude: 7, distancePc: 121, spectralType: 'O8', colorIndex: -0.31, colorSystem: 'B-V' })).toBe(35100); // HD 49748, G5 V at B−V −0.32: the colour is the one that is wrong. const g5 = effectiveTemperatureK({ magnitude: 9, distancePc: 184, spectralType: 'G5V', colorIndex: null })!; expect(effectiveTemperatureK({ magnitude: 9, distancePc: 184, spectralType: 'G5V', colorIndex: -0.319, colorSystem: 'B-V' })).toBe(g5); @@ -195,6 +195,19 @@ describe('effectiveTemperatureK', () => { }); }); +describe('a dwarf with a type and no colour', () => { + it("is drawn at its type's row of the dwarf sequence, not at the textbook colour of its type", () => { + // GJ 3655, M8 at V 19.57 and 14.35 pc: M8 V is 2 570 K and 0.114 R☉ (Mamajek's table, 2022.04.16). + // Through the textbook colour, B−V 1.88, the table's M5, and the textbook correction, −3.92 + // where M8's is −5.65, it was 3 001 K and 0.035 R☉, a third of Jupiter. + const gj3655 = { magnitude: 19.57, distancePc: 14.35, spectralType: 'M8', magnitudeBand: 'V', colorIndex: null } as const; + expect(effectiveTemperatureK(gj3655)).toBeCloseTo(2570, 6); + const radius = radiusFromLuminositySolar(luminositySolar(gj3655)!, effectiveTemperatureK(gj3655)!); + expect(radius / 0.114).toBeGreaterThan(1 / 1.2); + expect(radius / 0.114).toBeLessThan(1.2); + }); +}); + describe('radiusFromLuminositySolar', () => { it('is one for the Sun', () => { expect(radiusFromLuminositySolar(1, SOLAR_EFFECTIVE_TEMPERATURE_K)).toBeCloseTo(1, 12); diff --git a/src/app/shared/astro/stellar.ts b/src/app/shared/astro/stellar.ts index 4c88465..ab0e586 100644 --- a/src/app/shared/astro/stellar.ts +++ b/src/app/shared/astro/stellar.ts @@ -1,4 +1,4 @@ -import { DwarfSequencePoint, dwarfSequenceAtColor, dwarfSequenceAtTemperature, dwarfSequenceAtType, isGiant, parseSpectralClass, SpectralClass, spectralTypeToColorIndex } from './spectral'; +import { DwarfSequencePoint, dwarfSequenceAtColor, dwarfSequenceAtTemperature, dwarfSequenceAtType, isGiant, parseSpectralClass, SpectralClass } from './spectral'; /** * Stellar luminosity, derived from the two things the star catalogue actually measures. @@ -123,15 +123,17 @@ export function luminositySolar(star: StellarPhotometry): number | null { } // Where the star has a colour the dwarf sequence covers, its correction is read off that colour, - // and a G magnitude is carried to V first; only otherwise is the spectral type used, and a G - // magnitude taken as V. Gaia classifies none of its stars, so every one of them used to be - // given the Sun's correction, and TRAPPIST-1 came out at a seventh of its luminosity. Against - // the archive's own figure for 1 449 hosts, the worst tenth was off by 0.29 dex or more, and is - // now off by 0.12. + // and a G magnitude is carried to V first; otherwise both are read off the same table at its + // spectral type, and only with neither is a G magnitude taken as V. Gaia classifies none of its + // stars, so every one of them used to be given the Sun's correction, and TRAPPIST-1 came out at + // a seventh of its luminosity. Against the archive's own figure for 1 449 hosts, the worst tenth + // was off by 0.29 dex or more, and is now off by 0.12. A type with no colour took the textbook + // anchors below instead, M8 −3.92 where the table has −5.65: GJ 3655, M8, came out 8.9×10⁻⁵ L☉ + // at 3 001 K and 0.035 R☉, where its type's row gives 2 570 K and 0.106. // // Not for a star its type says is a giant, though, whose correction is read off its type along // with its temperature: see giantSurface. - const sequence = sequenceAtColour(star); + const sequence = sequenceAtColour(star) ?? dwarfSequenceAtType(star.spectralType); const absoluteV = absolute - (star.magnitudeBand === 'G' ? (sequence?.gMinusV ?? 0) : 0); const correction = giantSurface(star.spectralType)?.bolometricCorrectionV ?? sequence?.bolometricCorrectionV ?? bolometricCorrection(star.spectralType); const bolometric = absoluteV + correction; @@ -160,20 +162,17 @@ function sequenceAtColour(star: StellarPhotometry): DwarfSequencePoint | null { export const SOLAR_EFFECTIVE_TEMPERATURE_K = 5772; /** - * Effective temperature, off the dwarf sequence at the star's colour, or at the colour its - * spectral type implies where it has none; a giant's off its type (giantSurface). Exactly the - * Sun's for the Sun, which is at zero distance here. + * Effective temperature, off the dwarf sequence at the star's colour, or at its spectral type where + * it has none; a giant's off its type (giantSurface). Exactly the Sun's for the Sun, which is at + * zero distance here. The type was read through the textbook colour `spectralTypeToColorIndex` + * gives it, which the table puts elsewhere: M8's 1.88 is M5's, 3 001 K where M8 is 2 570, and every + * O type came out B0's 31 400. */ export function effectiveTemperatureK(star: StellarPhotometry): number | null { if (star.distancePc === 0) { return SOLAR_EFFECTIVE_TEMPERATURE_K; } - // A type's colour past the table is an O star's, which B−V no longer tells apart from B0. - return ( - giantSurface(star.spectralType)?.temperatureK ?? - (sequenceAtColour(star) ?? dwarfSequenceAtColor(spectralTypeToColorIndex(star.spectralType), 'B-V', true))?.temperatureK ?? - null - ); + return giantSurface(star.spectralType)?.temperatureK ?? (sequenceAtColour(star) ?? dwarfSequenceAtType(star.spectralType))?.temperatureK ?? null; } /**