package Subs::WrapUp;
##############################################################################
#
# DESCRIPTION: This subroutine class handles a number of cleanup tasks which
# DESCRIPTION: need to be done at the end of each processing run,
# DESCRIPTION: including creating output catalog files and verifying
# DESCRIPTION: the product files. Each of these functions is handled
# DESCRIPTION: by a separate method to make it easier to write a sub-class
# DESCRIPTION: which overriseds the default body method.
# DESCRIPTION:
# DESCRIPTION: Each processing script should run this subroutine class
# DESCRIPTION: (or a decendant of it) last.
#
# HISTORY
# HISTORY: $Log: WrapUp.pm,v $
# HISTORY: Revision 1.3 2014/02/27 06:38:17 apsop
# HISTORY: VERSION header now shows CVS Revision
# HISTORY:
# HISTORY: Revision 1.2 2006/08/01 20:35:34 apsop
# HISTORY: Add in CVS history indicator.
# HISTORY:
# HISTORY: 1.0 -> 1.1 2002-04-01
# HISTORY: Now make a hard link insteead of copying the parfiles. This way
# HISTORY: the data product version will stay up to date. Previously
# HISTORY: Things like missing file errors would not get counted, since
# HISTORY: they were logged after the parfiles were copied.
#
# VERSION: $Revision: 1.3 $
#
##############################################################################
use Subs::Sub;
@ISA = ("Subs::Sub");
use strict;
use Util::CoreTags;
#########################################
# constructor
#########################################
sub new {
my $proto=shift;
my $self=$proto->SUPER::new();
$self->{DESCRIPTION}="Doing final wrapup of all files";
$self->{FILES}=();
$self->{FITS_FILES}=();
$self->{CHECKSUM_TYPE}="checksum";
$self->{HTML_CAT_TYPE}="fileinfo";
return $self;
}
#########################
# METHODS:
#########################
##############################################################################
# Do a number of generic wrapup functions. Specifically:
# - save copies of the job.par and processing parfile.
# - create all output file catalogs (product and trend by default)
# - calculate site-independant checksums
# - update the checksums in all FITS file headers
# - run the fverify FTOOL on all FITS files.
# - check for leftover files, which are not included in any of the output
# catalogs
#############################################################################
sub body {
my $self=shift;
my $filename = $self->filename();
my $log = $self->log();
my $jobpar = $self->jobpar();
my $procpar = $self->procpar();
##############################################
# Save the parameter files
##############################################
$self->save_parfiles();
#####################################
# create the file catalogs
#####################################
$self->make_catalogs();
#######################################
# Write keywords to all the FITS files
#######################################
$self->write_standard_keywords();
###################################
# make the checksum file
###################################
$self->make_checksum_file();
##################################
# update FITS checksum files
##################################
$self->fits_checksums();
$self->verify();
######################################
# check for leftover files
######################################
$self->leftovers();
} # end of body method
#######################################################
# save a copy of the parfiles
#######################################################
sub save_parfiles {
my $self=shift;
my $log=$self->log();
my $filename=$self->filename();
my %pars=(jobpar => $self->jobpar(),
procpar => $self->procpar() );
my $type;
foreach $type (keys %pars) {
my $par=$pars{$type};
my $infile=$par->name();
my $outfile=$filename->get($type);
###############################################################
# copy the file if the outfile file does not exist
# or if the infile was modified before the last modification
# of the outfile.
# In stead of copying, we make a hard link. That way both
# copies of the file will stay in synch even if one is modified
# after the copy. This is important for the nprocerrors
# parameter.
################################################################
if( ! -f $outfile || (stat($outfile))[9] > (stat($infile))[9] ) {
$log->entry("Copying $infile to $outfile");
#open IN, "<$infile";
#open OUT, ">$outfile";
#print OUT <IN>;
#close IN;
#close OUT;
link $infile, $outfile
}
} # end of loop over parfiles
} # end of save_parfiles method
###########################################################################
###########################################################################
# make all FITS catalogs and the HTML file catalog
###########################################################################
sub make_catalogs {
my $self=shift;
my $filename=$self->filename();
######################################################
# get names of catalogs, and assume the HTML catalog
# has the same files as the first FITS catalog
######################################################
my @fits_catalogs=$filename->catalog_types();
my $html_cat_is_like=$fits_catalogs[0];
##########################################################
# register the files we have yet to make with the
# Catalog class
##########################################################
Util::Catalog->future_files((map {$_=>'FITS'} @fits_catalogs),
'checksum' =>'ASCII',
'fileinfo' =>'HTML');
###############################################
# create FITS catalogs
###############################################
my $type;
foreach $type (@fits_catalogs ) {
Util::Catalog->new($type)
->make()
->register_in_parfile();
}
########################################
# create the HTML catalog
########################################
Util::HTMLcatalog->new($html_cat_is_like,'fileinfo')
->make();
} # end of make_catalogs method
#########################################################################
#########################################################################
# add standard keywords to the headers of all the FITS files.
#########################################################################
sub write_standard_keywords {
my $self=shift;
my $log = $self->log();
my $filename = $self->filename();
my $jobpar = $self->jobpar();
my $procpar = $self->procpar();
$log->entry("Writing standard keywords to all FITS files");
####################################
# loop over all FITS files
####################################
my $file;
foreach $file (Util::Catalog->fits_files() ) {
my $fits = Util::FITSfile->new($file);
##################################
# loop over HDUs in the FITS file
##################################
my $nhdus = $fits->nhdus();
my $hdu;
for($hdu=0; $hdu<$nhdus; $hdu++) {
$fits->ext($hdu);
################################
# write keywords to the file
################################
$fits->begin_many_keywords();
$fits->keyword("SEQNUM", $jobpar->read("sequence"),
"Unique ID for this dataset" );
$fits->keyword("SEQPNUM", $jobpar->read("seqprocnum"),
"Number of times this dataset processed" );
$fits->keyword("PROCVER", $procpar->read("version"),
"Processing script version" );
$fits->end_many_keywords();
}
}
} # end of write_standard_keywords method
#########################################################################
#########################################################################
# calculate site independant checksums
#########################################################################
sub make_checksum_file {
my $self=shift;
my $log = $self->log();
my $filename = $self->filename();
my $jobpar = $self->jobpar();
$log->entry("Calculating site-independant checksums");
#####################################
# open the checksum file
#####################################
my $checksum_file=$filename->get("checksum");
open CHECKSUM, ">$checksum_file";
print CHECKSUM "This file lists all files plus site-independant\n";
print CHECKSUM "checksums for all FITS files. It may be used to compare\n";
print CHECKSUM "sequences processed by parallel pipelines.\n";
####################################
# loop over all FITS files
####################################
my $file;
foreach $file (Util::Catalog->fits_files() ) {
my $sum=Util::FITSfile->new($file)
->site_independant_checksum();
print CHECKSUM "$file $sum\n";
}
###########################
# close the checksum file
###########################
close CHECKSUM;
###################################################
# now calculate the checksum of the checksum file
# and record that in the checksum file
###################################################
my $checksum_tool=Util::FITSfile->checksum_tool();
my $seqcheck = $checksum_tool->command_line($checksum_file)
->run()
->stdout();
$seqcheck =~ s/^(\S*).*$/$1/s;
$jobpar->set({seqcheck=>$seqcheck});
$log->entry("Site independant checksum: $seqcheck");
} # end of make_checksums method
#############################################################################
#############################################################################
# run fverify on all the FITS files
#############################################################################
sub verify {
my $self=shift;
my $log=$self->log();
$log->entry("Running fverify on all FITS files");
###################
# set up fverify
###################
my $fverify=Util::Ftool->new("fverify")
->params({outfile=>"STDOUT",
prhead=>"no",
testdata=>"yes"})
->verbose(0);
######################################
# loop over all FITS files
######################################
my $file;
foreach $file (Util::Catalog->fits_files() ) {
Util::FITSfile->new($file)
->verify();
}
} # end of verify method
#############################################################################
#############################################################################
# set FITS checksum keywords
#############################################################################
sub fits_checksums {
my $self=shift;
my $log=$self->log();
$log->entry("Updating FITS checksum keywords");
#####################
# set up fchecksum
#####################
my $fchecksum=Util::Ftool->new("fchecksum")
->params({update =>"yes",
datasum=>"yes"})
->verbose(0);
######################################
# loop over all FITS files
######################################
my $file;
foreach $file (Util::Catalog->fits_files() ) {
$fchecksum->params({infile=>"$file"})
->run();
}
} # end of fits_checksums
#############################################################################
#############################################################################
# check for leftover files
#############################################################################
sub leftovers {
my $self=shift;
my $log =$self->log();
my $jobpar =$self->jobpar();
my $procpar=$self->procpar();
##########################################################
# Mash together a list of all the files in the current
# directory, plus all the files in the catalog, plus
# the names of the two unsaved parfiles. Then
# count the occurances of each filename in the combined
# list. Anything which does not appear twice is an error
#########################################################
my @files=glob("*");
my %count=();
my $file;
foreach $file (@files,
Util::Catalog->all_files(),
$jobpar ->name(),
$procpar->name() ) {
$count{$file}++;
}
##########################################
# look for files in this directory which
# are not in the catalog
##########################################
foreach $file (@files) {
if($count{$file} == 1 ) {
$log->error([ 1, UNKNOWN_FILE ], "Leftover file $file");
}
}
} # end of leftovers method
1;