#!/bin/perl #+ # nscamlog -- generate logsheet data from image headers # # Purpose: # Given a list of images, parse the image headers and print # out a formatted list of data. With no arguments, parse all of # the images in the current directory. # # Usage: # nscamlog [n | images] # # Arguments: # n = number of latest images to parse. # images = names of images to parse. If no images are listed, # then all images in the current directory will be read # (EXCEPT for backup.fits). # # Output: # to STDOUT # # Restrictions # None # # Note: # The output from this program is extra wide. To print it, use # this command: # enscript -1r -c -f Courier9 -P lw4s # # Exit values: # 0 = normal completion # 1 = wrong number of arguments # # Example: # 1) Generate log data for all images in the current directory: # nscamlog # # ) Generate log data for the last 5 images in the current directory: # nscamlog 5 # # 3) Generate log data for all images in the directory # /s/sdata602/nirspec/2003jan01/scam: # nscamlog /s/sdata602/nirspec/2003jan01/scam/*.fits #- # Modification history: # 2002-Dec-30 GDW Original version (deeplog) # 2003-Aug-27 GDW Changed TTIME to EXPTIME # 2004-Oct-10 GDW Added "last n images" option # 2004-Nov-09 jlyke Adapted for NIRSPEC use (nscamlog) # 2019-Jan-16 jlyke NIRSPEC Upgrade # 2021-Dec-01 jlyke Updated format to GDopp version, handle KOA #----------------------------------------------------------------------- use Getopt::Std; use File::Basename; # get command-line options... getopts("h"); # define the name of this program... my( $base) = basename($0); # define usage my( $usage) = <=0 ; $i--){ if( ($images[$i] =~ m/backup.fits/) or # remove backup files ($images[$i] =~ m/^cam/) or # remove cam files not ($images[$i] =~ m/.fits$/ or $images[$i] =~ m/.fits.gz$/)){ splice( @images, $i, 1) } } # parse args... if ( @ARGV == 1 and $ARGV[0] =~ /^\d+$/ ) { $m = $ARGV[0]; if ( $m > @images ) { $m = scalar(@images) }; $m = -$m; @images = @images[ $m .. -1 ]; # extract last $m elements of image list } elsif ( @ARGV > 0 ) { @images = @ARGV; } # verify number of images... die "ERROR: No images found\n" unless @images; ## get some information from the first NIRSPEC image... #for( $i=0 ; $i < @images ; $i++){ # %HeadValue = &GetFitsHead( $images[$i]); # last if (defined($HeadValue{'CURRINST'}) # and $HeadValue{'CURRINST'} =~ m/^NIRSP/) #} #die "ERROR: No NIRSPEC images found\n" # unless $HeadValue{'CURRINST'} =~ m/^NIRSP/; # print header... printf "\n"; printf "%-72s", "Project:"; printf "UT Date: %s", &BlankIfUndef($HeadValue{"DATE-OBS"}); printf "\n"; printf "%-72s", "Observers: " . &BlankIfUndef($HeadValue{"OBSERVER"}); printf "Weather:"; printf "\n"; printf "%-72s", "Data directory: " . &BlankIfUndef($HeadValue{"OUTDIR"}); printf "Seeing:"; printf "\n"; printf "\n"; $line = ''; for ( $i=0 ; $i<@X::keyword ; $i++ ) { $X::format[$i] =~ m/^%-?(\d+)/; $n = $1; $X::format[$i] =~ m/(\s+)$/; $space = $1; $buf = sprintf "%-${n}s$space", $X::title[$i]; print $buf; $buf =~ s/./_/g; $line .= $buf; } printf "\n"; printf "$line\n"; # set initial values of object and telescope offsets $Object = ""; $Filter = ""; $RaBase = &Ra2Num($HeadValue{'RABASE'}); $DecBase = &Dec2Num($HeadValue{'DECBASE'}); $Time = 0.0; $Itime = 0.0; $Coadds = 0; # loop over images... for ( $j=0 ; $j<@images ; $j++ ) { # reset $Comment $Comment = ""; # read image header... %HeadValue = &GetFitsHead( $images[$j]); # skip non-NIRSPEC images... # next unless (defined($HeadValue{'CURRINST'}) # and $HeadValue{'CURRINST'} =~ m/^NIRSP/); # build filename field... # $HeadValue{'FILENAME'} = (fileparse( $images[$j], '\..*'))[0]; # build filename field...compare DATAFILE keyword w/ filename # remove ".fits" from DATAFILE header keyword $HeadValue{'DATAFILE'} =~ s/.fits//; # remove ".fits.gz" or ".fits" from filenames in list of images $filename = (fileparse( $images[$j], '\.fits*/'))[0]; $filename =~ s/.fits.gz//; $filename =~ s/.fits//; if ( $HeadValue{'DATAFILE'} ne $filename){ # KOA filenames N[CS].YYYYMMDD.SSSSS $Comment = $Comment.$HeadValue{'DATAFILE'}; $HeadValue{'DATAFILE'} = $filename; } # read some keywords to adapt the printed values # $NewObj = $HeadValue{'OBJECT'}; $NewObj = $HeadValue{'TARGNAME'}; $NewFilt = $HeadValue{'SCAMFILT'}; # If UTC is in header, collect some more dcs keywords if ( defined($HeadValue{'UT'}) ) { $Ra = &Ra2Num($HeadValue{'RA'}); $Dec = &Dec2Num($HeadValue{'DEC'}); #print $Ra; #print $Dec; } if ( $NewObj ne $Object ) { $Comment = $Comment . " New Object"; } elsif ( $NewFilt ne $Filter ) { $Comment = $Comment . " New Filter"; } else { $RaDith = 3600.*($Ra - $RaBase)*cos($Pi/180.*$Dec); $DecDith = 3600.*($Dec - $DecBase); # print "$RaDith, $DecDith\n"; if ( ($RaDith != 0.) || ($DecDith != 0.) ) { $DitherSize = 3600.*sqrt(($RaDith*cos($Pi/180.*$Dec))**2 + $DecDith**2); # print "$RaDith, $DecDith\n"; # Setup the comment # Option 1 is raoff, decoff $Comment = $Comment . " en " . sprintf("%7.3f", $RaDith) . " " . sprintf("%7.3f", $DecDith) . "\""; # Option 2 is the combined dither size and time it took # $Comment = "Dith\: " . sprintf("%.2f", $TimeDiff) . "s " . sprintf("%.2f", $DitherSize) . "\""; # $Comment = "Dither\: " . sprintf("%.2f", $TimeDiff); } else { # When no dither option 1 states "No Dither" $Comment = $Comment; # Option 2 also prints the time between images # $Comment = "No Dith\: " . sprintf("%.2f", $TimeDiff) . "s "; } } # set the comment field if ( $printcomment == 0 ) { $HeadValue{$X::keyword[$#keyword]} = $Comment; } # reset variables for next time thru $Object = $NewObj; $Filter = $NewFilt; $RaBase = $Ra; $DecBase = $Dec; # print results... for ( $i=0 ; $i<@X::keyword ; $i++ ) { if ( defined $HeadValue{$X::keyword[$i]} and $HeadValue{$X::keyword[$i]} ne $null ){ $HeadValue{$X::keyword[$i]} =~ s/^\s+//; # remove leading whitespace $HeadValue{$X::keyword[$i]} =~ s/\s+$//; # remove trailing whitespace printf $X::format[$i], $HeadValue{$X::keyword[$i]} } else { $X::format[$i] =~ m/^%-?(\d+)/; $n = $1; if ( not defined $HeadValue{$X::keyword[$i]}){ $buf = '?' } else { $buf = '' } printf "%-${n}s ", $buf; } } printf "\n"; } #----------------------------------------------------------------------- sub GetFitsHead { #----------------------------------------------------------------------- # get file name to read header from my $infile = shift; my( $excess, $comment); # reset output hashes to null my %HeadValue = (); my %HeadComment = (); # open the file with a shared lock to prevent it being modified # during reading... open TEST, "<$infile"; flock TEST, 1; # open input file using appropriate method... if ($infile =~ /\.gz$/i) { open INFITS, "gunzip --stdout $infile |"; $| = 1; # enable autoflush on gunzip output } else { open INFITS, $infile; } # initialize input variable to allow for end-of-header trapping $headline = " "; # loop thru FITS file 80 bytes at a time until end-of-header mark found until (substr($headline,0,4) eq "END ") { read INFITS, $headline, 80 or die "unexpected end of file on read"; chomp($headline); # identify keyword name from first 8 bytes $name = substr($headline, 0, 8); $rest = substr($headline,9); # strip extra spaces off of keyword names $name =~ s/\s//g; # test if value is a string, handle single quotes if it is if (substr($rest,0,2) eq " '") { $lastquote = index($rest, "'", 2); $value = substr($rest,2,$lastquote-2); ($excess, $comment) = split (/\//, substr($rest, $lastquote)); } else { # otherwise split value from comment using / separator ($value, $comment) = split (/\//, $rest); $value =~ s/\s//g; } # add next value and comment to respective hashes unless ($name eq "END" or $name eq "") { $HeadValue{$name} = $value; $HeadComment{$name} = $comment; } } # close input FITS file close INFITS; close TEST; return %HeadValue; } #----------------------------------------------------------------------- sub AddColumn { #----------------------------------------------------------------------- my( $keyword, $title, $format) = @_; push( @X::keyword, $keyword); push( @X::title, $title); push( @X::format, $format); } #----------------------------------------------------------------------- sub Ra2Num { #----------------------------------------------------------------------- my( $coord) = @_; my( @t) = split /:/, $coord, 3; my( $ra) = 15.*($t[0] + $t[1]/60. + $t[2]/3600.); return $ra; } #----------------------------------------------------------------------- sub Dec2Num { #----------------------------------------------------------------------- my( $coord) = @_; my( @t) = split /:/, $coord, 3; my( $first) = substr($t[0],0,1); my( $sign) = 1.; if ( $first =~ m/-/ ) { $sign = -1.; $t[0] = $sign*$t[0]; } my( $dec) = ($t[0]/1. + $t[1]/60. + $t[2]/3600.) * $sign; return $dec; } #----------------------------------------------------------------------- sub BlankIfUndef { #----------------------------------------------------------------------- my( $value) = @_; if( defined $value){ return $value } else { return '' } }