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.5 2014/02/27 06:38:16 apsop
# HISTORY: VERSION header now shows CVS Revision
# HISTORY:
# HISTORY: Revision 1.4 2012/10/05 07:53:03 apsop
# HISTORY: In sub checkTargetID, have log entry mention that this is a
# HISTORY: remapped sequence. Also gave that sub a header.
# HISTORY:
# HISTORY: Revision 1.3 2011/01/18 20:01:35 apsop
# HISTORY: Added subroutine checkTargetID to verify that the target
# HISTORY: is actually related to the sequence parameter. This particularly
# HISTORY: useful for remapped sequences.
# HISTORY:
# 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: $Revision: 1.5 $
#
##############################################################################
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();
$self->checkTargetID();
$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
##########################################################################
##########################################################################
# Make sure that the target parameter agrees with the sequence parameter and
# fix it if it doesn't. This happens if the sequence had been remapped.
##########################################################################
sub checkTargetID{
my $self = shift;
my $jobpar = $self->jobpar();
my $log = $self->log();
my $target = $jobpar->read('target');
my $otarg = $target;
my $i = 0;
while( $target =~ /^0/){
$target =~ s/^0//;
$i++;
if($i > 11){
last;
}
}
my $trigid = $jobpar->read('sequence');
$trigid =~ s/\d{3}$//;
my $ntarg = $trigid;
my $j = 0;
while ($trigid =~ /^0/){
$trigid =~ s/^0//;
$j++;
if($j> 11){
last;
}
}
if ($trigid ne $target){
$jobpar->set({target => $ntarg});
$log->entry("Changed \"target\" from $otarg to $ntarg to make it agree with sequence number. Sequence had been remapped.");
}
}
############################################################################
############################################################################
# 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;