//*********************************************************************************
// class BuildBSC5 // default package
// Software released under the General Public License (version 2 or later), available at
// http://www.gnu.org/copyleft/gpl.html
//*********************************************************************************
import java.io.*;
import java.text.*;
import java.util.Date;
/******************************************************************
Parsing and building files from BSC 5 (Bright Star Catalog, 5th edition, preliminary version).
<BR>Original files found at :
<A HREF="http://adc.gsfc.nasa.gov/cgi-bin/adc/cat.pl?/catalogs/5/5050">
http://adc.gsfc.nasa.gov/cgi-bin/adc/cat.pl?/catalogs/5/5050</A>.
<BR>To work, the file <CODE>catalog.dat</CODE> must be in the current directory.
<BR><BR>The method <CODE>build()</CODE> can be used to generate binary or text files. It is also possible to choose the fields from the original file which are stored in the generated file.
<BR>Fields that can be transformed to the original file are expressed by a letter of <CODE>FIELDS_CODE</CODE> :
<LI><B>B</B> stands for BSC number</LI>
<LI><B>H</B> stands for HD number</LI>
<LI><B>S</B> stands for SAO number</LI>
<LI><B>R</B> stands for r.a.</LI>
<LI><B>D</B> stands for dec.</LI>
<LI><B>M</B> stands for visual magnitude</LI>
<LI><B>T</B> stands for spectral type</LI>
<LI><B>P</B> stands for parallax</LI>
<BR><BR><B>WARNING</B>, there is a bug : when text files are generated, one must remove manually several characters.
@author Thierry Graff
@history mar 02 2002 : Creation
@todo try to store ra dec with floats and see if precision is lost
*****************************************************************/
public abstract class BuildBSC5{
//=================================================================================
// CONSTANTS
//=================================================================================
// parameters for 1st argument of main()
private static final String PARAM_BUILD = "build";
private static final String PARAM_TEST01 = "test01";
private static final String PARAM_TEST02 = "test02";
private static final String PARAM_TEST03 = "test03";
private static final String PARAM_TEST04 = "test04";
// parameters for build().
private static final int FORMAT_TEXT = 0;
private static final int FORMAT_BINARY = 1;
private static final int FORMAT_RAD = 2;
// Codes of the different fields to retrieve (used in arrays)
/** Code to designate BSC number (= Harvard Revised Number). */
private static final int BSC = 0;
/** Code to designate HD catalog number. */
private static final int HD = 1;
/** Code to designate SAO catalog number. */
private static final int SAO = 2;
/** Code to designate r.a. 2000. */
private static final int RA = 3;
/** Code to designate dec. 2000. */
private static final int DEC = 4;
/** Code to designate visual magnitude. */
private static final int MAG = 5;
/** Code to designate spectral type. */
private static final int TYP = 6;
/** Code to designate parallax. */
private static final int PAR = 7;
private static final int NB_OUTPUT_FIELDS = 8;
/** Codes to designate fields ; contains the letters B, H, S, R, D, M, T, P. */
public static final String[] FIELDS_CODE = {"B", "H", "S", "R", "D", "M", "T", "P"};
// limits of columns for the fields
// WARNING : for easy coding with String.substring()
// COLS[i][0] is the nb specified in readMe - 1
// COLS[i][1] is the nb specified in readMe
private static final int[][] COLS = {
{0, 4}, // BSC
{25, 31}, // HD
{31, 37}, // SAO
{75, 83}, // RA
{83, 90}, // DEC
{102, 107}, // MAG
{127, 147}, // TYP
{161, 166} // PAR
};
private final static String INPUT_FILE_NAME = "catalog.dat";
/** nb of lines in original file */
private static final int NB_LINES = 9110;
/** nb of stars (= nb of lines of files generated by build() if _onlyStars = true */
private static final int NB_STARS = 9096;
private final static String LS = System.getProperty("line.separator");
private final static String SPACE = " ";
private final static String BLANK = "";
private final static String PLUS = "+";
/** To format radian values of ra and dec. */
// precision in file : 0.1 time sec for ra ( = 7.2e-6 rad) and a arcsec for dec ( = 4.8e-6 rad);
// So 6 decimal are kept when ra and dec are stored in radians.
/////////////////// TO BE CHECKED //////////////////////
private static final DecimalFormat NF = new DecimalFormat();
static{
NF.setMaximumFractionDigits(6);
NF.setMinimumFractionDigits(6);
DecimalFormatSymbols dfs = new DecimalFormatSymbols();
dfs.setDecimalSeparator('.');
NF.setDecimalFormatSymbols(dfs);
};
//=================================================================================
// STATIC FIELDS
//=================================================================================
/** Booleans to know which fields are taken into account. */
private static boolean[] _calcField = new boolean[NB_OUTPUT_FIELDS]; // false by default
/** Booleans to know if non-star objects are output or not. */
private static boolean _onlyStars = true;
//=================================================================================
// PUBLIC METHODS
//=================================================================================
//**************** main ************************
/** Entry point to use this class.
@arg args The first parameter indicates which method will be called.
<BR>if equals to "build", build() is called.
<BR>The following arguments are passed to the called method.
*/
public static void main(String[] args){
String paramList = "'" + PARAM_BUILD + "' or '" + PARAM_TEST01 + "' or '" + PARAM_TEST02
+ "' or '" + PARAM_TEST03 + "' or '" + PARAM_TEST04 + "'";
if (args.length == 0){
System.out.println("Call to main must have at least one parameter :");
System.out.println(paramList);
System.exit(0);
}
if (args[0].compareToIgnoreCase(PARAM_BUILD) == 0){
if(args.length != 5){
System.out.println("Call to build must be done with 4 arguments :");
System.out.println("file format, data flags, ra dec format, output file name");
System.exit(0);
}
build(args[1], args[2], args[3], args[4]);
}
else if (args[0].compareToIgnoreCase(PARAM_TEST01) == 0){
if(args.length != 2){
System.out.println("Call to test01 must be done with 1 arguments : testFileName");
System.exit(0);
}
test01(args[1]);
}
else if (args[0].compareToIgnoreCase(PARAM_TEST02) == 0){
if(args.length != 3){
System.out.println("Call to test02 must be done with 2 arguments : testFileName1, testFileName2");
System.exit(0);
}
test02(args[1], args[2]);
}
else if (args[0].compareToIgnoreCase(PARAM_TEST03) == 0){
if(args.length != 3){
System.out.println("Call to test03 must be done with 2 arguments : testFileName1, testFileName2");
System.exit(0);
}
test03(args[1], args[2]);
}
else if(args[0].compareToIgnoreCase(PARAM_TEST04) == 0){
if(args.length != 3){
System.out.println("Call to test04 must be done with 2 arguments : testFileName1, testFileName2");
System.exit(0);
}
test04(args[1], args[2]);
}
else{
System.out.println("First parameter must be :");
System.out.println(paramList);
}
}// end main
//**************** build() ************************
/** Method used to extract some fields from 'catalog.dat'.
<BR>Note : text fields are output with a fixed length ; space are added if necessary.
@param strFileFormat Indicates the output file format. Must be "TEXT" or "BINARY".
@param strDataFlags Indicates which fields will be in the output file.
Must be a combination of letters contained in <CODE>FIELDS_CODE</CODE>.
@param strRaDecFormat Indicates how to output ra and dec. Can be :
<LI>"TEXT" (output is done in standard format : HHMMSS for ra and sDDDMMSS.S for dec) ;</LI>
<!-- <LI>"DEG" (output is numeric, in decimal degrees) ;</LI> -->
<LI>"RAD" (output is numeric, in radians, with 7 decimals)</LI>
*/
public static void build(String strFileFormat, String strDataFlags,
String strRaDecFormat, String strOutputFileName){
int i; // used several times
// 1 - Parameter checking
int fileFormat;
if(strFileFormat.equalsIgnoreCase("text")) fileFormat = FORMAT_TEXT;
else if(strFileFormat.equalsIgnoreCase("binary")) fileFormat = FORMAT_BINARY;
else throw new IllegalArgumentException("parameter 'strFileFormat' must be 'text' or 'binary'");
// Get the fields to output
for (i = 0; i < NB_OUTPUT_FIELDS; i++){
if (strDataFlags.indexOf(FIELDS_CODE[i]) >= 0)
_calcField[i] = true;
}
int raDecFormat;
if (strRaDecFormat.equalsIgnoreCase("text")) raDecFormat = FORMAT_TEXT;
else if (strRaDecFormat.equalsIgnoreCase("rad")) raDecFormat = FORMAT_RAD;
else throw new IllegalArgumentException("parameter 'strRaDecFormat' must be 'text' or 'rad'");
// 2 - Loop on input file
try{
FileOutputStream fos = new FileOutputStream(new File(strOutputFileName));
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(INPUT_FILE_NAME)));
ObjectOutputStream oos = new ObjectOutputStream(fos);
int n = 0; // nb of output lines
String line;
StringBuffer strRes = new StringBuffer(BLANK);
double tmp = 0;
String strField; // used for text output format
// Main loop
for(int iLine = 0; iLine < NB_LINES; iLine++){
line = lnr.readLine();
// first check if it's a star - for non-star object, the line has no ra dec
if(_onlyStars && line.substring(COLS[RA][0], COLS[RA][1]).trim().length() ==0) continue;
n++; //System.out.println(n);
// loop on fields to output
for(i = 0; i < NB_OUTPUT_FIELDS; i++){
// for (i = 0; i < 10; i++){
if(_calcField[i]){
switch(i){
case RA :
if(raDecFormat == FORMAT_RAD){
tmp = getRa(line.substring(COLS[i][0], COLS[i][1]));
strField = NF.format(tmp);
}
else
strField = line.substring(COLS[i][0], COLS[i][1]);
break;
case DEC :
if(raDecFormat == FORMAT_RAD){
tmp = getDec(line.substring(COLS[i][0], COLS[i][1]));
strField = NF.format(tmp);
strField = (tmp > 0 ? PLUS : BLANK) + strField; // add '+' for > 0 results
}
else
strField = line.substring(COLS[i][0], COLS[i][1]);
break;
case PAR : // some stars don't have parallax
try{strField = line.substring(COLS[i][0], COLS[i][1]);}
catch(Exception e){strField = " ";}
break;
default :
strField = line.substring(COLS[i][0], COLS[i][1]);
}// end switch
// Write the field in the output
if(fileFormat == FORMAT_TEXT) strRes.append(strField);
else{ // BINARY
if ((i == RA || i == DEC) && raDecFormat == FORMAT_RAD)
oos.writeDouble(tmp);
else
oos.writeObject(strField);
}
}// end if(_calcField[i])
}// end loop on fields to output
strRes.append(LS);
}// end main loop
System.out.println(n + " lines in the output file");
if (fileFormat == FORMAT_TEXT) fos.write(strRes.toString().getBytes());
oos.close();
fos.close();
}
catch(Exception e){
e.printStackTrace();
}
}// end build()
//*************************************************
/** To test if binary values can be retrieved when the file contains both doubles and Strings
(test for a binary file containing BSC number, ra, dec). */
// result of test : OK, possible to retrieve correctly.
public static void test01(String strInputFile){
try{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(strInputFile)));
for (int i = 0; i < 5; i++){
String bsc = (String)ois.readObject();
double ra = ois.readDouble();
double dec = ois.readDouble();
System.out.println("====== " + i + " ======");
System.out.println("BSC : " + bsc);
System.out.println("ra : " + ra);
System.out.println("dec : " + dec);
}
ois.close();
}catch (Exception e){ e.printStackTrace(); }
}// end test01
//*************************************************
/** To test execution time between text and binary versions for ra / dec in radians.
@param testFile1 : a binary file containing ra dec expressed in radians
@param testFile2 : a text file containing ra dec expressed in radians
*/
public static void test02(String testFile1, String testFile2){
try{
Date startTest1, endTest1;
Date startTest2, endTest2;
long duration1, duration2;
int i, j;
// test binary
System.out.println("read binary...");
double ra, dec;
startTest1 = new Date();
for (j = 0; j < 10; j++){
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(testFile1)));
for (i = 0; i < NB_STARS; i++){
ra = ois.readDouble();
dec = ois.readDouble();
}
ois.close();
ois = null;
}
endTest1 = new Date();
duration1 = endTest1.getTime() - startTest1.getTime();
// test text
System.out.println("read text...");
String strRa, strDec;
String line;
startTest2 = new Date();
for (j = 0; j < 10; j++){
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(testFile2)));
for (i = 0; i < NB_STARS; i++){
//for (int i = 0; i < 2; i++){
line = lnr.readLine();
ra = Double.parseDouble(line.substring(0, 9));
//System.out.println("ra : " + ra);
dec = Double.parseDouble(line.substring(9));
//System.out.println("dec : " + dec);
}
lnr.close();
lnr = null;
}
endTest2 = new Date();
duration2 = endTest2.getTime() - startTest2.getTime();
System.out.println("time for binary : " + duration1); // result = 63
System.out.println("time for text : " + duration2); // result = 328
// COMMENTS ON THE RESULTS :
// A first execution without loops on j were giving binary = 0 and text = 94.
// So in 63 and 328, a large part of the time can be taken to build the streams.
}catch (Exception e){ e.printStackTrace(); }
}// end test02
//*************************************************
/** To test execution time between text and binary versions for ra / dec in text format.
@param testFile1 : a binary file containing ra dec expressed in text format
@param testFile2 : a text file containing ra dec expressed in text format
*/
public static void test03(String testFile1, String testFile2){
try{
Date startTest1, endTest1;
Date startTest2, endTest2;
long duration1, duration2;
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(testFile1)));
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(testFile2)));
String strRa, strDec;
int i;
// test binary
System.out.println("read binary...");
startTest1 = new Date();
for (i = 0; i < NB_STARS; i++){
//for (i = 0; i < 2; i++){
strRa = (String)ois.readObject();
//System.out.println("strRa : " + strRa);
strDec = (String)ois.readObject();
//System.out.println("strDec : " + strDec);
}
endTest1 = new Date();
duration1 = endTest1.getTime() - startTest1.getTime();
// test text
System.out.println("read text...");
String line;
startTest2 = new Date();
for (i = 0; i < NB_STARS; i++){
//for (i = 0; i < 2; i++){
line = lnr.readLine();
strRa = line.substring(0, 8);
//System.out.println("strRa : " + strRa);
strDec = line.substring(8);
//System.out.println("strDec : " + strDec);
}
endTest2 = new Date();
duration2 = endTest2.getTime() - startTest2.getTime();
ois.close();
lnr.close();
System.out.println("time for binary : " + duration1); // res = 203
System.out.println("time for text : " + duration2); // res = 47
}catch (Exception e){ e.printStackTrace(); }
}// end test03
//*************************************************
/** To test execution time as it will be used in JEphem :
<LI>get ra and dec as doubles, and the other fields as Strings.</LI>
- between text and binary versions for files containing all fields (ra / dec in RAD format).
@param testFile1 : a binary file containing all the fields
@param testFile2 : a text file containing all the fields
*/
public static void test04(String testFile1, String testFile2){
try{
Date startTest1, endTest1;
Date startTest2, endTest2;
long duration1, duration2;
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(testFile1)));
LineNumberReader lnr = new LineNumberReader(new FileReader(new File(testFile2)));
String strBSC, strHD, strSAO, strMag, strTyp, strPar;
double ra, dec;
int i;
// test binary
System.out.println("read binary...");
startTest1 = new Date();
for (i = 0; i < NB_STARS; i++){
//for (i = 0; i < 4; i++){
strBSC = (String)ois.readObject();
//System.out.println("strBSC : " + strBSC);
strHD = (String)ois.readObject();
strSAO = (String)ois.readObject();
ra = ois.readDouble();
dec = ois.readDouble();
strMag = (String)ois.readObject();
strTyp = (String)ois.readObject();
strPar = (String)ois.readObject();
//System.out.println("strPar : " + strPar);
}
endTest1 = new Date();
duration1 = endTest1.getTime() - startTest1.getTime();
// test text
System.out.println("read text...");
String line;
startTest2 = new Date();
for (i = 0; i < NB_STARS; i++){
//for (i = 0; i < 2; i++){
line = lnr.readLine();
strBSC = line.substring(0, 4);
strHD = line.substring(4, 10);
strSAO = line.substring(10, 16);
ra = Double.parseDouble(line.substring(16, 24));
dec = Double.parseDouble(line.substring(24, 33));
strMag = line.substring(33, 38);
strTyp = line.substring(38, 58);
strPar = line.substring(58);
}
endTest2 = new Date();
duration2 = endTest2.getTime() - startTest2.getTime();
ois.close();
lnr.close();
System.out.println("time for binary : " + duration1); // res = 203
System.out.println("time for text : " + duration2); // res = 47
}catch (Exception e){ e.printStackTrace(); }
}// end test04
//=================================================================================
// PRIVATE METHODS
//=================================================================================
//*************************************************
/** Auxiliary method which converts ra from input file to <B>radians</B>.
@param str Contains the ra as formatted in the input file : HHMMSS.S
*/
private static double getRa(String str){
try{
double hours = Double.parseDouble(str.substring(0,2));
// System.out.println("ra - parsed hours : " + hours);
double minuts = Double.parseDouble(str.substring(2,4))/60.0; // convert minuts to decimal hours
// System.out.println("ra - parsed minuts : " + minuts);
double seconds = Double.parseDouble(str.substring(4))/3600.0; // convert seconds to decimal hours
// System.out.println("ra - parsed seconds : " + seconds);
double res = hours + minuts + seconds;
res *= 15.0; // convert to degrees
return Math.toRadians(res);
}catch (NumberFormatException nfe){
System.out.println("getRa - Unable to parse '" + str + "'");
return 0.0;
}
}// end getRa
//*************************************************
/** Auxiliary method which converts dec from input file format to <B>radians</B>.
@param str Contains the dec as formatted in the input file : sDDMMSS (s = sign).
*/
private static double getDec(String str){
try{
double deg = Double.parseDouble(str.substring(0,3));
// System.out.println("dec - parsed deg : " + deg);
double minuts = Double.parseDouble(str.substring(3,5))/60.0; // convert minuts to decimal degrees
// System.out.println("dec - parsed minuts " + minuts);
double seconds = Double.parseDouble(str.substring(5))/3600.0; // convert seconds to decimal degrees
// System.out.println("dec - parsed seconds " + seconds);
double res = deg + minuts + seconds;
return Math.toRadians(res);
}catch (NumberFormatException nfe){
System.out.println("getDec - Unable to parse '" + str + "'");
return 0.0;
}
}// end getDec
}//end class BuildBSC5