File indexing completed on 2024-04-28 03:42:53

0001 #!/usr/bin/perl
0002 #
0003 # tycdatatomysql_pm.pl   Put star data from Tycho-1/Tycho-2 ASCII data file into a database
0004 #
0005 # CAUTION: Will truncate the table supplied!
0006 #
0007 # NOTE: The Tycho-1 text data file should be supplied via stdin:
0008 #  use  cat <tycho-1 data file> | <this script> to achieve this.
0009 #
0010 # This version of the script takes into account the proper motion of the star for J2000.0 +/- x millenia
0011 use strict;
0012 use DBI;
0013 use HTMesh;
0014 use Math::Trig;
0015 use Math::Complex;
0016 
0017 my $ERROR;
0018 my @STARS;
0019 
0020 my $VERBOSE = 0;
0021 
0022 my $cnt;
0023 
0024 # For database handling
0025 my $db_db = shift;
0026 my $db_user = shift;
0027 !($db_db eq "") and !($db_user eq "") or print "USAGE: " . $0 . " <database name> <MySQL Username> [[MySQL Password [Table [Millenia]]]\n" and exit;
0028 my $db_pass = shift;
0029 my $db_tbl = shift;
0030 my $pm_millenia = shift;
0031 ($pm_millenia eq "") and $pm_millenia = 10;
0032 if($db_tbl eq "") {
0033     $db_tbl = "tycho"
0034 }
0035 
0036 my $db_query = qq/CREATE DATABASE IF NOT EXISTS `$db_db`;/;
0037 my $db_select_query = qq/USE `$db_db`/;
0038 
0039 my $tbl_query = qq/
0040 CREATE TABLE IF NOT EXISTS `$db_tbl` (
0041   `Trixel` int NOT NULL COMMENT 'Trixel Name',
0042   `HD` int NULL COMMENT 'HD Catalog Number',
0043   `RA` double NOT NULL COMMENT 'RA Hours',
0044   `Dec` double NOT NULL COMMENT 'Declination Degrees',
0045   `dRA` double NOT NULL COMMENT 'Proper Motion along RA',
0046   `dDec` double NOT NULL COMMENT 'Proper Motion along Dec',
0047   `PM` double NOT NULL COMMENT 'Proper Motion (magnitude)',
0048   `Parallax` double NOT NULL COMMENT 'Parallax',
0049   `Mag` float NOT NULL COMMENT 'Visual Magnitude',
0050   `BV_Index` float NOT NULL COMMENT 'B-V Color Index',
0051   `Spec_Type` char(2) NOT NULL COMMENT 'Spectral Class',
0052   `Mult` tinyint(1) NOT NULL COMMENT 'Multiple?',
0053   `Var` tinyint(1) NOT NULL COMMENT 'Variable?',
0054   `Name` varchar(70) default NULL COMMENT 'Long Name',
0055   `GName` varchar(15) default NULL COMMENT 'Genetive Name',
0056   `UID` int(11) NOT NULL auto_increment COMMENT 'Unique ID',
0057   `Copies` tinyint(8) NOT NULL COMMENT 'Number of Copies of the star',
0058   PRIMARY KEY  (`UID`),
0059   UNIQUE KEY `UID` (`UID`),
0060   KEY `Trixel` (`Trixel`,`PM`,`Mag`)
0061 ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;/;
0062 
0063 my $tbl_trunc_query = qq/TRUNCATE TABLE `$db_tbl`/;
0064 
0065 # For the HTMesh
0066 my $level = 3;      # Note: If you change this, change at the TODO below as well.
0067 
0068 # Create a new HTMesh, of level $level
0069 my $mesh = new HTMesh($level);
0070 
0071 # Get the database handle
0072 my $dbh = DBI->connect("DBI:mysql:", $db_user, $db_pass, { RaiseError => 1, AutoCommit => 0 });
0073 
0074 my @fields = qw/Trixel HD RA Dec dRA dDec PM Parallax Mag BV_Index
0075     Spec_Type Mult Var GName Name Copies/;
0076 
0077 $dbh->do($db_query);
0078 $dbh->do($db_select_query);
0079 $dbh->do($tbl_query);
0080 $dbh->do($tbl_trunc_query);
0081 $dbh->commit();
0082 
0083 if( $VERBOSE ) {
0084     for( @fields ) {
0085         printf $_ . "|";
0086     }
0087     printf "\n";
0088 }
0089 
0090 while(<>) {
0091     m/^\s*#/ and do { print if $VERBOSE; next};
0092     m/\S/ or     do { print if $VERBOSE; next};
0093     chomp;
0094     my $star = kstars_unpack($_) or do {
0095         warn sprintf("%4d: FORMAT ERROR ($ERROR):\n$_\n", $.);
0096         next;
0097     };
0098     $star->{line} = $.;
0099 
0100     if( $VERBOSE ) {
0101         for(@fields) {
0102             printf $star->{$_} . "|";
0103         }
0104         printf "\n";
0105     }
0106 
0107     my ( $RA1, $Dec1 ) = proper_motion_coords( $star->{RA}, $star->{Dec}, $star->{dRA}, $star->{dDec}, -$pm_millenia * 1000 );
0108     my ( $RA2, $Dec2 ) = proper_motion_coords( $star->{RA}, $star->{Dec}, $star->{dRA}, $star->{dDec}, $pm_millenia * 1000 );
0109 
0110 #    ( $star->{PM} > 1000.0 ) and print "$RA1, $Dec1 : $star->{RA}, $star->{Dec} : $RA2, $Dec2\n";
0111 
0112     my $leftDec;
0113     my $rightDec;
0114     my $topRA;
0115     my $botRA;
0116 
0117     my $verbose = 0;
0118 #    if( $star->{HD} == "91125" ) {
0119 #        $verbose = 1;
0120 #    }
0121 #    else {
0122 #       print $star->{HD} . "\n";
0123 #    }
0124 
0125     $verbose and print "(RA1, RA2, Dec1, Dec2) = ($RA1 ,$RA2 ,$Dec1 ,$Dec2 )\n";
0126 
0127     if( $Dec1 < $Dec2 ) {
0128         $leftDec = $Dec1;
0129         $rightDec = $Dec2;
0130     }
0131     else {
0132         $leftDec = $Dec2;
0133         $rightDec = $Dec1;
0134     }
0135 
0136     if( $RA1 < $RA2 ) {
0137         $topRA = $RA1;
0138         $botRA = $RA2;
0139     }
0140     else {
0141         $topRA = $RA2;
0142         $botRA = $RA1;
0143     }
0144 
0145     $verbose and print "leftDec = $leftDec and topRA = $topRA\n";
0146 
0147     my $epsilon = ( 90.0 / 3600.0 ) / 15.0;
0148 
0149     $star->{originalTrixelID} = $mesh->lookup_id( $star->{RA}, $star->{Dec} );
0150 
0151     $verbose and print "Original trixel ID = " . $star->{originalTrixelID};
0152 
0153     my @trixels;
0154     if( $star->{Name} eq "" && $star->{GName} eq "" ) {
0155         my $separation = sqrt( hour2deg($botRA - $topRA) * hour2deg($botRA - $topRA) + ($leftDec - $rightDec) * ($leftDec - $rightDec) );
0156         if( $separation > 50.0 / 60.0 ) {
0157 #            $mesh->intersect_poly4( $botRA, $leftDec,
0158 #                                    $botRA - $epsilon, $leftDec + $epsilon,
0159 #                                    $topRA - $epsilon, $rightDec - $epsilon,
0160 #                                    $topRA, $rightDec);
0161             $mesh->intersect_poly4( $topRA, $rightDec,
0162                                     $topRA - $epsilon, $rightDec - $epsilon,
0163                                     $botRA - $epsilon, $leftDec + $epsilon,
0164                                     $botRA, $leftDec);
0165 
0166             @trixels = $mesh->results();
0167         }
0168         if( !@trixels ) {
0169            @trixels = $mesh->lookup_id( $star->{RA}, $star->{Dec} );
0170         }
0171     }
0172     else {
0173         @trixels = $mesh->lookup_id( $star->{RA}, $star->{Dec} );
0174     }
0175         
0176     for(@trixels) {
0177         my $tid = $_;
0178         $star->{Trixel} = $tid - 512; # TODO : Change if you change HTMesh level.
0179         $star->{Copies} = 0;
0180         if( $star->{originalTrixelID} == $tid ) {
0181             $star->{Copies} = @trixels;
0182         }
0183         $verbose and print "Trixel = " . $star->{Trixel} . "\n";
0184         my $query ||= qq/INSERT INTO `$db_tbl` (/ .
0185             join(", ", map {"`$_`"} @fields) .
0186             qq/) VALUES (/ .
0187             join(", ", map {"?"} @fields) .
0188             qq/)/;
0189         my $sth ||= $dbh->prepare($query);
0190         $sth->execute(@$star{@fields});
0191     }
0192         
0193 }
0194 
0195 $dbh->commit();
0196 
0197 $dbh->disconnect();
0198 
0199 exit;
0200 
0201 #----------------------------------------------------------------------------
0202 #--- Subroutines ------------------------------------------------------------
0203 #----------------------------------------------------------------------------
0204 
0205 sub kstars_unpack {
0206     my $line = shift;
0207     chomp $line;
0208 
0209     # Column number 78 demarkates between numeric data and the genetive/long names
0210     my $s1 = substr($line, 0, 80, "");
0211 
0212     # Comments on the File format:
0213     # ============================
0214     # * Most fields are of variable width
0215     # * All fields are separated by atleast one space and have a non-blank value,
0216     #   excepting the case of genetive name and long name fields
0217     #
0218     # Fields are: 
0219     # -----------
0220     # HDNum  RA Dec pmRA pmDec parallax Vmag B-V mult? var? [genetive : full]
0221     #
0222     # The regexp used here is as strict as possible on the adherence to field formats
0223     
0224     $s1 =~ m{^\s*(\d+)\s               # HD Number
0225             \s*(\d?\d\.\d{8})\s        # RA Hours
0226             \s*(-?\d?\d\.\d{8})\s      # DEC DDMMSS.SS
0227             \s*(-?\d+\.\d\d)\s         # dRA/dt 
0228             \s*(-?\d+\.\d\d)\s         # dDec/dt
0229             \s*(-?\d+\.\d[\d ])\s      # Parallax
0230             \s*([- \d]\d\.\d\d)\s      # Magnitude
0231             \s*([- ]\d.\d\d)\s         # B-V index
0232             ([01])\s                   # Multiple?
0233             ([01])\s                   # Variable?
0234             ([A-Z ].?|sd)\s            # Spectral Type
0235             }x or do 
0236         {
0237             $ERROR = "Positional Error (0-59)";
0238             return;
0239         };
0240     
0241     my $star = {
0242         HD        => $1,
0243         RA        => $2,
0244         Dec       => $3,
0245     dRA       => $4,
0246     dDec      => $5,
0247     Parallax  => $6,
0248         Mag       => $7,
0249     BV_Index  => $8,
0250         Mult      => $9,
0251     Var       => $10,
0252         Spec_Type => $11,
0253         line      => $.,
0254         PM        => sqrt($4 * $4 + $5 * $5),
0255     };
0256     
0257     $line or return $star;
0258     
0259 #    printf $line . "\n";
0260     $star->{GName} = (($line =~ s/^([^:\s].*?)(\s:|$)//) ? $1 : "");
0261     $line =~ s/^://;
0262     $star->{Name} = (($line =~ s/^\s*(\S.*?)\s*$//) ? $1 : "");
0263     return $star;
0264 }
0265 
0266 sub proper_motion_coords {
0267     my ( $ra0, $dec0, $pmRA, $pmDec, $years ) = @_;
0268 
0269     my $theta0 = hour2rad($ra0);
0270     my $lat0   = deg2rad($dec0);
0271 
0272     my $pm = sqrt( $pmRA * $pmRA + $pmDec * $pmDec ) * $years;
0273     my $dir0 = ( $pm > 0 ) ? atan2( $pmRA, $pmDec ) : atan2( -$pmRA, -$pmDec );
0274     ( $pm < 0 ) and $pm = - $pm;
0275 #    print "$pm, $dir0\n";
0276 
0277     my $dst = milliarcsecond2rad($pm);
0278 
0279     my $phi0 = pi/2 - $lat0;
0280 
0281     my $lat1   = asin(sin($lat0)*cos($dst) +
0282                       cos($lat0)*sin($dst)*cos($dir0));
0283     my $dtheta = atan2(sin($dir0)*sin($dst)*cos($lat0),
0284                        cos($dst)-sin($lat0)*sin($lat1));
0285 
0286     return (rad2hour($theta0 + $dtheta), rad2deg($lat1));
0287     #return (rad2milliarcsecond($dtheta) * cos($lat0),
0288     #        rad2milliarcsecond($lat1 - $lat0));
0289 }
0290 
0291 sub hour2rad {
0292     return deg2rad($_[0] * 15.);
0293 }
0294 
0295 sub rad2hour {
0296     return rad2deg($_[0]) / 15.;
0297 }
0298 
0299 sub milliarcsecond2rad {
0300     return deg2rad( $_[0] / ( 60 * 60 * 1000));
0301 }
0302 sub rad2milliarcsecond {
0303     return rad2deg( $_[0]) * ( 60 * 60 * 1000);
0304 }