Subs::CheckInput (version 1.2)


package Subs::CheckInput;
#############################################################################
#
# DESCRIPTION: This subroutine class provides a number of methods for
# DESCRIPTION: checking the input files for a processing run.
# DESCRIPTION: It provides a simple default body method, which
# DESCRIPTION: missions with specific needs may override. 
# DESCRIPTION: Processing scripts should run this subroutine 
# DESCRIPTION: (or a subclass of it) first.
#
# HISTORY
# HISTORY: $Log: CheckInput.pm,v $
# HISTORY: Revision 1.2  2006/08/01 20:35:34  apsop
# HISTORY: Add in CVS history indicator.
# HISTORY:
# HISTORY: 1.0 -> 1.1 2000-06-28
# HISTORY: Fixed a bug in the file trimming sectopn of the fix_overlaps method
# HISTORY: 
# HISTORY: 1.1 -> 1.2 2001-03-05
# HISTORY: Minor adjustments in variable declarations
#
# VERSION: 1.2
#
##############################################################################

use Subs::Sub;
@ISA = ("Subs::Sub");
use strict;

use Util::CoreTags;


#########################################
#
#########################################
sub new { #()
    my $proto=shift;
    my $self=$proto->SUPER::new(@_);

    $self->{DESCRIPTION}="Checking input files for validity";

    return $self;
}

###############################
# METHODS:
###############################


############################################################################
############################################################################
# this only calls the verify_input method without fverify requested.
# Mission specific versions of this class should override this method
# to do other interesting things.
############################################################################
sub body {
    my $self=shift;

    $self->verify_input();                               

} # end of subroutine body



###########################################################################
###########################################################################
# Verify all the input files - i.e. make sure they exist, and 
# optionally run fverify on each of them.
###########################################################################
sub verify_input {
    my $self=shift;
    my $fverify_requested=shift;

    my $filename=$self->filename();
    my $log     =$self->log();
    my $jobpar  =$self->jobpar();

    $log->entry("Verifying the input files");


    #########################################
    # set up an fverify FTOOL object
    #########################################
    my $fverify;
    if($fverify_requested ) {
        $fverify=Util::Ftool->new("fverify")
                            ->params({outfile=>"STDOUT",
                                      prhead=>"no",
                                      testdata=>"yes"})
                            ->verbose(0);
    }


    ######################################
    # dump the input catalog file
    ######################################
    my $cat=$filename->get("inputcat");
    
    my %list=Util::FITSfile->new($cat,1,'[FORMAT==\'FITS\']')
                           ->cols("FILENAME FORMAT")
                           ->table();

    ##############################
    # loop over all files
    ##############################
    my $file;
    my $format;
    while( ($file,$format) = each %list ) {

        if( -e $file) {
            ##################################################
            # file exists, so run fverify if it's a FITS file
            ##################################################
            if($format eq "FITS" && $fverify_requested ) {
                 ##########################
                 # FITS file - run fverify
                 ##########################
                 $log->entry("Running fverify on $file");

                 $fverify->params({infile=>$file})->run();
                 if($fverify->had_error() || 
                    $fverify->parfile()->read("numerrs") ) {
                     #################################################
                     # only dump the fverify output if there was an
                     # error to avoid filling up the log with trash
                     #################################################
                     $log->entry("Output from fverify");
                     $log->text($fverify->stdout());
                 }

            } elsif($format eq "FITS") {
                ######################################
                # FITS file, but we won't run fverify
                ######################################
                $log->entry("FITS file $file exists\n");
           
            } else {
                 ################
                 # non-FITS file
                 ################
                 $log->entry("non-FITS file $file exists\n");
            }


        } else {
            #################################
            # file is missing, give an error
            #################################
            $log->error([ 3, BAD_INPUT ],
                    "Required input file $file is missing");
        }
                
    } # end of loop over input files

                                 
    
        

} # end of verify_input method

