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.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: 1.1 # ############################################################################## 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;