1 // buildstardb.cpp
2 //
3 // Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 
10 #include <string>
11 #include <vector>
12 #include <map>
13 #include <algorithm>
14 #include <iostream>
15 #include <fstream>
16 #include <cstdio>
17 #include <assert.h>
18 #include "stardb.h"
19 
20 using namespace std;
21 
22 
23 static string MainDatabaseFile("hip_main.dat");
24 static string ComponentDatabaseFile("h_dm_com.dat");
25 static string OrbitalDatabase("hip_dm_o.dat");
26 
27 static const int HipStarRecordLength = 451;
28 static const int HipComponentRecordLength = 239;
29 
30 static uint32 NullCCDMIdentifier = 0xffffffff;
31 static uint32 NullCatalogNumber = 0xffffffff;
32 
33 
34 class HipparcosStar
35 {
36 public:
37     HipparcosStar();
38 
39     void write(ostream&);
40 
41     uint32 HIPCatalogNumber;
42     uint32 HDCatalogNumber;
43     float ascension;
44     float declination;
45     float parallax;
46     float appMag;
47     StellarClass stellarClass;
48 
49     uint32 CCDMIdentifier;
50     uint8 starsWithCCDM;
51     uint8 nComponents;
52     uint8 parallaxError;
53 };
54 
HipparcosStar()55 HipparcosStar::HipparcosStar() :
56     HIPCatalogNumber(NullCatalogNumber),
57     HDCatalogNumber(NullCatalogNumber),
58     ascension(0.0f),
59     declination(0.0f),
60     parallax(0.0f),
61     appMag(0.0f),
62     CCDMIdentifier(NullCCDMIdentifier),
63     starsWithCCDM(0),
64     nComponents(1),
65     parallaxError(0)
66 {
67 }
68 
binwrite(ostream & out,T x)69 template<class T> void binwrite(ostream& out, T x)
70 {
71     out.write(reinterpret_cast<char*>(&x), sizeof(T));
72 }
73 
write(ostream & out)74 void HipparcosStar::write(ostream& out)
75 {
76 #if 0
77     if (HDCatalogNumber != NullCatalogNumber)
78         binwrite(out, HDCatalogNumber);
79     else
80         binwrite(out, HIPCatalogNumber | 0x10000000);
81 #endif
82     binwrite(out, HIPCatalogNumber);
83     binwrite(out, HDCatalogNumber);
84     binwrite(out, ascension);
85     binwrite(out, declination);
86     binwrite(out, parallax);
87     binwrite(out, (short) (appMag * 256));
88     binwrite(out, stellarClass);
89     binwrite(out, parallaxError);
90 }
91 
operator <(const HipparcosStar & a,const HipparcosStar & b)92 bool operator<(const HipparcosStar& a, const HipparcosStar& b)
93 {
94     return a.HIPCatalogNumber < b.HIPCatalogNumber;
95 }
96 
97 struct HIPCatalogComparePredicate
98 {
HIPCatalogComparePredicateHIPCatalogComparePredicate99     HIPCatalogComparePredicate() : dummy(0)
100     {
101     }
102 
operator ()HIPCatalogComparePredicate103     bool operator()(const HipparcosStar* star0, const HipparcosStar* star1) const
104     {
105         return star0->HIPCatalogNumber < star1->HIPCatalogNumber;
106     }
107 
operator ()HIPCatalogComparePredicate108     bool operator()(const HipparcosStar* star0, uint32 hip)
109     {
110         return star0->HIPCatalogNumber < hip;
111     }
112 
113     int dummy;
114 };
115 
116 
117 class MultistarSystem
118 {
119 public:
120     int nStars; // Never greater than four in the HIPPARCOS catalog
121     HipparcosStar* stars[4];
122 };
123 
124 
125 class HipparcosComponent
126 {
127 public:
128     HipparcosComponent();
129 
130     HipparcosStar* star;
131     char componentID;
132     char refComponentID;
133     float ascension;
134     float declination;
135     float appMag;
136     float bMag;
137     float vMag;
138     bool hasBV;
139     float positionAngle;
140     float separation;
141 };
142 
HipparcosComponent()143 HipparcosComponent::HipparcosComponent() :
144     star(NULL),
145     componentID('A'),
146     refComponentID('A'),
147     appMag(0.0f),
148     bMag(0.0f),
149     vMag(0.0f),
150     hasBV(false),
151     positionAngle(0.0f),
152     separation(0.0f)
153 {
154 }
155 
156 
157 vector<HipparcosStar> stars;
158 vector<HipparcosStar> companions;
159 vector<HipparcosComponent> components;
160 vector<HipparcosStar*> starIndex;
161 
162 typedef map<uint32, MultistarSystem*> MultistarSystemCatalog;
163 MultistarSystemCatalog starSystems;
164 
165 
findStar(uint32 hip)166 HipparcosStar* findStar(uint32 hip)
167 {
168     HIPCatalogComparePredicate pred;
169 
170     vector<HipparcosStar*>::iterator iter = lower_bound(starIndex.begin(),
171                                                         starIndex.end(),
172                                                         hip, pred);
173     if (iter == starIndex.end())
174         return NULL;
175     HipparcosStar* star = *iter;
176     if (star->HIPCatalogNumber == hip)
177         return star;
178     else
179         return NULL;
180 }
181 
182 
ParseStellarClass(char * starType)183 StellarClass ParseStellarClass(char *starType)
184 {
185     StellarClass::StarType type = StellarClass::NormalStar;
186     StellarClass::SpectralClass specClass = StellarClass::Spectral_A;
187     StellarClass::LuminosityClass lum = StellarClass::Lum_V;
188     unsigned short number = 5;
189     int i = 0;
190 
191     // Subdwarves (luminosity class VI) are prefixed with sd
192     if (starType[i] == 's' && starType[i + 1] == 'd')
193     {
194         lum = StellarClass::Lum_VI;
195         i += 2;
196     }
197 
198     switch (starType[i])
199     {
200     case 'O':
201         specClass = StellarClass::Spectral_O;
202         break;
203     case 'B':
204         specClass = StellarClass::Spectral_B;
205         break;
206     case 'A':
207         specClass = StellarClass::Spectral_A;
208         break;
209     case 'F':
210         specClass = StellarClass::Spectral_F;
211         break;
212     case 'G':
213         specClass = StellarClass::Spectral_G;
214         break;
215     case 'K':
216         specClass = StellarClass::Spectral_K;
217         break;
218     case 'M':
219         specClass = StellarClass::Spectral_M;
220         break;
221     case 'R':
222         specClass = StellarClass::Spectral_R;
223         break;
224     case 'N':
225         specClass = StellarClass::Spectral_S;
226         break;
227     case 'S':
228         specClass = StellarClass::Spectral_N;
229         break;
230     case 'W':
231 	i++;
232 	if (starType[i] == 'C')
233  	    specClass = StellarClass::Spectral_WC;
234 	else if (starType[i] == 'N')
235 	    specClass = StellarClass::Spectral_WN;
236 	else
237 	    i--;
238 	break;
239 
240     case 'D':
241         type = StellarClass::WhiteDwarf;
242         return StellarClass(type, specClass, 0, lum);
243 
244     default:
245         specClass = StellarClass::Spectral_Unknown;
246         break;
247     }
248 
249     i++;
250     if (starType[i] >= '0' && starType[i] <= '9')
251     {
252         number = starType[i] - '0';
253     }
254     else
255     {
256         // No number given for spectral class; assume it's a 5 unless
257         // the star is type O, as O5 stars are exceedingly rare.
258         if (specClass == StellarClass::Spectral_O)
259             number = 9;
260         else
261             number = 5;
262     }
263 
264     if (lum != StellarClass::Lum_VI)
265     {
266         i++;
267         lum = StellarClass::Lum_V;
268         while (i < 13 && starType[i] != '\0') {
269             if (starType[i] == 'I') {
270                 if (starType[i + 1] == 'I') {
271                     if (starType[i + 2] == 'I') {
272                         lum = StellarClass::Lum_III;
273                     } else {
274                         lum = StellarClass::Lum_II;
275                     }
276                 } else if (starType[i + 1] == 'V') {
277                     lum = StellarClass::Lum_IV;
278                 } else if (starType[i + 1] == 'a') {
279                     if (starType[i + 2] == '0')
280                         lum = StellarClass::Lum_Ia0;
281                     else
282                         lum = StellarClass::Lum_Ia;
283                 } else if (starType[i + 1] == 'b') {
284                     lum = StellarClass::Lum_Ib;
285                 } else {
286                     lum = StellarClass::Lum_Ib;
287                 }
288                 break;
289             } else if (starType[i] == 'V') {
290                 if (starType[i + 1] == 'I')
291                     lum = StellarClass::Lum_VI;
292                 else
293                     lum = StellarClass::Lum_V;
294                 break;
295             }
296             i++;
297         }
298     }
299 
300     return StellarClass(type, specClass, number, lum);
301 }
302 
303 
TheSun()304 HipparcosStar TheSun()
305 {
306     HipparcosStar star;
307 
308     star.HDCatalogNumber = 0;
309     star.HIPCatalogNumber = 0;
310     star.ascension = 0.0f;
311     star.declination = 0.0f;
312     star.parallax = 1000000.0f;
313     star.appMag = -15.17f;
314     star.stellarClass = StellarClass(StellarClass::NormalStar,
315                                      StellarClass::Spectral_G, 2,
316                                      StellarClass::Lum_V);
317 
318     return star;
319 }
320 
321 
ReadStarRecord(istream & in)322 bool ReadStarRecord(istream& in)
323 {
324     HipparcosStar star;
325     char buf[HipStarRecordLength];
326 
327     in.read(buf, HipStarRecordLength);
328 
329     if (sscanf(buf + 2, "%d", &star.HIPCatalogNumber) != 1)
330     {
331         cout << "Error reading catalog number.\n";
332         return false;
333     }
334 
335     sscanf(buf + 390, "%d", &star.HDCatalogNumber);
336 
337     if (sscanf(buf + 41, "%f", &star.appMag) != 1)
338     {
339         cout << "Error reading magnitude.\n";
340         return false;
341     }
342 
343     if (sscanf(buf + 79, "%f", &star.parallax) != 1)
344     {
345         // cout << "Error reading parallax.\n";
346     }
347 
348     bool coordReadError = false;
349     if (sscanf(buf + 51, "%f", &star.ascension) != 1)
350         coordReadError = true;
351     if (sscanf(buf + 64, "%f", &star.declination) != 1)
352         coordReadError = true;
353     star.ascension = (float) (star.ascension * 24.0 / 360.0);
354 
355     // Read the lower resolution coordinates in hhmmss form if we failed
356     // to read the coordinates in degrees.  Not sure why the high resolution
357     // coordinates are occasionally missing . . .
358     if (coordReadError)
359     {
360         int hh = 0;
361         int mm = 0;
362         float seconds;
363         if (sscanf(buf + 17, "%d %d %f", &hh, &mm, &seconds) != 3)
364         {
365             cout << "Error reading ascension.\n";
366             return false;
367         }
368         star.ascension = hh + (float) mm / 60.0f + (float) seconds / 3600.0f;
369 
370         char decSign;
371         int deg;
372         if (sscanf(buf + 29, "%c%d %d %f", &decSign, &deg, &mm, &seconds) != 4)
373         {
374             cout << "Error reading declination.\n";
375             return false;
376         }
377         star.declination = deg + (float) mm / 60.0f + (float) seconds / 3600.0f;
378         if (decSign == '-')
379             star.declination = -star.declination;
380     }
381 
382     char* spectralType = buf + 435;
383     spectralType[12] = '\0';
384     star.stellarClass = ParseStellarClass(spectralType);
385 
386     int asc = 0;
387     int dec = 0;
388     char decSign = ' ';
389     if (sscanf(buf + 327, "%d%c%d", &asc, &decSign, &dec) == 3)
390     {
391         if (decSign == '-')
392             dec = -dec;
393         star.CCDMIdentifier = asc << 16 | (dec & 0xffff);
394 
395         int n = 1;
396         sscanf(buf + 340, "%d", &n);
397         star.starsWithCCDM = (uint8) n;
398         sscanf(buf + 343, "%d", &n);
399         star.nComponents = (uint8) n;
400     }
401 
402     float parallaxError = 0.0f;
403     if (sscanf(buf + 119, "%f", &parallaxError) != 0)
404     {
405         if (star.parallax < 0.0f || parallaxError / star.parallax > 1.0f)
406             star.parallaxError = (int8) 255;
407         else
408             star.parallaxError = (int8) (parallaxError / star.parallax * 200);
409     }
410 
411     stars.insert(stars.end(), star);
412 
413     return true;
414 }
415 
416 
ReadComponentRecord(istream & in)417 bool ReadComponentRecord(istream& in)
418 {
419     HipparcosComponent component;
420     char buf[HipComponentRecordLength];
421 
422     in.read(buf, HipComponentRecordLength);
423 
424     uint32 hip;
425     if (sscanf(buf + 42, "%ud", &hip) != 1)
426     {
427         cout << "Missing HIP catalog number for component.\n";
428         return false;
429     }
430 
431     component.star = findStar(hip);
432     if (component.star == NULL)
433     {
434         cout << "Nonexistent HIP catalog number for component.\n";
435         return false;
436     }
437 
438     if (sscanf(buf + 40, "%c", &component.componentID) != 1)
439     {
440         cout << "Missing component identifier.\n";
441         return false;
442     }
443 
444     if (sscanf(buf + 175, "%c", &component.refComponentID) != 1)
445     {
446         cout << "Error reading reference component.\n";
447         return false;
448     }
449     if (component.refComponentID == ' ')
450         component.refComponentID = component.componentID;
451 
452     // Read astrometric information
453     if (sscanf(buf + 88, "%f", &component.ascension) != 1)
454     {
455         cout << "Missing ascension for component.\n";
456         return false;
457     }
458     component.ascension = (float) (component.ascension * 24.0 / 360.0);
459 
460     if (sscanf(buf + 101, "%f", &component.declination) != 1)
461     {
462         cout << "Missing declination for component.\n";
463         return false;
464     }
465 
466     // Read photometric information
467     if (sscanf(buf + 49, "%f", &component.appMag) != 1)
468     {
469         cout << "Missing magnitude for component.\n";
470         return false;
471     }
472 
473     // vMag and bMag may be necessary to guess the spectral type
474     if (sscanf(buf + 62, "%f", &component.bMag) != 1 ||
475         sscanf(buf + 69, "%f", &component.vMag) != 1)
476     {
477         component.bMag = component.vMag = component.appMag;
478     }
479     else
480     {
481         component.hasBV = true;
482     }
483 
484     if (component.componentID != component.refComponentID)
485     {
486         if (sscanf(buf + 177, "%f", &component.positionAngle) != 1)
487         {
488             cout << "Missing position angle for component.\n";
489             return false;
490         }
491         if (sscanf(buf + 185, "%f", &component.separation) != 1)
492         {
493             cout << "Missing separation for component.\n";
494             return false;
495         }
496     }
497 
498     components.insert(components.end(), component);
499 
500     return true;
501 };
502 
503 
BuildMultistarSystemCatalog()504 void BuildMultistarSystemCatalog()
505 {
506     for (vector<HipparcosStar>::iterator iter = stars.begin();
507          iter != stars.end(); iter++)
508     {
509         if (iter->CCDMIdentifier != NullCCDMIdentifier)
510         {
511             MultistarSystemCatalog::iterator it =
512                 starSystems.find(iter->CCDMIdentifier);
513             if (it == starSystems.end())
514             {
515                 MultistarSystem* multiSystem = new MultistarSystem();
516                 multiSystem->nStars = 1;
517                 multiSystem->stars[0] = iter;
518                 starSystems.insert(MultistarSystemCatalog::value_type(iter->CCDMIdentifier, multiSystem));
519             }
520             else
521             {
522                 MultistarSystem* multiSystem = it->second;
523                 if (multiSystem->nStars == 4)
524                 {
525                     cout << "Number of stars in system exceeds 4\n";
526                 }
527                 else
528                 {
529                     multiSystem->stars[multiSystem->nStars] = iter;
530                     multiSystem->nStars++;
531                 }
532             }
533         }
534     }
535 }
536 
537 
guessSpectralType(float colorIndex,float absMag)538 StellarClass guessSpectralType(float colorIndex, float absMag)
539 {
540     StellarClass::SpectralClass specClass = StellarClass::Spectral_Unknown;
541     float subclass = 0.0f;
542 
543     if (colorIndex < -0.25f)
544     {
545         specClass = StellarClass::Spectral_O;
546         subclass = (colorIndex + 0.5f) / 0.25f;
547     }
548     else if (colorIndex < 0.0f)
549     {
550         specClass = StellarClass::Spectral_B;
551         subclass = (colorIndex + 0.25f) / 0.25f;
552     }
553     else if (colorIndex < 0.25f)
554     {
555         specClass = StellarClass::Spectral_A;
556         subclass = (colorIndex - 0.0f) / 0.25f;
557     }
558     else if (colorIndex < 0.6f)
559     {
560         specClass = StellarClass::Spectral_F;
561         subclass = (colorIndex - 0.25f) / 0.35f;
562     }
563     else if (colorIndex < 0.85f)
564     {
565         specClass = StellarClass::Spectral_G;
566         subclass = (colorIndex - 0.6f) / 0.25f;
567     }
568     else if (colorIndex < 1.4f)
569     {
570         specClass = StellarClass::Spectral_K;
571         subclass = (colorIndex - 0.85f) / 0.55f;
572     }
573     else
574     {
575         specClass = StellarClass::Spectral_M;
576         subclass = (colorIndex - 1.4f) / 1.0f;
577     }
578 
579     if (subclass < 0.0f)
580         subclass = 0.0f;
581     else if (subclass > 1.0f)
582         subclass = 1.0f;
583 
584     return StellarClass(StellarClass::NormalStar,
585                         specClass,
586                         (unsigned int) (subclass * 9.99f),
587                         StellarClass::Lum_V);
588 }
589 
590 
ConstrainComponentParallaxes()591 void ConstrainComponentParallaxes()
592 {
593     for (MultistarSystemCatalog::iterator iter = starSystems.begin();
594          iter != starSystems.end(); iter++)
595     {
596         MultistarSystem* multiSystem = iter->second;
597         if (multiSystem->nStars > 1)
598         {
599             for (int i = 1; i < multiSystem->nStars; i++)
600                 multiSystem->stars[i]->parallax = multiSystem->stars[0]->parallax;
601         }
602 #if 0
603         if (multiSystem->nStars > 2)
604         {
605             cout << multiSystem->nStars << ": ";
606             if (multiSystem->stars[0]->HDCatalogNumber != NullCatalogNumber)
607                 cout << "HD " << multiSystem->stars[0]->HDCatalogNumber;
608             else
609                 cout << "HIP " << multiSystem->stars[0]->HIPCatalogNumber;
610             cout << '\n';
611         }
612 #endif
613     }
614 }
615 
616 
CorrectErrors()617 void CorrectErrors()
618 {
619     for (vector<HipparcosStar>::iterator iter = stars.begin();
620          iter != stars.end(); iter++)
621     {
622         // Fix the spectral class of Capella, listed for some reason
623         // as M1 in the database.
624         if (iter->HDCatalogNumber == 34029)
625         {
626             iter->stellarClass = StellarClass(StellarClass::NormalStar,
627                                               StellarClass::Spectral_G, 0,
628                                               StellarClass::Lum_III);
629         }
630     }
631 }
632 
633 
634 // Process the vector of star components and insert those that are companions
635 // of stars in the primary database into the companions vector.
CreateCompanionList()636 void CreateCompanionList()
637 {
638     for (vector<HipparcosComponent>::iterator iter = components.begin();
639          iter != components.end(); iter++)
640     {
641         // Don't insert the reference component, as this star should already
642         // be in the primary database.
643         if (iter->componentID != iter->refComponentID)
644         {
645             int componentNumber = iter->componentID - 'A';
646             if (componentNumber > 0 && componentNumber < 8)
647             {
648                 HipparcosStar star;
649 
650                 star.HDCatalogNumber = NullCatalogNumber;
651                 star.HIPCatalogNumber = iter->star->HIPCatalogNumber |
652                     (componentNumber << 25);
653 
654                 star.ascension = iter->ascension;
655                 star.declination = iter->declination;
656                 star.parallax = iter->star->parallax;
657                 star.appMag = iter->appMag;
658                 if (iter->hasBV)
659                     star.stellarClass = guessSpectralType(iter->bMag - iter->vMag, 0.0f);
660                 else
661                     star.stellarClass = StellarClass(StellarClass::NormalStar,
662                                                      StellarClass::Spectral_Unknown,
663                                                      0, StellarClass::Lum_V);
664 
665                 star.CCDMIdentifier = iter->star->CCDMIdentifier;
666                 star.parallaxError = iter->star->parallaxError;
667 
668                 companions.insert(companions.end(), star);
669             }
670         }
671     }
672 }
673 
674 
ShowStarsWithComponents()675 void ShowStarsWithComponents()
676 {
677     cout << "\nStars with >2 components\n";
678     for (vector<HipparcosStar>::iterator iter = stars.begin();
679          iter != stars.end(); iter++)
680     {
681         if (iter->nComponents > 2)
682         {
683             cout << (int) iter->nComponents << ": ";
684             if (iter->HDCatalogNumber != NullCatalogNumber)
685                 cout << "HD " << iter->HDCatalogNumber;
686             else
687                 cout << "HIP " << iter->HIPCatalogNumber;
688             cout << '\n';
689         }
690     }
691 }
692 
693 
main(int argc,char * argv[])694 int main(int argc, char* argv[])
695 {
696     assert(sizeof(StellarClass) == 2);
697 
698     // Read star records from the primary HIPPARCOS catalog
699     {
700         ifstream mainDatabase(MainDatabaseFile.c_str(), ios::in | ios::binary);
701         if (!mainDatabase.good())
702         {
703             cout << "Error opening " << MainDatabaseFile << '\n';
704             exit(1);
705         }
706 
707         cout << "Reading HIPPARCOS data set.\n";
708         while (mainDatabase.good())
709         {
710             ReadStarRecord(mainDatabase);
711             if (stars.size() % 10000 == 0)
712                 cout << stars.size() << " records.\n";
713         }
714     }
715     cout << "Read " << stars.size() << " stars from main database.\n";
716 
717     cout << "Adding the Sun...\n";
718     stars.insert(stars.end(), TheSun());
719 
720     cout << "Sorting stars...\n";
721     {
722         starIndex.reserve(stars.size());
723         for (vector<HipparcosStar>::iterator iter = stars.begin();
724              iter != stars.end(); iter++)
725         {
726             starIndex.insert(starIndex.end(), iter);
727         }
728 
729         HIPCatalogComparePredicate pred;
730 
731         // It may not even be necessary to sort the records, if the
732         // HIPPARCOS catalog is strictly ordered by catalog number.  I'm not
733         // sure about this however,
734         random_shuffle(starIndex.begin(), starIndex.end());
735         sort(starIndex.begin(), starIndex.end(), pred);
736     }
737 
738     // Read component records
739     {
740         ifstream componentDatabase(ComponentDatabaseFile.c_str(),
741                                    ios::in | ios::binary);
742         if (!componentDatabase.good())
743         {
744             cout << "Error opening " << ComponentDatabaseFile << '\n';
745             exit(1);
746         }
747 
748         cout << "Reading HIPPARCOS component database.\n";
749         while (componentDatabase.good())
750         {
751             ReadComponentRecord(componentDatabase);
752         }
753     }
754     cout << "Read " << components.size() << " components.\n";
755 
756     {
757         int aComp = 0, bComp = 0, cComp = 0, dComp = 0, eComp = 0, otherComp = 0;
758         int bvComp = 0;
759         for (int i = 0; i < components.size(); i++)
760         {
761             switch (components[i].componentID)
762             {
763             case 'A':
764                 aComp++; break;
765             case 'B':
766                 bComp++; break;
767             case 'C':
768                 cComp++; break;
769             case 'D':
770                 dComp++; break;
771             case 'E':
772                 eComp++; break;
773             default:
774                 otherComp++; break;
775             }
776             if (components[i].hasBV && components[i].componentID != 'A')
777                 bvComp++;
778         }
779 
780         cout << "A:" << aComp << "  B:" << bComp << "  C:" << cComp << "  D:" << dComp << "  E:" << eComp << '\n';
781         cout << "Components with B-V mag: " << bvComp << '\n';
782     }
783 
784     cout << "Building catalog of multiple star systems.\n";
785     BuildMultistarSystemCatalog();
786 
787     int nMultipleSystems = starSystems.size();
788     cout << "Stars in multiple star systems: " << nMultipleSystems << '\n';
789 
790     ConstrainComponentParallaxes();
791 
792     CorrectErrors();
793 
794     // CreateCompanionList();
795     cout << "Companion stars: " << companions.size() << '\n';
796     cout << "Total stars: " << stars.size() + companions.size() << '\n';
797 
798     ShowStarsWithComponents();
799 
800     char* outputFile = "stars.dat";
801     if (argc > 1)
802         outputFile = argv[1];
803 
804     cout << "Writing processed star records to " << outputFile << '\n';
805     ofstream out(outputFile, ios::out | ios::binary);
806     if (!out.good())
807     {
808         cout << "Error opening " << outputFile << '\n';
809         exit(1);
810     }
811 
812     binwrite(out, stars.size() + companions.size());
813     {
814         vector<HipparcosStar>::iterator iter;
815         for (iter = stars.begin(); iter != stars.end(); iter++)
816             iter->write(out);
817         for (iter = companions.begin(); iter != companions.end(); iter++)
818             iter->write(out);
819     }
820 
821 #if 0
822     char* hdOutputFile = "hdxref.dat";
823 
824     cout << "Writing out HD cross reference to " << hdOutputFile << '\n';
825     ofstream hdout(hdOutputFile, ios::out | ios::binary);
826     if (!out.good())
827     {
828         cout << "Error opening " << hdOutputFile << '\n';
829         exit(1);
830     }
831 
832     {
833         int nHD = 0;
834         vector<HipparcosStar>::iterator iter;
835         for (iter = stars.begin(); iter != stars.end(); iter++)
836         {
837             if (iter->HDCatalogNumber != NullCatalogNumber)
838                 nHD++;
839         }
840         binwrite(hdout, nHD);
841 
842         cout << nHD << " stars have HD numbers.\n";
843 
844         for (iter = stars.begin(); iter != stars.end(); iter++)
845         {
846             if (iter->HDCatalogNumber != NullCatalogNumber)
847             {
848                 binwrite(hdout, iter->HDCatalogNumber);
849                 binwrite(hdout, iter->HIPCatalogNumber);
850             }
851         }
852     }
853 #endif
854 
855     return 0;
856 }
857