##########################################################################
##########################################################################
# calculate the observation date and record it in the job.par.
# This is done by reading the given start and stop mission time keywords
# from the headers of a particular type of file.
##########################################################################
sub determine_obsdate {
    my $self=shift;

    my $type=shift;
    my $start_key=shift;
    my $stop_key=shift;

    my $log=$self->log();
    my $jobpar=$self->jobpar();
    my $filename=$self->filename();

    $log->entry("Calculating Observation start and end times\n");

    ######################################################
    # read all the start and stop keyword values
    ######################################################
    my @files=$filename->any($type);
    my @times = Util::FITSlist->new(@files)
                              ->extension($self->option("obsdate_ext"))
                              ->keywords($start_key,$stop_key);

    ####################################
    # calculate the earliest start time
    ####################################
    my $tstop;
    my $tstart = $tstop = shift @times;
    foreach (@times) {

        if($_ < $tstart ) { $tstart = $_}
        if($_ > $tstop  ) { $tstop  = $_}
    }
 

    ############################################################
    # create date objects corresponding to start and stop times
    ############################################################
    my $start_date=Util::Date->new($tstart);
    my $stop_date =Util::Date->new($tstop );

    ###########################################
    # record the results in the jobpar and log
    ###########################################
    $jobpar->set({tstart  => $tstart,
                  tstop   => $tstop,
                  obsdate => $start_date->date(),
                  obstime => $start_date->time(),
                  enddate =>  $stop_date->date(),
                  endtime =>  $stop_date->time() });

    $log->entry("Observation begins $tstart = ".$start_date->date()." ".
                                                $start_date->time()     );

    $log->entry("Observation ends $tstop = ".$stop_date->date()." ".
                                             $stop_date->time()     );

} # end of obsdate method


############################################################################
############################################################################
# check for and remove overlaps of adjacent input files of a given type.
# This routine must be called multiple times if overlaps must be removed from
#  more than one file type.
############################################################################
sub fix_overlaps {
    my $self=shift;
    my $type=shift;
    my $ext=shift;
    my %keys=@_;

    my $filename=$self->filename();
    my $log=$self->log();

    #######################################################
    # first get a list of all files of the given type
    # since if there's only one file we can just quit now
    ######################################################
    my @files=$filename->any($type);
    if(@files == 1 ) {
        return;
    }

    ########################################################################
    # there's more than one file, so we need to do some work here.
    # first log what we're about to do.
    ########################################################################
    $log->entry("Checking for overlaps in extension $ext of $type files\n");

    ################################################################
    # loop over all files of the given type and collect their
    # start and stop times
    ################################################################
    my %first;
    my %last;
    my $file;
    foreach $file (@files) {
 
        ####################################################
        # read the first and last time values from the file
        ####################################################
        my $fits=Util::FITSfile->new($file,$ext)
                               ->cols("TIME");

        my $nrows=$fits->nrows();

        $first{$file}=$fits->rows(1     )->table();
        $last{ $file}=$fits->rows($nrows)->table();

        $log->entry("$file begins at $first{$file} and ends at $last{$file}");

    }

    #############################################
    # sort the files with the last end time first
    #############################################
    @files=sort {$last{$b} <=> $last{$a} } keys %last;

    ##########################################################
    # loop over all the files again - remove overlaps
    ##########################################################
    my $prev=shift @files;
    my $this;
    while(($this = $prev) && ($prev=shift @files) ) {
        #########################################
        # delete files wholely within this file
        #########################################
        while( $prev && $first{$prev} >= $first{$this}) {
            $log->error(2,"Deleting $prev since it is contained within $this");

            unlink $prev;
            $prev = shift @files;
        }
        if( ! $prev ) {last}


        ##############################################
        # do the files overlap
        ##############################################
        if( $first{$this} < $last{$prev} ) {
            #########################################
            # files overlap partially
            #########################################
            my $overlap = $last{$prev} - $first{$this};
            $log->error(1,"$this and $prev overlap by $overlap seconds");
            $log->entry("Trimming the beginning of $this");

            #########################################
            # so clip off the beginning of this file
            #########################################
            my $this_fits=Util::FITSfile->new($this,$ext,
                                              "\[TIME>$last{$prev}\]");
            $this_fits->copy();

            ########################################
            # adjust keywords
            ########################################
            my $prev_fits=Util::FITSfile->new($prev,$ext);

            my $this_key;
            my $prev_key;
            while( ($this_key,$prev_key) = each %keys ) {
                ####################################################
                # copy the end keyword from the previous file
                # to the begin keyword from this file
                ####################################################
                $this_fits->keyword($this_key,
                                    $prev_fits->keyword($prev_key) );
            }

        } # end if there was an overlap
    } # end of loop over files

} # end of overlap method
            



 
1;