// buildstardb.cpp // // Copyright (C) 2001, Chris Laurel // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. #include #include #include #include #include #include #include #include #include #include "celengine/stardb.h" using namespace std; #ifdef _WIN32 static string MainDatabaseFile("hip_main.dat"); static string TychoDatabaseFile("tyc_main.dat"); static string ComponentDatabaseFile("h_dm_com.dat"); static string OrbitalDatabase("hip_dm_o.dat"); #else #ifndef MACOSX_PB #include #endif /*MACOSX_PB*/ static string MainDatabaseFile(HIP_DATA_DIR "/hip_main.dat"); static string TychoDatabaseFile(HIP_DATA_DIR "/tyc_main.dat"); static string ComponentDatabaseFile(HIP_DATA_DIR "/h_dm_com.dat"); static string OrbitalDatabase(HIP_DATA_DIR "/hip_dm_o.dat"); #endif static const int HipStarRecordLength = 451; static const int HipComponentRecordLength = 239; static const int TycStarRecordLength = 351; static uint32 NullCCDMIdentifier = 0xffffffff; static uint32 NullCatalogNumber = 0xffffffff; static int verbose, dropstars; class HipparcosStar { public: HipparcosStar(); void write(ostream&); void analyze(); uint32 HIPCatalogNumber; uint32 HDCatalogNumber; float ascension; float declination; float parallax; float appMag; StellarClass stellarClass; uint32 CCDMIdentifier; uint8 starsWithCCDM; uint8 nComponents; uint8 parallaxError; uint tycline; uint status; float e_RA; // Errors in Right Ascension, float e_DE; // Declination, float e_Mag; // and Magnitude }; HipparcosStar::HipparcosStar() : HIPCatalogNumber(NullCatalogNumber), HDCatalogNumber(NullCatalogNumber), ascension(0.0f), declination(0.0f), parallax(0.0f), appMag(0.0f), CCDMIdentifier(NullCCDMIdentifier), starsWithCCDM(0), nComponents(1), parallaxError(0), tycline(0), e_RA(0.0f), e_DE(0.0f), e_Mag(0.0f) { } template void binwrite(ostream& out, T x) { out.write(reinterpret_cast(&x), sizeof(T)); } void HipparcosStar::write(ostream& out) { if (status>=2) return; #if 0 if (HDCatalogNumber != NullCatalogNumber) binwrite(out, HDCatalogNumber); else binwrite(out, HIPCatalogNumber | 0x10000000); #endif binwrite(out, HIPCatalogNumber); binwrite(out, HDCatalogNumber); binwrite(out, ascension); binwrite(out, declination); binwrite(out, parallax); binwrite(out, (short) (appMag * 256)); binwrite(out, stellarClass); binwrite(out, parallaxError); } // Statistic Values: float s_er; // Sum of Error in RA float s_erq; // Sum of Squares of Errors in RA unsigned int n_er; // Number of Error Values float s_ed, s_edq; // Ditto for Declination unsigned int n_ed; unsigned int n_drop,n_dub; // number of stars to drop, number dubious void HipparcosStar::analyze() { int dubious=0; status=0; if ((parallax) <= 0.4 && ((dropstars==0) || (dropstars==1 && appMag<6.0))) parallax=0.4; /* fix strange paralaxes so the stars aren't *way* out there. A parallax of 0.4 will put them at just a touch above 8154 LY away. */ if (parallax <= 0.0) dubious+=400; else if (parallax<0.2) dubious+=4; else if (parallax<0.4) dubious+=2; if (parallax<=parallaxError) dubious+=2; else if (parallax<=(2*parallaxError)) dubious++; if (e_RA<1000.0) { s_er+=e_RA; s_erq+=square(e_RA); n_er++; if (e_RA>20.0) dubious+=100; else if (e_RA>15.0) dubious+=2; else if (e_RA>10.0) dubious++; } else dubious+=4; /* No error given, assume it's rather dubious */ if (e_DE<1000.0) { s_ed+=e_DE; s_edq+=square(e_DE); n_ed++; if (e_DE>20.0) dubious+=100; else if (e_DE>15.0) dubious+=2; else if (e_DE>10.0) dubious++; } else dubious+=4; /* No error given, assume it's rather dubious */ if (dubious>3) { status=1; n_dub++; } if ((dubious>5) && (dropstars) && (!(dropstars==1 && appMag<6.0))) { status=2; n_drop++; } } bool operator<(const HipparcosStar& a, const HipparcosStar& b) { return a.HIPCatalogNumber < b.HIPCatalogNumber; } struct HIPCatalogComparePredicate { HIPCatalogComparePredicate() : dummy(0) { } bool operator()(const HipparcosStar* star0, const HipparcosStar* star1) const { return star0->HIPCatalogNumber < star1->HIPCatalogNumber; } bool operator()(const HipparcosStar* star0, uint32 hip) { return star0->HIPCatalogNumber < hip; } int dummy; }; class MultistarSystem { public: int nStars; // Never greater than four in the HIPPARCOS catalog HipparcosStar* stars[4]; }; class HipparcosComponent { public: HipparcosComponent(); HipparcosStar* star; char componentID; char refComponentID; float ascension; float declination; float appMag; float bMag; float vMag; bool hasBV; float positionAngle; float separation; }; HipparcosComponent::HipparcosComponent() : star(NULL), componentID('A'), refComponentID('A'), appMag(0.0f), bMag(0.0f), vMag(0.0f), hasBV(false), positionAngle(0.0f), separation(0.0f) { } vector stars; vector companions; vector components; vector starIndex; typedef map MultistarSystemCatalog; MultistarSystemCatalog starSystems; HipparcosStar* findStar(uint32 hip) { HIPCatalogComparePredicate pred; vector::iterator iter = lower_bound(starIndex.begin(), starIndex.end(), hip, pred); if (iter == starIndex.end()) return NULL; HipparcosStar* star = *iter; if (star->HIPCatalogNumber == hip) return star; else return NULL; } StellarClass ParseStellarClass(char *starType) { StellarClass::StarType type = StellarClass::NormalStar; StellarClass::SpectralClass specClass = StellarClass::Spectral_A; StellarClass::LuminosityClass lum = StellarClass::Lum_V; unsigned short number = 5; int i = 0; // Subdwarves (luminosity class VI) are prefixed with sd if (starType[i] == 's' && starType[i + 1] == 'd') { lum = StellarClass::Lum_VI; i += 2; } switch (starType[i]) { case 'O': specClass = StellarClass::Spectral_O; break; case 'B': specClass = StellarClass::Spectral_B; break; case 'A': specClass = StellarClass::Spectral_A; break; case 'F': specClass = StellarClass::Spectral_F; break; case 'G': specClass = StellarClass::Spectral_G; break; case 'K': specClass = StellarClass::Spectral_K; break; case 'M': specClass = StellarClass::Spectral_M; break; case 'R': specClass = StellarClass::Spectral_R; break; case 'N': specClass = StellarClass::Spectral_S; break; case 'S': specClass = StellarClass::Spectral_N; break; case 'W': i++; if (starType[i] == 'C') specClass = StellarClass::Spectral_WC; else if (starType[i] == 'N') specClass = StellarClass::Spectral_WN; else i--; break; case 'D': type = StellarClass::WhiteDwarf; return StellarClass(type, specClass, 0, lum); default: specClass = StellarClass::Spectral_Unknown; break; } i++; if (starType[i] >= '0' && starType[i] <= '9') { number = starType[i] - '0'; } else { // No number given for spectral class; assume it's a 5 unless // the star is type O, as O5 stars are exceedingly rare. if (specClass == StellarClass::Spectral_O) number = 9; else number = 5; } if (lum != StellarClass::Lum_VI) { i++; lum = StellarClass::Lum_V; while (i < 13 && starType[i] != '\0') { if (starType[i] == 'I') { if (starType[i + 1] == 'I') { if (starType[i + 2] == 'I') { lum = StellarClass::Lum_III; } else { lum = StellarClass::Lum_II; } } else if (starType[i + 1] == 'V') { lum = StellarClass::Lum_IV; } else if (starType[i + 1] == 'a') { if (starType[i + 2] == '0') lum = StellarClass::Lum_Ia0; else lum = StellarClass::Lum_Ia; } else if (starType[i + 1] == 'b') { lum = StellarClass::Lum_Ib; } else { lum = StellarClass::Lum_Ib; } break; } else if (starType[i] == 'V') { if (starType[i + 1] == 'I') lum = StellarClass::Lum_VI; else lum = StellarClass::Lum_V; break; } i++; } } return StellarClass(type, specClass, number, lum); } HipparcosStar TheSun() { HipparcosStar star; star.HDCatalogNumber = 0; star.HIPCatalogNumber = 0; star.ascension = 0.0f; star.declination = 0.0f; star.parallax = 1000000.0f; star.appMag = -15.17f; star.stellarClass = StellarClass(StellarClass::NormalStar, StellarClass::Spectral_G, 2, StellarClass::Lum_V); return star; } StellarClass guessSpectralType(float colorIndex, float absMag) { StellarClass::SpectralClass specClass = StellarClass::Spectral_Unknown; float subclass = 0.0f; if (colorIndex < -0.25f) { specClass = StellarClass::Spectral_O; subclass = (colorIndex + 0.5f) / 0.25f; } else if (colorIndex < 0.0f) { specClass = StellarClass::Spectral_B; subclass = (colorIndex + 0.25f) / 0.25f; } else if (colorIndex < 0.25f) { specClass = StellarClass::Spectral_A; subclass = (colorIndex - 0.0f) / 0.25f; } else if (colorIndex < 0.6f) { specClass = StellarClass::Spectral_F; subclass = (colorIndex - 0.25f) / 0.35f; } else if (colorIndex < 0.85f) { specClass = StellarClass::Spectral_G; subclass = (colorIndex - 0.6f) / 0.25f; } else if (colorIndex < 1.4f) { specClass = StellarClass::Spectral_K; subclass = (colorIndex - 0.85f) / 0.55f; } else { specClass = StellarClass::Spectral_M; subclass = (colorIndex - 1.4f) / 1.0f; } if (subclass < 0.0f) subclass = 0.0f; else if (subclass > 1.0f) subclass = 1.0f; return StellarClass(StellarClass::NormalStar, specClass, (unsigned int) (subclass * 9.99f), StellarClass::Lum_V); } static unsigned int okStars, lineno, changes, tested; bool CheckStarRecord(istream& in) { HipparcosStar star,*hipstar; char buf[HipStarRecordLength]; bool ok=true; in.read(buf, TycStarRecordLength); lineno++; if (sscanf(buf + 210, "%d", &star.HIPCatalogNumber) != 1) { // Not in Hipparcos, skip it. if (verbose>1) cout << "Error reading HIPPARCOS catalog number.\n"; return false; } if (verbose>1) cout << "Testing HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; if (!(hipstar=findStar(star.HIPCatalogNumber))) { cout << "Error finding HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; return false; } if (hipstar->tycline) { if (verbose>0) cout << "Duplicate Tycho Line for HIP " << star.HIPCatalogNumber << " from Line " << lineno << ", earlier Line at " << hipstar->tycline << " ." << endl; } else hipstar->tycline=lineno; tested++; sscanf(buf + 309, "%d", &star.HDCatalogNumber); if (sscanf(buf + 224, "%f", &star.e_Mag) != 1) /* Tycho Database gives no error in for VMag, so we use error on BTmag instead.*/ { /* no standard Error given even in BTmag, give it a large value so CheckStarRecord() will use the Tycho value if possible */ star.e_Mag = 1000.0f; } else if (star.e_Mag >1000.0) { cout << "Huge BTmag error for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; } if (sscanf(buf + 41, "%f", &star.appMag) != 1) { if (verbose>0) cout << "Error reading magnitude for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; } else if (star.e_Mag < hipstar->e_Mag) { hipstar->appMag=star.appMag; hipstar->e_Mag=star.e_Mag; changes++; if (verbose > 2) cout << " Change Mag.\n"; } float parallaxError = 0.0f; if (sscanf(buf + 119, "%f", ¶llaxError) != 0) { if (star.parallax < 0.0f || parallaxError / star.parallax > 1.0f) star.parallaxError = (int8) 255; else star.parallaxError = (int8) (parallaxError / star.parallax * 200); } if (sscanf(buf + 79, "%f", &star.parallax) != 1) { if (verbose>0) cout << "Error reading parallax for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; ok=false; } else if (star.parallax< 0.0) { if (hipstar->parallax< 0.0) { if (verbose>0) cout << "Negative parallax for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; ok=false; } } else if (star.parallaxError < hipstar->parallaxError) { hipstar->parallax=star.parallax; hipstar->parallaxError=star.parallaxError; changes++; if (verbose > 2) cout << " Change Parallax.\n"; } if (sscanf(buf + 105, "%f", &star.e_RA) != 1) { /* no standard Error givenfor Right Ascension , give it a large value so original HIPPARCOS value will be used */ if (verbose>0) cout << "No RA error for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; star.e_RA = 2000.0f; } else if (star.e_RA >1000.0) { cout << "Huge RA error for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; } if (sscanf(buf + 112, "%f", &star.e_DE) != 1) { /* no standard Error given for Declination, give it a large value so original HIPPARCOS value will be used. */ if (verbose>0) cout << "No DE error for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; star.e_DE = 2000.0f; } else if (star.e_DE >1000.0) { cout << "Huge DE error for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; } bool coordReadError = false; if (sscanf(buf + 51, "%f", &star.ascension) != 1) coordReadError = true; if (sscanf(buf + 64, "%f", &star.declination) != 1) coordReadError = true; star.ascension = (float) (star.ascension * 24.0 / 360.0); // Read the lower resolution coordinates in hhmmss form if we failed // to read the coordinates in degrees. Not sure why the high resolution // coordinates are occasionally missing . . . if (coordReadError) { int hh = 0; int mm = 0; float seconds; coordReadError=false; if (sscanf(buf + 17, "%d %d %f", &hh, &mm, &seconds) != 3) { cout << "Error reading ascension for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; coordReadError=true;; } else { star.ascension = hh + (float) mm / 60.0f + (float) seconds / 3600.0f; char decSign; int deg; if (sscanf(buf + 29, "%c%d %d %f", &decSign, °, &mm, &seconds) != 4) { cout << "Error reading declination for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; coordReadError=true;; } else { star.declination = deg + (float) mm / 60.0f + (float) seconds / 3600.0f; if (decSign == '-') star.declination = -star.declination; } } } if (!((coordReadError) || ((star.ascension==hipstar->ascension) && (star.declination==hipstar->declination)))) { float ast=star.e_RA * star.e_DE; float ahi=hipstar->e_RA * hipstar->e_DE; if ((aste_RA + hipstar->e_DE)))) //if ((star.e_RA * star.e_DE) < (hipstar->e_RA * hipstar->e_DE)) { // Error on the Tycho value is smaller, use it. hipstar->ascension=star.ascension; hipstar->declination=star.declination; hipstar->e_RA=star.e_RA; hipstar->e_DE=star.e_DE; changes++; if (verbose > 2) cout << " Change Position.\n"; } } int asc = 0; int dec = 0; char decSign = ' '; if (sscanf(buf + 299, "%d%c%d", &asc, &decSign, &dec) == 3) { if (decSign == '-') dec = -dec; star.CCDMIdentifier = asc << 16 | (dec & 0xffff); if (star.CCDMIdentifier != hipstar->CCDMIdentifier) { cout << "Diffrence in CCDM Identifier for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; ok=false; } } if (ok) okStars++; return true; } bool ReadStarRecord(istream& in) { HipparcosStar star; char buf[HipStarRecordLength]; in.read(buf, HipStarRecordLength); if (sscanf(buf + 8, "%d", &star.HIPCatalogNumber) != 1) { cout << "Error reading catalog number.\n"; return false; } sscanf(buf + 390, "%d", &star.HDCatalogNumber); star.tycline=0; if (sscanf(buf + 41, "%f", &star.appMag) != 1) { if (verbose>0) cout << "Error reading magnitude for HIP " << star.HIPCatalogNumber << " ." << endl; return false; } if (sscanf(buf + 79, "%f", &star.parallax) != 1) { if (verbose>0) cout << "Error reading parallax for HIP " << star.HIPCatalogNumber << " ." << endl; return false; } if (star.parallax< 0.0) { if (verbose>0) cout << "Negative parallax for HIP " << star.HIPCatalogNumber << " ." << endl; } bool coordReadError = false; if (sscanf(buf + 51, "%f", &star.ascension) != 1) coordReadError = true; if (sscanf(buf + 64, "%f", &star.declination) != 1) coordReadError = true; star.ascension = (float) (star.ascension * 24.0 / 360.0); // Read the lower resolution coordinates in hhmmss form if we failed // to read the coordinates in degrees. Not sure why the high resolution // coordinates are occasionally missing . . . if (coordReadError) { int hh = 0; int mm = 0; float seconds; if (sscanf(buf + 17, "%d %d %f", &hh, &mm, &seconds) != 3) { cout << "Error reading ascension for HIP " << star.HIPCatalogNumber << " ." << endl; return false; } star.ascension = hh + (float) mm / 60.0f + (float) seconds / 3600.0f; char decSign; int deg; if (sscanf(buf + 29, "%c%d %d %f", &decSign, °, &mm, &seconds) != 4) { cout << "Error reading declination for HIP " << star.HIPCatalogNumber << " ." << endl; return false; } star.declination = deg + (float) mm / 60.0f + (float) seconds / 3600.0f; if (decSign == '-') star.declination = -star.declination; } int asc = 0; int dec = 0; char decSign = ' '; int n = 1; if (sscanf(buf + 327, "%d%c%d", &asc, &decSign, &dec) == 3) { if (decSign == '-') dec = -dec; star.CCDMIdentifier = asc << 16 | (dec & 0xffff); sscanf(buf + 340, "%d", &n); star.starsWithCCDM = (uint8) n; sscanf(buf + 343, "%d", &n); star.nComponents = (uint8) n; } char* spectralType = buf + 435; spectralType[12] = '\0'; star.stellarClass = ParseStellarClass(spectralType); if (star.stellarClass.getSpectralClass() == StellarClass::Spectral_Unknown) { float bmag,vmag; if ((sscanf(buf + 217, "%f", &bmag) == 1) && (sscanf(buf + 230, "%f", &vmag) == 1)) { if (verbose>0) cout << "Guessing Type " << spectralType << "for HIP " << star.HIPCatalogNumber << " ." << endl; star.stellarClass = guessSpectralType(bmag - vmag, 0.0f); } else if (verbose>0) cout << "Unparsable stellar class " << spectralType << "for HIP " << star.HIPCatalogNumber << " ." << endl; } float parallaxError = 0.0f; if (sscanf(buf + 119, "%f", ¶llaxError) != 0) { if (star.parallax < 0.0f || parallaxError / star.parallax > 1.0f) star.parallaxError = (int8) 254; else star.parallaxError = (int8) (parallaxError / star.parallax * 200); } if (sscanf(buf + 105, "%f", &star.e_RA) != 1) { /* no standard Error givenfor Right Ascension , give it a large value so CheckStarRecord() will use Tycho value if possible */ star.e_RA = 1000.0f; } else if (star.e_RA >1000.0) { cout << "Huge RA error for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; } if (sscanf(buf + 112, "%f", &star.e_DE) != 1) { /* no standard Error given for Declination, give it a large value so CheckStarRecord() will use the Tycho value if possible */ star.e_DE = 1000.0f; } else if (star.e_DE >1000.0) { cout << "Huge DE error for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; } if (sscanf(buf + 224, "%f", &star.e_Mag) != 1) // No error in HIPPARCOS for VMag, use error on BTmag instead. { /* no standard Error given give it a large value so CheckStarRecord() will use the Tycho value if possible */ star.e_Mag = 1000.0f; } else if (star.e_Mag >1000.0) { cout << "Huge BTmag error for HIP " << star.HIPCatalogNumber << " from Line " << lineno << " ." << endl; } stars.insert(stars.end(), star); return true; } bool ReadComponentRecord(istream& in) { HipparcosComponent component; char buf[HipComponentRecordLength]; in.read(buf, HipComponentRecordLength); uint32 hip; if (sscanf(buf + 42, "%ud", &hip) != 1) { cout << "Missing HIP catalog number for component.\n"; return false; } component.star = findStar(hip); if (component.star == NULL) { cout << "Nonexistent HIP catalog number for component.\n"; return false; } if (sscanf(buf + 40, "%c", &component.componentID) != 1) { cout << "Missing component identifier.\n"; return false; } if (sscanf(buf + 175, "%c", &component.refComponentID) != 1) { cout << "Error reading reference component.\n"; return false; } if (component.refComponentID == ' ') component.refComponentID = component.componentID; // Read astrometric information if (sscanf(buf + 88, "%f", &component.ascension) != 1) { cout << "Missing ascension for component.\n"; return false; } component.ascension = (float) (component.ascension * 24.0 / 360.0); if (sscanf(buf + 101, "%f", &component.declination) != 1) { cout << "Missing declination for component.\n"; return false; } // Read photometric information if (sscanf(buf + 49, "%f", &component.appMag) != 1) { cout << "Missing magnitude for component.\n"; return false; } // vMag and bMag may be necessary to guess the spectral type if (sscanf(buf + 62, "%f", &component.bMag) != 1 || sscanf(buf + 75, "%f", &component.vMag) != 1) { component.bMag = component.vMag = component.appMag; } else { component.hasBV = true; } if (component.componentID != component.refComponentID) { if (sscanf(buf + 177, "%f", &component.positionAngle) != 1) { cout << "Missing position angle for component.\n"; return false; } if (sscanf(buf + 185, "%f", &component.separation) != 1) { cout << "Missing separation for component.\n"; return false; } } components.insert(components.end(), component); return true; }; void BuildMultistarSystemCatalog() { for (vector::iterator iter = stars.begin(); iter != stars.end(); iter++) { if (iter->CCDMIdentifier != NullCCDMIdentifier) { MultistarSystemCatalog::iterator it = starSystems.find(iter->CCDMIdentifier); if (it == starSystems.end()) { MultistarSystem* multiSystem = new MultistarSystem(); multiSystem->nStars = 1; multiSystem->stars[0] = &*iter; starSystems.insert(MultistarSystemCatalog::value_type(iter->CCDMIdentifier, multiSystem)); } else { MultistarSystem* multiSystem = it->second; if (multiSystem->nStars == 4) { cout << "Number of stars in system exceeds 4\n"; } else { multiSystem->stars[multiSystem->nStars] = &*iter; multiSystem->nStars++; } } } } } void ConstrainComponentParallaxes() { for (MultistarSystemCatalog::iterator iter = starSystems.begin(); iter != starSystems.end(); iter++) { MultistarSystem* multiSystem = iter->second; if (multiSystem->nStars > 1) { for (int i = 1; i < multiSystem->nStars; i++) multiSystem->stars[i]->parallax = multiSystem->stars[0]->parallax; } #if 0 if (multiSystem->nStars > 2) { cout << multiSystem->nStars << ": "; if (multiSystem->stars[0]->HDCatalogNumber != NullCatalogNumber) cout << "HD " << multiSystem->stars[0]->HDCatalogNumber; else cout << "HIP " << multiSystem->stars[0]->HIPCatalogNumber; cout << '\n'; } #endif } } void CorrectErrors() { for (vector::iterator iter = stars.begin(); iter != stars.end(); iter++) { // Fix the spectral class of Capella, listed for some reason // as M1 in the database. if (iter->HDCatalogNumber == 34029) { iter->stellarClass = StellarClass(StellarClass::NormalStar, StellarClass::Spectral_G, 0, StellarClass::Lum_III); } } } // Process the vector of star components and insert those that are companions // of stars in the primary database into the companions vector. void CreateCompanionList() { for (vector::iterator iter = components.begin(); iter != components.end(); iter++) { // Don't insert the reference component, as this star should already // be in the primary database. if (iter->componentID != iter->refComponentID) { int componentNumber = iter->componentID - 'A'; if (componentNumber > 0 && componentNumber < 8) { HipparcosStar star; star.HDCatalogNumber = NullCatalogNumber; star.HIPCatalogNumber = iter->star->HIPCatalogNumber | (componentNumber << 25); star.ascension = iter->ascension; star.declination = iter->declination; star.parallax = iter->star->parallax; star.appMag = iter->appMag; if (iter->hasBV) star.stellarClass = guessSpectralType(iter->bMag - iter->vMag, 0.0f); else star.stellarClass = StellarClass(StellarClass::NormalStar, StellarClass::Spectral_Unknown, 0, StellarClass::Lum_V); star.CCDMIdentifier = iter->star->CCDMIdentifier; star.parallaxError = iter->star->parallaxError; companions.insert(companions.end(), star); } } } } void ShowStarsWithComponents() { cout << "\nStars with >2 components\n"; for (vector::iterator iter = stars.begin(); iter != stars.end(); iter++) { if (iter->nComponents > 2) { cout << (int) iter->nComponents << ": "; if (iter->HDCatalogNumber != NullCatalogNumber) cout << "HD " << iter->HDCatalogNumber; else cout << "HIP " << iter->HIPCatalogNumber; cout << '\n'; } } } void CompareTycho() { ifstream tycDatabase(TychoDatabaseFile.c_str(), ios::in | ios::binary); if (!tycDatabase.is_open()) { cout << "Error opening " << TychoDatabaseFile << '\n'; cout << "You may download this file from ftp://cdsarc.u-strasbg.fr/cats/I/239/\n"; return; } int recs=0; cout << "Comparing Tycho data set.\n"; okStars=0; lineno=0; changes=0; while (tycDatabase.good()) { CheckStarRecord(tycDatabase); if (++recs % 10000 == 0) { if (verbose>=0) cout << recs << " records.\n"; else cout << "."; cout.flush(); } } if (verbose<0) cout << "\n"; else cout << recs << " records checked, " << tested << " tested, " << okStars << " checked out OK, and " << changes << " changes were made.\n"; } int main(int argc, char* argv[]) { assert(sizeof(StellarClass) == 2); verbose=0; dropstars=1; int c; while((c=getopt(argc,argv,"v::qd:"))>-1) { if (c=='?') { cout << "Usage: buildstardb [-v[] [-q] [-d \n"; exit(1); } else if (c=='v') { if (optarg) { verbose=(int)atol(optarg); if (verbose<-1) verbose=-1; else if (verbose>3) verbose=3; } else verbose=1; } else if (c=='d') { /* Dropstar level. 0 = don't drop stars 1 = drop only non-naked eye visible stars 2 = drop all stars with strange values */ dropstars=(int)atol(optarg); if (dropstars<0) dropstars=0; else if (dropstars>2) dropstars=2; } else if (c=='q') { verbose=-1; } } // Read star records from the primary HIPPARCOS catalog { ifstream mainDatabase(MainDatabaseFile.c_str(), ios::in | ios::binary); if (!mainDatabase.is_open()) { cout << "Error opening " << MainDatabaseFile << '\n'; cout << "You may download this file from ftp://cdsarc.u-strasbg.fr/cats/I/239/\n"; exit(1); } cout << "Reading HIPPARCOS data set.\n"; while (mainDatabase.good()) { ReadStarRecord(mainDatabase); if (stars.size() % 10000 == 0) { if (verbose>=0) cout << stars.size() << " records.\n"; else cout << "."; cout.flush(); } } if (verbose<0) cout << "\n"; } if (verbose>=0) { cout << "Read " << stars.size() << " stars from main database.\n"; cout << "Adding the Sun...\n"; } stars.insert(stars.end(), TheSun()); if (verbose>=0) cout << "Sorting stars...\n"; { starIndex.reserve(stars.size()); for (vector::iterator iter = stars.begin(); iter != stars.end(); iter++) { starIndex.insert(starIndex.end(), &*iter); } HIPCatalogComparePredicate pred; // It may not even be necessary to sort the records, if the // HIPPARCOS catalog is strictly ordered by catalog number. I'm not // sure about this however, random_shuffle(starIndex.begin(), starIndex.end()); sort(starIndex.begin(), starIndex.end(), pred); } // Read component records { ifstream componentDatabase(ComponentDatabaseFile.c_str(), ios::in | ios::binary); if (!componentDatabase.is_open()) { cout << "Error opening " << ComponentDatabaseFile << '\n'; cout << "You may download this file from ftp://cdsarc.u-strasbg.fr/cats/I/239/\n"; exit(1); } if (verbose>=0) cout << "Reading HIPPARCOS component database.\n"; while (componentDatabase.good()) { ReadComponentRecord(componentDatabase); } } if (verbose>=0) cout << "Read " << components.size() << " components.\n"; { int aComp = 0, bComp = 0, cComp = 0, dComp = 0, eComp = 0, otherComp = 0; int bvComp = 0; for (unsigned int i = 0; i < components.size(); i++) { switch (components[i].componentID) { case 'A': aComp++; break; case 'B': bComp++; break; case 'C': cComp++; break; case 'D': dComp++; break; case 'E': eComp++; break; default: otherComp++; break; } if (components[i].hasBV && components[i].componentID != 'A') bvComp++; } if (verbose>=0) { cout << "A:" << aComp << " B:" << bComp << " C:" << cComp << " D:" << dComp << " E:" << eComp << '\n'; cout << "Components with B-V mag: " << bvComp << '\n'; } } if (verbose>=0) cout << "Building catalog of multiple star systems.\n"; BuildMultistarSystemCatalog(); int nMultipleSystems = starSystems.size(); if (verbose>=0) cout << "Stars in multiple star systems: " << nMultipleSystems << '\n'; ConstrainComponentParallaxes(); CorrectErrors(); CompareTycho(); // CreateCompanionList(); if (verbose>=0) { cout << "Companion stars: " << companions.size() << '\n'; cout << "Total stars: " << stars.size() + companions.size() << '\n'; } if (verbose>0) ShowStarsWithComponents(); const char* outputFile = "stars.dat"; if (argv[optind]) outputFile = argv[optind]; cout << "Writing processed star records to " << outputFile << '\n'; ofstream out(outputFile, ios::out | ios::binary); if (!out.good()) { cout << "Error opening " << outputFile << '\n'; exit(1); } s_er=0.0; // Zero the statistics values s_erq=0.0; n_er=0; s_er=0.0; s_erq=0.0; n_er=0; n_drop=0; n_dub=0; { vector::iterator iter; for (iter = stars.begin(); iter != stars.end(); iter++) iter->analyze(); for (iter = companions.begin(); iter != companions.end(); iter++) iter->analyze(); binwrite(out, stars.size() + companions.size() - n_drop); float av_r,av_d; // average Right Ascension/Declination av_r=s_er/((float)n_er); av_d=s_ed/((float)n_ed); if (verbose>=0) { cout << "RA Error average: " << av_r << " with Standard Error: " << sqrt((s_erq+(square(s_er)/n_er) - (2*av_r*s_er))/(n_er-1)) << " .\n"; cout << "DE Error average: " << av_d << " with Standard Error: " << sqrt((s_edq+(square(s_ed)/n_ed) - (2*av_d*s_ed))/(n_ed-1)) << " .\n"; } for (iter = stars.begin(); iter != stars.end(); iter++) iter->write(out); for (iter = companions.begin(); iter != companions.end(); iter++) iter->write(out); } cout << "Stars processed: " << stars.size() + companions.size() << " Number dropped: " << n_drop << " number dubious: " << n_dub << " .\n"; #if 0 char* hdOutputFile = "hdxref.dat"; cout << "Writing out HD cross reference to " << hdOutputFile << '\n'; ofstream hdout(hdOutputFile, ios::out | ios::binary); if (!out.good()) { cout << "Error opening " << hdOutputFile << '\n'; exit(1); } { int nHD = 0; vector::iterator iter; for (iter = stars.begin(); iter != stars.end(); iter++) { if (iter->HDCatalogNumber != NullCatalogNumber) nHD++; } binwrite(hdout, nHD); cout << nHD << " stars have HD numbers.\n"; for (iter = stars.begin(); iter != stars.end(); iter++) { if (iter->HDCatalogNumber != NullCatalogNumber) { binwrite(hdout, iter->HDCatalogNumber); binwrite(hdout, iter->HIPCatalogNumber); } } } #endif return 0; }