#!/usr/bin/perl ############################################################################### # PERL script to search in a general way through the 2QZ catalogue. # This is the command line version, which has been modifed from the WWW/CGI # version. # # Written by S.M. Croom & R.J. Smith 6/2/01 # # SMC 22/02/01 (v1.1) # # RJS 22/02/01 (v1.2) # Many changes, principally to produce prettified HTML output results. # Added maxrows to %allkeywords array. # Changed file name to cat_search_www.cgi so it can be called as # a cgi-bin from the CGIservlet-1.2.pl mini server. # # SMC 24/02/01 (v1.3) # fixed problem with zero (0) entries in boxes. # U/R min and max now supported # ra min/max wrap around at RA=0h now works # # RJS 28/02/01 (v1.4) # Changed name back to cat_search_www.pl. Sorry! # Web page now calls searcher.cgi. I think this means that the only # paths we are dependent on are /bin/sh and that the user has # `perl' in their search PATH, since we call both Servelet and # cat_search_www.pl via `perl **********.pl' # Added explicit printf for better formatting # -ve decs are now printed out as -ve # Swapped ID and redshift columns in output table # # SMC 08/03/01 (v1.5) # Now checks for limits of the 2QZ survey areas when doing RA,Dec search # Search in r mag fixed to include proper upper limits (not upper limits+10) # # RJS 09/03/01 (v1.6) # Taking advantage of SMC's addition of writing search results in # /tmp/2QZ.out, I have written out 2QZ.out.html as a replacement # for the old allpub.cat.html containing only requested objects. # It is therefore MUCH faster to load. These are linked from the # CAT column in results table. # Added `Observation 2' to the results table. # Reformatted results table header slightly in line with WWW # version. # # SMC 12/06/02 (v1.7) # Added a search keyword for object name. This can be a string which # is contained within either the catalogue or IAU name of the object. The # new keyword is called "name". # # SMC 23/08/02 (v1.8) # Fixed problem when the object name was passed as "2QZ J012526.7-313341". # The 2QZ is removed, as are any leading or trailing blanks. # # SMC 08/11/02 (v1.9) # Fixed problem with "+" (which is a meta-character in perl regular # expressions) in the name of objects, so that searching on the name # e.g. J131858.7+003051 works. # # SMC 11/06/03 (v2.0) # Fixed bug with quality search (found by BJB) # ################################################################################ # # # LICENCE # # # # 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. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program; if not, write to the Free Software # # Foundation, Inc., 59 Temple Place - Suite 330, # # Boston, MA 02111-1307, USA. # # # ################################################################################ # # version control: $version=2.0; print "cat_search.pl version $version\n\n"; # # CGI stuff to accept form input: # # define a hash of all allowable keywords %allkeywords = (bmin,bmin,bmax,bmax,ubmin,ubmin,ubmax,ubmax,brmin,brmin,brmax,brmax); %allkeywords = (ramin,ramin,ramax,ramax,decmin,decmin,decmax,decmax,%allkeywords); %allkeywords = (ra,ra,dec,dec,radius,radius,umin,umin,umax,umax,%allkeywords); %allkeywords = (zmin,zmin,zmax,zmax,qualmin,qualmin,qualmax,qualmax,%allkeywords); %allkeywords = (snmin,snmin,snmax,snmax,id,id,rmin,rmin,rmax,rmax,%allkeywords); %allkeywords = (maxrows,maxrows,subid,subid,postype,postype,name,name,%allkeywords); # define position keywords: %poskeywords = (ramin,ramin,ramax,ramax,decmin,decmin,decmax,decmax,ra,ra,dec,dec); # set a few useful parameters: $pi=atan2(1,1)*4; $dtor=$pi/180.0; # # get the keywords from the command line: if ( scalar(@ARGV) == 0 ) { print "Usage: cat_search.pl ...\n"; print "or: cat_search.pl -h for more help\n"; exit(10); } elsif ($ARGV[0] eq "-h") { help(); exit(11); } else { @inlist = @ARGV; $inlistnumber = scalar(@ARGV); } # figure out constraints: $catfile=$ARGV[0]; $outfile=$ARGV[1]; print "catalogue file : $catfile\n"; print "input constraints:\n"; $ncont=0; $i=2; $nval=0; $nkey=0; while ($i < $inlistnumber) { if ($ARGV[$i] =~ /=/) { # split up the entry if there is an equals sign @tmp=split(/=/,$ARGV[$i]); $data{$tmp[0]}=$tmp[1]; $keyword=$tmp[0]; $i++; } else { $data{$keyword}=$data{$keyword}." ".$ARGV[$i]; $i++; } } # Now extract only those keywords which match with the search keywords: while (($key, $val) = each %data) { if ( $val =~ /\w/ && $allkeywords{$key}) { $val =~ s/^\s+//; # remove leading whitespaces $val =~ s/\s+$//; # remove trailing whitespaces if ($key =~ /id/ && $val =~ /Any/) { # if any IDs don't use this keyword next; } $value{$key}=$val; $keywords{$key}=$key; print "$key: $val\n"; } } # find out which RA/Dec search mechanism is used and remove any other # elements from the hash of constraints: if ($value{postype} =~ /radius/) { delete $value{ramin}; delete $value{ramax}; delete $value{decmin}; delete $value{decmax}; delete $keywords{ramin}; delete $keywords{ramax}; delete $keywords{decmin}; delete $keywords{decmax}; } elsif ($value{postype} =~ /minmax/) { delete $value{ra}; delete $value{dec}; delete $value{radius}; delete $keywords{ra}; delete $keywords{dec}; delete $keywords{radius}; } delete $value{postype}; delete $keyword{postype}; # Do checks on the values of the constraints that have been input. # All but ID and name require only numerical input: foreach $keywd (keys %value) { if ($keywd =~ /name/) { # if the keyword is "name" remove 2QZ and all blanks, and fix up + signs: $value{$keywd} =~ s/2QZ//g; $value{$keywd} =~ s/\s//g; $value{$keywd} =~ s/\+/\\\+/g; } @tmp=split(/\s+/,$value{$keywd}); # first check if there is just one element in the string $nelement=$#tmp; if ($nelement > 2) { print "ERROR: input value for $keywd is invalid\n"; exit(99); } if ($nelement > 0) { if ($keywd !~ /ra/ && $keywd !~ /dec/) { print "ERROR: input value for $keywd is invalid\n"; exit(98); } } if ($keywd =~ /id/) { if ($value{$keywd} !~ /^([a-zA-Z])*(\?{0,2})$/ ) { # check for a valid string print "ERROR: input value for $keywd is invalid: $value{$keywd}\n"; exit(97); } if ($value{$keywd} =~ /noid/) { $value{$keywd}='\?\?'; } } elsif ($keywd !~ /name/) { foreach $val (@tmp) { if ($val !~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?$/ ) { # checks for a number print "ERROR: input value for $keywd is invalid\n"; exit(96); } } } } # If the ramin, ramax, decmin, decmax keywords are set then convert to # radians (uses set_ra() and set_dec()): if ($keywords{ramin}) { @tmp=split(/\s+/,$value{ramin}); $value{ramin}=set_ra(@tmp); } if ($keywords{ramax}) { @tmp=split(/\s+/,$value{ramax}); $value{ramax}=set_ra(@tmp); } if ($keywords{decmin}) { @tmp=split(/\s+/,$value{decmin}); $value{decmin}=set_dec(@tmp); } if ($keywords{decmax} =~ /decmax/) { @tmp=split(/\s+/,$value{decmax}); $value{decmax}=set_dec(@tmp); } # find out whether we have both min and max RA limits: $raminmax=0; if ($keywords{ramax} && $keywords{ramin}) { if ($value{ramin} < $value{ramax}) { $raminmax=1; # normal min < max } else { $raminmax=2; # min > max, so wrap around RA=0h } } # open an output file in to put the catalogue file: open (OUT, "> ".$outfile); # if the ra,dec,radius keywords are used they need to be all used # so check to make sure that they are and convert the values to radians for # use later on (call to set_ra() and set_dec() made to check whether the # input was in radians or hh mm ss format). Also check that the coordinates # input are within the 2QZ survey area: $nrmin=2.5842; $nrmax=3.8851; $ndmin=-0.0522; $ndmax=0.0357; $srmin=5.6827; # these take care of the RA=0h $srmax=0.8623; # wrap around $sdmin=-0.5637; $sdmax=-0.4751; if ( $keywords{ra} || $keywords{dec} || $keywords{radius}) { if ($keywords{ra} !~ /ra/ || $keywords{dec} !~ /dec/ || $keywords{radius} !~ /radius/){ print "\nERROR: for a search around a position all 3 keywords required:\n"; print " ra, dec, radius\n"; exit(12); } else { @tmp=split(/\s+/,$value{ra}); $racent=set_ra(@tmp); @tmp=split(/\s+/,$value{dec}); $deccent=set_dec(@tmp); # if the search position is outside the 2QZ region flag the error. The limits are # approximate (as the actual survey limits are defined in B1950): unless (($racent > $nrmin && $racent < $nrmax && $deccent < 0.0357 && $deccent >$ndmin ) || (($deccent < $sdmax && $deccent > $sdmin) && ($racent > $srmin || $racent < $srmax))) { print "\nERROR: coordinates outside of 2QZ survey range\nApprox. 9h 50m -- 14h 50m, -2.5deg -- +2.5deg\n And 21h 40m -- 3h 20m, -32.5deg -- -27.5deg\n"; exit(13); } $radius=$value{radius}; $radius=$radius*$dtor/60.0; $racentplus=$racent+2*$pi; # ra centre + 360 deg for RA=0 overlap $racentminus=$racent-2*$pi; # ra centre - 360 deg for RA=24 overlap $raposextent=$racent+$radius*cos($deccent); $ranegextent=$racent-$radius*cos($deccent); $poswrap=0; $negwrap=0; if ($raposextent > 2*$pi) { # see if the search area cuts across 24h $poswrap=1; } if ($ranegextent < 0) { # see if the search area cuts across 0h $negwrap=1; } $centresearch=1; } } #------------------------------------------------------------------------------ # All the checks and setup stuff are now done so open the catalogue file and # read in the entries. The catalogue MUST be set up so that the best ID # is placed in ID_1. open ( CAT , $catfile ) or die "can\'t open catalogue file\n"; $nlines=0; while ( $line = ) { chomp($line); $lines[$nlines]=$line; $nlines++; } close(CAT); # Now for the real grunt work... scan through the catalogue entries and find # the objects which match the selection criteria, writing the selected objects # to the output file: $nselected=0; for ($i=0; $i<$nlines; $i++) { # if (substr($lines[$i],1,3) eq "2QZ") { # rlinepub($lines[$i]); # this for the old 10k public release catalogue file # $racat=$raradj; # $deccat=$decradj; # } # else { rlinefast($lines[$i]); # this is a standard catalogue file $racat=($ra1j+$ra2j/60.0+$ra3j/3600.0)*15.0*$dtor; $deccat=$dsignj*($dec1j+$dec2j/60.0+$dec3j/3600.0)*$dtor; # } $test=1; # selected object: test=1; unselected object: test=0 foreach $keywd (keys %value) { # loop over all the keywords if ($test == 0) { last; # if $test=0 then give up with this object } # check for an object name: if ($keywd eq "name") { $test1=string_check($iauname,$value{name}); $test2=string_check($catname,$value{name}); if ($test1 == 0 && $test2 == 0) {$test=0;} } # checks for magnitude and colour ranges: elsif ($keywd eq "bmin") { $test=min_check($b,$value{bmin}); } elsif ($keywd eq "bmax") { $test=max_check($b,$value{bmax}); } elsif ($keywd eq "umin") { $test=min_check($ub+$b,$value{umin}); } elsif ($keywd eq "umax") { $test=max_check($ub+$b,$value{umax}); } elsif ($keywd eq "rmin") { $r=$b-$br; if ($br < -5) { # get proper upper limit r mags $r=$r-10.0; } $test=min_check($r,$value{rmin}); } elsif ($keywd eq "rmax") { $r=$b-$br; if ($br < -5) { # get proper upper limit r mags $r=$r-10.0; } $test=max_check($r,$value{rmax}); } elsif ($keywd eq "ubmin") { $test=min_check($ub,$value{ubmin}); } elsif ($keywd eq "ubmax") { $test=max_check($ub,$value{ubmax}); } elsif ($keywd eq "brmin") { $test=min_check($br,$value{brmin}); } elsif ($keywd eq "brmax") { $test=max_check($br,$value{brmax}); } # check for redshift, quality and ID: elsif ($keywd eq "zmin") { $test=min_check($z1,$value{zmin}); } elsif ($keywd eq "zmax") { $test=max_check($z1,$value{zmax}); } elsif ($keywd eq "qualmin") { $test=min_check($zq1,$value{qualmin}); } elsif ($keywd eq "qualmax") { $test=max_check($zq1,$value{qualmin}); } elsif ($keywd eq "id") { $test=string_check($id1,$value{id}); } elsif ($keywd eq "subid") { $test=string_check($id1,$value{subid}); } elsif ($keywd eq "snmin") { $test=min_check($sn1,$value{snmin}); } elsif ($keywd eq "snmax") { $test=max_check($sn1,$value{snmax}); } # check for positional limits: elsif ($keywd eq "decmin") { $test=min_check($deccat,$value{decmin}); } elsif ($keywd eq "decmax") { $test=max_check($deccat,$value{decmax}); } # need to do something clever here. If only one of ramin and ramax # is specified then do the normal min/max checking. But if both # are specified then we need to do some checks for the RA=0h wrap # around elsif ($keywd eq "ramin" && $raminmax == 0) { $test=min_check($racat,$value{ramin}); } elsif ($keywd eq "ramax" && $raminmax == 0) { $test=max_check($racat,$value{ramax}); } } # do RA min/max test: if ($test == 1) { if ($raminmax == 1){ # this is a normal min/max test if ($racat < $value{ramin} || $racat > $value{ramax}) { $test=0; } } if ($raminmax == 2) { # this the RA=0h wrap case if ($racat > $value{ramax} && $racat < $value{ramin}) { $test=0; } } } # do a search around a central position. In some cases this has to be done # more than once because of the RA=0h wrap around. This is the most time # intensive bit of the searching so only so this when everything else is done: if ($centresearch == 1 && $test == 1) { $postest1=0; $postest2=0; $postest3=0; $postest1=position_check($racat,$deccat,$racent,$deccent,$radius); if ($poswrap == 1) { # check for wrap around 24h $postest2=position_check($racat,$deccat,$racentminus,$deccent,$radius); } if ($negwrap == 1) { # check for wrap around 0h $postest3=position_check($racat,$deccat,$racentplus,$deccent,$radius); } if ($postest1 == 1 || $postest2 == 1 || $postest3 == 1) { $test=1; } else { $test=0; } } # finally print the selected lines: if ($test == 1) { print OUT "$lines[$i]\n"; # write to catalogue file $linetest[$i]=1; $nselected++; } } close(OUT); print "$nselected objects selected and written to $outfile\n"; exit(0); ############################################################################### ############################################################################### # subroutines... ############################################################################### # subroutine to print out help information: sub help { print "CAT_SEARCH.PL HELP\n"; print "------------------\n"; print "This script does a generalized search through the 2QZ catalogue\n"; print "The syntax used in the following:\n\n"; print "cat_search.pl ...\n\n"; print "the constraints all take the form:\n\n"; print "=\n\n"; print "currently useable keywords are:\n\n"; print "keyword | definition\n"; print "----------------------------------------------------\n"; print "name | sub-string within either the IAU or catalogue name\n"; print "----------------------------------------------------\n"; print "bmin | minimum (bright) bj magnitude\n"; print "bmax | maximum (faint) bj magnitude\n"; print "umin | minimum (bright) u magnitude\n"; print "umax | maximum (faint) u magnitude\n"; print "rmin | minimum (bright) r magnitude\n"; print "rmax | maximum (faint) r magnitude\n"; print "ubmin | minimum (blue) u-bj magnitude\n"; print "ubmax | maximum (red) u-bj magnitude\n"; print "brmin | minimum (blue) bj-r magnitude\n"; print "brmax | maximum (red) bj-r magnitude\n"; print "----------------------------------------------------\n"; print "ramin | minimum ra (hh mm ss or decimal degrees)\n"; print "ramax | maximum ra (hh mm ss or decimal degrees)\n"; print "decmin | minimum dec (+-dd mm ss or decimal degrees)\n"; print "decmax | maximum dec (+-dd mm ss or decimal degrees)\n"; print "----------------------------------------------------\n"; print "zmin | minimum redshift\n"; print "zmax | maximum redshift\n"; print "qualmin | minimum quality flag value (>=11)\n"; print "qualmax | maximum quality flag value (<=33)\n"; print "id | string to search IDs for\n"; print "snmin | minimum signal-to-noise\n"; print "snmax | maximum signal-to-noise\n"; # print "comment | string to find in comments\n"; print "----------------------------------------------------\n"; print "ra | centre of search region (hh mm ss or degrees) )\n"; print "dec | centre of search region (+-dd mm ss or degrees) ) must be used\n"; print "radius | search radius in arcminutes ) together\n"; print "----------------------------------------------------\n"; print "\n"; print "\n"; print "positional arguments:\n"; print "These can be given in the standard (hh mm ss.s) type of format, or can be\n"; print "given in decimal degrees (NOT decimal radians). The search radius is always\n"; print "in arcminutes\n\n"; print "A simple example:\n"; print "cat_search.pl sgp.cat out.cat bmin=20.5 bmax=20.0\n"; print "This example will find all objects in the range 20= $_[1]) { return 1; } else { return 0; } } ############################################################################### # subroutine to check if an object is selected below an abitrary maximum value sub max_check { if ($_[0] <= $_[1]) { return 1; } else { return 0; } } ############################################################################### # subroutine to check if an object is less than a set distance # away from a point in ra,dec space. Coordinates specified in # radians, and the small angle approximation is used. Usage: # position check ( ra, dec, ra_cent, dec_cent, radius) sub position_check { my $diff = (($_[0]-$_[2])**2*cos($_[1])*cos($_[3])+($_[1]-$_[3])**2)**0.5; if ($diff <= $_[4]) { return 1; } else { return 0; } } ############################################################################### # subroutine to check is an object contains a string: sub string_check { if ($_[0] =~ $_[1]) { return 1; } else { return 0; } } ############################################################################### # subroutine to read a catalogue entry in the format of the old 10k public 2QZ # catalogue. Now obselete, but included here for backwards compatability. sub rlinepub { ($dum,$iauname,$ra1j,$ra2j,$ra3j,$dec1j,$dec2j,$dec3j,$raradj,$decradj,$b,$ub,$br,$nobs,$z1,$zq1,$id1,$date1,$fobs1,$sn1,$z2,$zq2,$id2,$date2,$fobs2,$sn2,$zprev,$radio,$xray,$dust)=split(/\s+/,$_[0]); # set up checks for declination sign: if ($dec1j =~ /-/) { $dsignj=-1; $dsigncharj="-"; } else { $dsignj=1.0; $dsigncharj="+"; } # remove signs (-/+) from declination: $dec1j=~s/-//; $dec1j=~s/\+//; return; } ############################################################################### # A quick version of the rline routine using unpack. This uses an extact # description of the catalogue file format so is less flexible (need to be # careful of minor catalogue format changes) but about twice as quick:: # sub rlinefast { # define the format: my $lineform="a16xa2xa2xa5xa1a2xa2xa4xa5xa10xa25xa2xa2xa5xa1a2xa2xa4xa3xa9xa9xa11xa11xxxxa6xxxa7xxxa7xxxa1xa6xa2xa10xa8xa4xa3xa7xa6xa2xa10xa8xa4xa3xa7xa5xa6xa7xa7xa20xa20"; # do the unpacking: ($iauname,$ra1j,$ra2j,$ra3j,$dsigncharj,$dec1j,$dec2j,$dec3j,$catno,$catname,$sector,$ra1,$ra2,$ra3,$dsignchar,$dec1,$dec2,$dec3,$ukstfld,$apmx,$apmy,$rarad,$decrad,$b,$ub,$br,$nobs,$z1,$zq1,$id1,$date1,$fobs1,$fibre1,$sn1,$z2,$zq2,$id2,$date2,$fobs2,$fibre2,$sn2,$zprev,$radio,$xray,$dust,$comment1,$comment2)=unpack($lineform,$_[0]); # do declination sigh stuff: $dsign=1; if ($dsignchar =~ /-/) {$dsign=-1;} $dsignj=1; if ($dsigncharj =~ /-/) {$dsignj=-1;} return; } ############################################################################### # subroutine to read the catalogue entries in a standard format 2QZ catalogue # file sub rline { my @tmp=split(/\s+/," ".$_[0]); $iauname=$tmp[1]; $ra1j=$tmp[2]; $ra2j=$tmp[3]; $ra3j=$tmp[4]; $dec1j=$tmp[5]; $dec2j=$tmp[6]; $dec3j=$tmp[7]; $catno=$tmp[8]; $catname=$tmp[9]; $sector=$tmp[10]; $ra1=$tmp[11]; $ra2=$tmp[12]; $ra3=$tmp[13]; $dec1=$tmp[14]; $dec2=$tmp[15]; $dec3=$tmp[16]; $ukstfld=$tmp[17]; $apmx=$tmp[18]; $apmy=$tmp[19]; $rarad=$tmp[20]; $decrad=$tmp[21]; $b=$tmp[22]; $ub=$tmp[23]; $br=$tmp[24]; $nobs=$tmp[25]; $z1=$tmp[26]; $zq1=$tmp[27]; $id1=$tmp[28]; $date1=$tmp[29]; $fobs1=$tmp[30]; $fibre1=$tmp[31]; $sn1=$tmp[32]; $z2=$tmp[33]; $zq2=$tmp[34]; $id2=$tmp[35]; $date2=$tmp[36]; $fobs2=$tmp[37]; $fibre2=$tmp[38]; $sn2=$tmp[39]; $zprev=$tmp[40]; $radio=$tmp[41]; $xray=$tmp[42]; $dust=$tmp[43]; $comment1=$tmp[44]; $comment2=$tmp[45]; # set up checks for declination sign: $dsign=1.0; $dsignchar="+"; if ($dec1 =~ /-/) { $dsign=-1; $dsignchar="-"; } $dsignj=1.0; $dsigncharj="+"; if ($dec1j =~ /-/) { $dsignj=-1; $dsigncharj="-"; } # remove signs (-/+) from declination: $dec1=~s/-//; $dec1=~s/\+//; $dec1j=~s/-//; $dec1j=~s/\+//; return; } ###############################################################################