diff --git a/celestia.cfg b/celestia.cfg index 3baec95db..ff8d3c53d 100644 --- a/celestia.cfg +++ b/celestia.cfg @@ -101,6 +101,7 @@ StarTextures # Wolf-Rayet stars WC "bstar.*" WN "bstar.*" + WO "bstar.*" # brown dwarfs L "browndwarf.*" diff --git a/src/celengine/star.cpp b/src/celengine/star.cpp index 79dd90741..528fb2fe5 100644 --- a/src/celengine/star.cpp +++ b/src/celengine/star.cpp @@ -117,6 +117,12 @@ static float tempWC[10] = 60000, 60000, 60000, 60000, 60000, 60000, 60000, 54000, 46000, 38000 }; +// These values are based on extrapolation of 6 samples. +static float tempWO[10] = +{ + 210000, 210000, 200000, 160000, 140000, 130000, 130000, 130000, 130000, 130000 +}; + // Brown dwarf temperatures. From this website: // https://www.pas.rochester.edu/~emamajek/EEM_dwarf_UBVIJHK_colors_Teff.txt // Data for types after Y2 (which are not actually used) is extrapolated. @@ -386,7 +392,7 @@ const char* SubclassNames[11] = { const char* SpectralClassNames[StellarClass::NormalClassCount] = { "O", "B", "A", "F", "G", "K", "M", "R", - "S", "N", "WC", "WN", "?", "L", "T", "Y", "C", + "S", "N", "WC", "WN", "WO", "?", "L", "T", "Y", "C", }; const char* WDSpectralClassNames[StellarClass::WDClassCount] = { @@ -488,6 +494,7 @@ StarDetails::GetNormalStarDetails(StellarClass::SpectralClass specClass, case StellarClass::Spectral_O: case StellarClass::Spectral_WN: case StellarClass::Spectral_WC: + case StellarClass::Spectral_WO: subclass = 9; break; case StellarClass::Spectral_Y: @@ -564,6 +571,9 @@ StarDetails::GetNormalStarDetails(StellarClass::SpectralClass specClass, case StellarClass::Spectral_WC: temp = tempWC[subclass]; break; + case StellarClass::Spectral_WO: + temp = tempWO[subclass]; + break; case StellarClass::Spectral_L: temp = tempL[subclass]; break; @@ -621,6 +631,7 @@ StarDetails::GetNormalStarDetails(StellarClass::SpectralClass specClass, case StellarClass::Spectral_WC: case StellarClass::Spectral_WN: + case StellarClass::Spectral_WO: period = rotperiod_O[lumIndex][subclass]; bmagCorrection = bmag_correctionO[lumIndex][subclass]; break; diff --git a/src/celengine/stellarclass.cpp b/src/celengine/stellarclass.cpp index 1be98bd12..1326f372a 100644 --- a/src/celengine/stellarclass.cpp +++ b/src/celengine/stellarclass.cpp @@ -76,7 +76,7 @@ string StellarClass::str() const case StellarClass::BlackHole: return "X"; case StellarClass::NormalStar: - s0 = "OBAFGKMRSNWW?LTYC"[(unsigned int) getSpectralClass()]; + s0 = "OBAFGKMRSNWWW?LTYC"[(unsigned int) getSpectralClass()]; s1 = "0123456789"[getSubclass()]; switch (getLuminosityClass()) { @@ -116,13 +116,18 @@ string StellarClass::str() const uint16_t StellarClass::packV1() const { - // StarDB Ver. 0x0100 doesn't support Spectral_Y. - // Classes following Spectral_Y are shifted by 1. + // StarDB Ver. 0x0100 doesn't support Spectral_Y/WO. + // Classes following Spectral_Y are shifted by 2. + // Classes following Spectral_WO are shifted by 1. uint16_t sc; - if (specClass == SpectralClass::Spectral_Y) - sc = (uint16_t) SpectralClass::Spectral_Unknown; + if (specClass > SpectralClass::Spectral_Y) + sc = (uint16_t) specClass - 2; + else if (specClass == SpectralClass::Spectral_Y) + sc = (uint16_t) SpectralClass::Spectral_WO; // WO uses value Unknown used + else if (specClass > SpectralClass::Spectral_WO) + sc = (uint16_t) specClass - 1; else - sc = (uint16_t) specClass > SpectralClass::Spectral_Y ? specClass - 1 : specClass; + sc = (uint16_t) specClass; return (((uint16_t) starType << 12) | (((uint16_t) sc & 0x0f) << 8) | @@ -134,7 +139,7 @@ StellarClass::packV1() const uint16_t StellarClass::packV2() const { - uint16_t sc = (starType == StellarClass::WhiteDwarf ? specClass - 1 : specClass); + uint16_t sc = (starType == StellarClass::WhiteDwarf ? specClass - 2 : specClass); return (((uint16_t) starType << 13) | (((uint16_t) sc & 0x1f) << 8) | @@ -152,17 +157,37 @@ StellarClass::unpackV1(uint16_t st) { case NormalStar: specClass = static_cast(st >> 8 & 0xf); - // StarDB Ver. 0x0100 doesn't support Spectral_Y - // Spectral_Y has the value Spectral_C had earlier. - if (specClass == SpectralClass::Spectral_Y) + // StarDB Ver. 0x0100 doesn't support Spectral_Y & Spectral_WO + // 0x0100 0x0200 + // Spectral_Unknown = 12 Spectral_WO = 12 + // Spectral_L = 13 Spectral_Unknown = 13 + // Spectral_T = 14 Spectral_L = 14 + // Spectral_C = 15 Spectral_T = 15 + // Spectral_Y = 16 + // Spectral_C = 17 + switch (specClass) + { + case SpectralClass::Spectral_WO: + specClass = SpectralClass::Spectral_Unknown; + break; + case SpectralClass::Spectral_Unknown: + specClass = SpectralClass::Spectral_L; + break; + case SpectralClass::Spectral_L: + specClass = SpectralClass::Spectral_T; + break; + case SpectralClass::Spectral_T: specClass = SpectralClass::Spectral_C; + break; + default: break; + } subclass = st >> 4 & 0xf; lumClass = static_cast(st & 0xf); break; case WhiteDwarf: if ((st >> 8 & 0xf) >= WDClassCount) return false; - specClass = static_cast((st >> 8 & 0xf) + SpectralClass::Spectral_DA); + specClass = static_cast((st >> 8 & 0xf) + FirstWDClass); subclass = st >> 4 & 0xf; lumClass = Lum_Unknown; break; @@ -195,7 +220,7 @@ StellarClass::unpackV2(uint16_t st) case WhiteDwarf: if ((st >> 8 & 0xf) >= WDClassCount) return false; - specClass = static_cast((st >> 8 & 0xf) + SpectralClass::Spectral_DA); + specClass = static_cast((st >> 8 & 0xf) + FirstWDClass); subclass = st >> 4 & 0xf; lumClass = Lum_Unknown; break; @@ -320,6 +345,11 @@ StellarClass::parse(const string& st) state = NormalStarSubclassState; i++; break; + case 'O': + specClass = StellarClass::Spectral_WO; + state = NormalStarSubclassState; + i++; + break; default: specClass = StellarClass::Spectral_WC; state = NormalStarSubclassState; diff --git a/src/celengine/stellarclass.h b/src/celengine/stellarclass.h index 20274acd5..55299bf2a 100644 --- a/src/celengine/stellarclass.h +++ b/src/celengine/stellarclass.h @@ -40,28 +40,29 @@ public: Spectral_N = 9, // superceded by class C Spectral_WC = 10, Spectral_WN = 11, - Spectral_Unknown = 12, - Spectral_L = 13, - Spectral_T = 14, - Spectral_Y = 15, // brown dwarf - Spectral_C = 16, - Spectral_DA = 17, // white dwarf A (Balmer lines, no He I or metals) - Spectral_DB = 18, // white dwarf B (He I lines, no H or metals) - Spectral_DC = 19, // white dwarf C, continuous spectrum - Spectral_DO = 20, // white dwarf O, He II strong, He I or H - Spectral_DQ = 21, // white dwarf Q, carbon features - Spectral_DZ = 22, // white dwarf Z, metal lines only, no H or He - Spectral_D = 23, // generic white dwarf, no additional data - Spectral_DX = 24, - Spectral_Count = 25, + Spectral_WO = 12, + Spectral_Unknown = 13, + Spectral_L = 14, + Spectral_T = 15, + Spectral_Y = 16, // brown dwarf + Spectral_C = 17, + Spectral_DA = 18, // white dwarf A (Balmer lines, no He I or metals) + Spectral_DB = 19, // white dwarf B (He I lines, no H or metals) + Spectral_DC = 20, // white dwarf C, continuous spectrum + Spectral_DO = 21, // white dwarf O, He II strong, He I or H + Spectral_DQ = 22, // white dwarf Q, carbon features + Spectral_DZ = 23, // white dwarf Z, metal lines only, no H or He + Spectral_D = 24, // generic white dwarf, no additional data + Spectral_DX = 25, + Spectral_Count = 26, }; enum { - FirstWDClass = 17, + FirstWDClass = 18, WDClassCount = 8, SubclassCount = 11, - NormalClassCount = 17, + NormalClassCount = 18, }; enum LuminosityClass @@ -111,8 +112,8 @@ public: uint16_t packV2() const; bool unpackV2(uint16_t); - /* [[deprecated]] */ inline uint16_t pack() const; - /* [[deprecated]] */ inline bool unpack(uint16_t); + [[deprecated]] inline uint16_t pack() const; + [[deprecated]] inline bool unpack(uint16_t); private: StarType starType; @@ -168,11 +169,11 @@ StellarClass::LuminosityClass StellarClass::getLuminosityClass() const return lumClass; } -/* [[deprecated]] */ uint16_t StellarClass::pack() const +[[deprecated]] uint16_t StellarClass::pack() const { return packV1(); } -/* [[deprecated]] */ bool StellarClass::unpack(uint16_t t) +[[deprecated]] bool StellarClass::unpack(uint16_t t) { return unpackV1(t); } diff --git a/src/celestia/configfile.cpp b/src/celestia/configfile.cpp index ead95d34c..0ea334488 100644 --- a/src/celestia/configfile.cpp +++ b/src/celestia/configfile.cpp @@ -291,6 +291,7 @@ CelestiaConfig* ReadCelestiaConfig(const fs::path& filename, CelestiaConfig *con starTexTable->getString("N", starTexNames[StellarClass::Spectral_N]); starTexTable->getString("WC", starTexNames[StellarClass::Spectral_WC]); starTexTable->getString("WN", starTexNames[StellarClass::Spectral_WN]); + starTexTable->getString("WO", starTexNames[StellarClass::Spectral_WO]); starTexTable->getString("Unknown", starTexNames[StellarClass::Spectral_Unknown]); starTexTable->getString("L", starTexNames[StellarClass::Spectral_L]); starTexTable->getString("T", starTexNames[StellarClass::Spectral_T]); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 3ceab8039..24dbac3b0 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -2,6 +2,7 @@ include(TestCase) test_case(hash celengine) test_case(fs celengine) +test_case(stellarclass celengine) if(WIN32) test_case(winutil celutil) endif() diff --git a/test/unit/stellarclass_test.cpp b/test/unit/stellarclass_test.cpp new file mode 100644 index 000000000..513905495 --- /dev/null +++ b/test/unit/stellarclass_test.cpp @@ -0,0 +1,198 @@ +#include + +#define CATCH_CONFIG_MAIN +#include + +#define CHECK_NORMAL_STAR(u, _class, _str) \ + REQUIRE(u.getStarType() == StellarClass::NormalStar); \ + REQUIRE(u.getSpectralClass() == _class); \ + REQUIRE(u.getSubclass() == 5); \ + REQUIRE(u.getLuminosityClass() == StellarClass::Lum_Ia0); \ + REQUIRE(u.str() == _str); + +#define CHECK_WHITE_DWARF(u, _class, _str) \ + REQUIRE(u.getStarType() == StellarClass::WhiteDwarf); \ + REQUIRE(u.getSpectralClass() == _class); \ + REQUIRE(u.getSubclass() == 5); \ + REQUIRE(u.getLuminosityClass() == StellarClass::Lum_Unknown); \ + REQUIRE(u.str() == _str); + +TEST_CASE("StellarClass", "[StellarClass]") +{ + SECTION("StellarClass::Spectral_WO") + { + StellarClass sc(StellarClass::NormalStar, + StellarClass::Spectral_WO, + 5, + StellarClass::Lum_Ia0); + + uint16_t packed; + StellarClass u; + + SECTION("Packed as V1") + { + packed = sc.packV1(); + REQUIRE(u.unpackV1(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown, "?5 I-a0"); + } + + SECTION("Packed as V2") + { + packed = sc.packV2(); + REQUIRE(u.unpackV2(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_WO, "W5 I-a0"); + } + } + + SECTION("StellarClass::Spectral_Y") + { + StellarClass sc(StellarClass::NormalStar, + StellarClass::Spectral_Y, + 5, + StellarClass::Lum_Ia0); + + uint16_t packed; + StellarClass u; + + SECTION("Packed as V1") + { + packed = sc.packV1(); + REQUIRE(u.unpackV1(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown, "?5 I-a0"); + } + + SECTION("Packed as V2") + { + packed = sc.packV2(); + REQUIRE(u.unpackV2(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_Y, "Y5 I-a0"); + } + } + + SECTION("StellarClass::Spectral_Unknown") + { + StellarClass sc(StellarClass::NormalStar, + StellarClass::Spectral_Unknown, + 5, + StellarClass::Lum_Ia0); + + uint16_t packed; + StellarClass u; + + SECTION("Packed as V1") + { + packed = sc.packV1(); + REQUIRE(u.unpackV1(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown, "?5 I-a0"); + } + + SECTION("Packed as V2") + { + packed = sc.packV2(); + REQUIRE(u.unpackV2(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_Unknown, "?5 I-a0"); + } + } + + SECTION("StellarClass::Spectral_C") + { + StellarClass sc(StellarClass::NormalStar, + StellarClass::Spectral_C, + 5, + StellarClass::Lum_Ia0); + + uint16_t packed; + StellarClass u; + + SECTION("Packed as V1") + { + packed = sc.packV1(); + REQUIRE(u.unpackV1(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_C, "C5 I-a0"); + } + + SECTION("Packed as V2") + { + packed = sc.packV2(); + REQUIRE(u.unpackV2(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_C, "C5 I-a0"); + } + } + + SECTION("StellarClass::Spectral_L") + { + StellarClass sc(StellarClass::NormalStar, + StellarClass::Spectral_L, + 5, + StellarClass::Lum_Ia0); + + uint16_t packed; + StellarClass u; + + SECTION("Packed as V1") + { + packed = sc.packV1(); + REQUIRE(u.unpackV1(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_L, "L5 I-a0"); + } + + SECTION("Packed as V2") + { + packed = sc.packV2(); + REQUIRE(u.unpackV2(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_L, "L5 I-a0"); + } + } + + + SECTION("StellarClass::Spectral_T") + { + StellarClass sc(StellarClass::NormalStar, + StellarClass::Spectral_T, + 5, + StellarClass::Lum_Ia0); + + uint16_t packed; + StellarClass u; + + SECTION("Packed as V1") + { + packed = sc.packV1(); + REQUIRE(u.unpackV1(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_T, "T5 I-a0"); + } + + SECTION("Packed as V2") + { + packed = sc.packV2(); + REQUIRE(u.unpackV2(packed)); + CHECK_NORMAL_STAR(u, StellarClass::Spectral_T, "T5 I-a0"); + } + } + + SECTION("StellarClass::Spectral_DO") + { + StellarClass sc(StellarClass::WhiteDwarf, + StellarClass::Spectral_DO, + 5, + StellarClass::Lum_Ia0); + + uint16_t packed; + StellarClass u; + + SECTION("Packed as V1") + { + packed = sc.packV1(); + REQUIRE(u.unpackV1(packed)); + CHECK_WHITE_DWARF(u, StellarClass::Spectral_DO, "WD"); + } + + SECTION("Packed as V2") + { + packed = sc.packV2(); + REQUIRE(u.unpackV2(packed)); + CHECK_WHITE_DWARF(u, StellarClass::Spectral_DO, "WD"); + } + } + +}