package Subs::StartEndTimes; ############################################################################## # # DESCRIPTION: This subroutine does a number of things invoving the time # DESCRIPTION: values in every FITS HDU for a list of file types. # DESCRIPTION: # DESCRIPTION: If an extension had TSTART and TSTOP keywords, it checks to # DESCRIPTION: be sure that neither is zero and that TSTART <= TSTOP. # DESCRIPTION: It also sets the values for the DATE-OBS, TIME-OBS, DATE-END, # DESCRIPTION: TIME-END keywords. Finally it keeps a running tally of the # DESCRIPTION: earliest TSTART and the latest TSTOP. These values are used # DESCRIPTION: to mark start and finish of the entire observation. # DESCRIPTION: # DESCRIPTION: Every TIME column is checked for whether it is in order. # DESCRIPTION: The BAT bcdh files are not checked since the BAT_TELEM column # DESCRIPTION: is not supposed to be in order. # DESCRIPTION: # DESCRIPTION: Finally, for every GTI extension, the subroutine checks that # DESCRIPTION: no two GTIs overlap, that they are in order and that they # DESCRIPTION: all have STOP > START. # # HISTORY: # HISTORY: $Log: StartEndTimes.pm,v $ # HISTORY: Revision 1.20 2004/10/12 16:28:09 apsop # HISTORY: Turn off sort checking of TIME columns in order to decrease run time. # HISTORY: # HISTORY: Revision 1.19 2004/08/30 13:19:30 apsop # HISTORY: Add in new trend types. Need better way of doing this. # HISTORY: # HISTORY: Revision 1.18 2004/08/22 18:42:25 apsop # HISTORY: Initial changes for new file classes and repository # HISTORY: # HISTORY: Revision 1.17 2004/07/12 13:45:40 apsop # HISTORY: Add timedata type to check list # HISTORY: # HISTORY: Revision 1.16 2004/06/08 00:09:36 apsop # HISTORY: Fix for handling case with no attitude info. # HISTORY: # HISTORY: Revision 1.15 2004/06/02 18:53:20 apsop # HISTORY: Add uvot compression trend file to list of files to proccess # HISTORY: # HISTORY: Revision 1.14 2004/05/28 19:45:20 apsop # HISTORY: Write CVSINIT keyword into all the fits files # HISTORY: # HISTORY: Revision 1.13 2004/05/06 20:02:34 dah # HISTORY: Add version number back into the header comments. # HISTORY: # HISTORY: Revision 1.12 2004/04/16 20:21:18 dah # HISTORY: Begin using embedded history records # HISTORY: # # VERSION: 0.0 # # ############################################################################## use Subs::Sub; @ISA = ("Subs::Sub"); use strict; sub new { my $proto=shift; my $self=$proto->SUPER::new(); $self->{DESCRIPTION}="Determining start and end times of the observation"; return $self; } ################## # METHODS: ################## sub body { my $self=shift; my $log =$self->log(); my $filename=$self->filename(); my $procpar =$self->procpar(); my $jobpar =$self->jobpar(); my @types = ('attitude', 'unfiltered', 'hk', 'scenhk', 'enhk', 'rawimage', 'bamdph', 'maskwt', 'bgaoff', 'bamgaoff', 'rawdph', 'dph', 'lightcurve', 'rawlc', 'batlcatt', 'gti', 'ucmp', 'timedata', 'bscalemap', 'bsegment', 'bcatalog', 'btbveto', 'btblongtr', 'btbshorttr', 'btbratetr', 'btbimgtr', 'btbratedg', 'btbrun', 'bgain', 'boffset', 'bdetflag', 'bcomman', 'bdaphk', 'bshelllg', 'btrigflx'); my $tstart; my $tstop; ########################################## # get the maximum reasonable TSTART-TSTOP ########################################## my $max_duration = $procpar->read("max_duration"); ####################### # Setup for UTCF value ####################### my $time_file = $filename->get('timedata', 'swift', '', 0); my (@utcf_times, @utcf); if( -f $time_file ){ my $time_fits = Util::FITSfile->new($time_file, 'UTCF'); my @utcf_times = $time_fits->cols('TIME')->table(); my @utcf = $time_fits->cols('UTCF')->table(); } ######################## # loop over file types ######################## my $type; foreach $type (@types) { $log->entry("Examining TSTART and TSTOP in all $type files"); ################################### # loop over the files of this type ################################### my $file; foreach $file ($filename->any($type) ) { my $fits = Util::FITSfile->new($file); ################################ # loop over all HDUs ################################ my $nhdus = $fits->nhdus(); my $ext; for($ext=0; $ext<$nhdus; $ext++) { $log->entry("Examining $file\[$ext\]"); $fits->ext($ext); ########################################### # check if there are TSTART/TSTOP keywords ########################################### my $start = $fits->keyword("TSTART"); my $stop = $fits->keyword("TSTOP"); if(defined $start && defined $stop ) { ######################################## # make some sanity checks ######################################## if($start == 0.0 || $stop == 0.0 || $stop < $start || $stop - $start > $max_duration ) { $log->error(1, "Skipping $file\[$ext\] since it has ". "invalid TSTART=$start TSTOP=$stop"); next; } $log->entry("TSTART=$start TSTOP=$stop"); ####################################################### # keep a running tally of the absolute start/end_times ####################################################### if(!defined($tstart) || $start<$tstart) { $tstart = $start } if(!defined($tstop ) || $stop >$tstop ) { $tstop = $stop } $log->entry("Observation tstart=$tstart tstop=$tstop"); ####################################### # write the DATE/TIME OBS/END keywords ####################################### my $first = Util::Date->new($start); my $last = Util::Date->new($stop); $fits->keyword('DATE-OBS', $first->date().'T'.$first->time() ); $fits->keyword('DATE-END', $last->date().'T'.$last->time() ); #################################### # Determine UTCFINI and write it in #################################### if(@utcf){ my $itime = 0; while( $tstart > $utcf_times[$itime] && $itime < $#utcf_times){ $itime++ } $fits->keyword('UTCFINIT', $utcf[$itime]); } } $log->entry("Checking $file\[$ext\]"); ###################################### # now check if there is a time column ###################################### #if($ext > 0 && $fits->find_column('TIME') ) { # $fits->cols('TIME'); # ####################################### # # make sure the column is time ordered # # we don't check BAT BCDH files since their # # BAT_TELEM extension is purposely out of # # time order. # ####################################### # if( $fits->keyword('EXTNAME') !~ /^BAT_/ && !$fits->isOrdered() ) { # $log->error(2, "$file\[$ext\] is out of time order"); # } #} ########################################### # finally check if this is a GTI extension ########################################### if($ext > 0) { ##################################################### # primary extension doesn't have an EXTNAME keyword ##################################################### my $extname = $fits->keyword('EXTNAME'); unless(defined $extname){ ################################################ # sanity check - this can be taken out when the # FITS files are more stable ################################################ $log->error(1, "$file has no EXTNAME in extension 1"); } else { if($extname =~ /GTI/) { ########################################### # are the START columns in order? ########################################### unless($fits->cols('START')->isOrdered() ) { $log->entry("$file\[$ext\] START column is out of order. Will sort."); $fits->sort('START'); } ############################################### # are the individual GTIs of positive duration ############################################### my %intervals = $fits->cols("START", "STOP")->table(); foreach (keys %intervals ) { if($intervals{$_} <= $_ ) { $log->error(2, "Invalid GTI". "START=$_ STOP=$intervals{$_} ". "in $file\[$ext\]" ); } } ########################################### # are there overlaps ############################################ unless($fits->cols('START')->isOrdered('unique') && $fits->cols('STOP')->isOrdered('unique')) { $log->entry("$file\[$ext\] Has overlapping GTIs. Will merge."); my $temp = 'merged_gti.tmp'; Util::Ftool->new('mgtime') ->params({ingtis => "$file\[$ext\] $file\[$ext\]", outgti => $temp, merge => 'OR'}) ->run(); Util::FITSfile->new($temp) ->import_header("$file\[$ext\]", 'except', '') ->append_to($file); Util::Ftool->new('fdelhdu') ->params({infile => "$file\[$ext\]", confirm => 'no', proceed => 'yes'}) ->run(); unlink $temp; $ext--; } } } } } # end of loop over HDUs } # end of loop over files } # end of loop over file types ############################################################# # check if we got start and stop times from the FITS files ############################################################# unless(defined $tstart && defined $tstop) { ######################################################## # nothing from the FITS files, so try getting # the start and stop times directly from the telemetry ######################################################## $log->entry("Extracting observation start and end times from ". "the telemetry secondary headers."); my $squirt = Util::Tool->new($procpar->read("squirt"), "squirt"); $squirt->stdin(1); #so that we don't redirect from /dev/null foreach my $telem ($filename->any("telemetry")) { $squirt->command_line("-e '\"%time2\\n\"; filter: 0;' < $telem 2>&1"); $squirt->run(); my @times=split /\s+/, $squirt->stdout(); @times = sort { $a <=> $b } @times; my $max = $times[@times-1]; if(! defined $tstop || $max > $tstop) { $tstop = $max} @times = grep {$_ > $tstop - $max_duration } @times; my $min = $times[0]; $log->entry("In $telem min=$min max=$max"); if(!defined $tstart || $min < $tstart) {$tstart = $min} } } ############################################ # check if we got absolute start/stop times ############################################ unless(defined $tstart) { $log->error(1, "Can't determine observation start time, ". "setting to zero"); $tstart=0.0; } unless(defined $tstop) { $log->error(1, "Can't determine observation end time, setting to zero"); $tstop=0.0; } #################################### # convert mission time to date/time #################################### my $start_date = Util::Date->new($tstart); my $stop_date = Util::Date->new($tstop ); ###################### # log the results ###################### $log->entry("overall TSTART=$tstart = ". $start_date->date()."T". $start_date->time() ); $log->entry("overall TSTOP=$tstop = ". $stop_date->date()."T". $stop_date->time() ); ##################################### # ... and record them in the job.par ##################################### $jobpar->set({tstart => $tstart, tstop => $tstop, obsdate => $start_date->date(), obstime => $start_date->time(), enddate => $stop_date->date(), endtime => $stop_date->time() }); } # end of body method