package Subs::BATDB; ############################################################################## # # DESCRIPTION: # # HISTORY: $Log: BATDB.pm,v $ # HISTORY: Revision 1.10 2007/02/10 22:28:33 apsop # HISTORY: Set orig obs to seq obs for tdrss failed triggers. # HISTORY: # HISTORY: Revision 1.9 2007/02/08 14:31:34 apsop # HISTORY: Fix bug in calculation of original observation id, segment was being set to wrong value. # HISTORY: # HISTORY: Revision 1.8 2007/01/31 20:46:10 apsop # HISTORY: Add entries for the failed trigger event data. # HISTORY: # HISTORY: Revision 1.7 2006/08/02 19:46:00 apsop # HISTORY: If aspect correction fails for individual snapshots, change from level 2 to level 1 error. # HISTORY: # HISTORY: Revision 1.6 2005/12/22 18:03:38 apsop # HISTORY: Give module a version number to make the install scripts happy. # HISTORY: # HISTORY: Revision 1.5 2005/11/14 20:21:34 apsop # HISTORY: Wrote out map built-in in long-hand in response to inexplicable behavior. # HISTORY: Possible perl bug(?) # HISTORY: # HISTORY: Revision 1.4 2005/11/08 17:07:59 apsop # HISTORY: Use Filename calls to get bat db file names. Use caldb for alignfile in prefilter. Set RATE_CODE to INDEF for non-rate modes. Clean up temp $gtifile. # HISTORY: # HISTORY: Revision 1.3 2005/08/30 13:55:51 apsop # HISTORY: Change alignfile param to make in compatible with old version of aspect. Change rate_code column to ratecode. # HISTORY: # HISTORY: Revision 1.2 2005/08/16 22:23:33 apsop # HISTORY: Propagate original/true target, segment and observation numbers from # HISTORY: Rich's database HK file instead of taking from job.par. # HISTORY: # HISTORY: Revision 1.1 2005/08/16 21:36:37 apsop # HISTORY: Module for creating HEASARC BAT exposure database file. # HISTORY: # # VERSION: 0.0 # ############################################################################## use Subs::Sub; @ISA = ("Subs::Sub"); use strict; use Astro::FITS::CFITSIO qw(:constants); use Util::HEAdas; use Util::FITStable; use Util::CoreTags; sub new { my $proto=shift; my $self=$proto->SUPER::new(); $self->{DESCRIPTION} = 'Update BAT exposure database'; return $self; } ################## # METHODS: ################## sub body { my $self=shift; my $log = $self->log(); my $filename = $self->filename(); my $procpar = $self->procpar(); my $jobpar = $self->jobpar(); # set up the database columns my @db = ( { name => 'name', # source name type => '80A', comment => 'Designation of the Pointed Source', # $jobpar->read('object') }, { name => 'orig_target_id', # Target_id type => '1J', null => -1, disp => 'I8', comment => 'Trigger Number as Originally Assigned', # $jobpar->read('target') }, { name => 'target_id', # True target_id type => '1J', null => -1, disp => 'I8', comment => 'Unique Trigger Number with Any Degeneracy Removed', # substr(0, 8, $jobpar->read('sequence')) }, { name => 'ra', # R.A. type => '1E', unit => 'deg', disp => 'F10.5', comment => 'Right Ascension (Pointing Position)', # $jobpar->read('ra') }, { name => 'dec', # Dec. type => '1e', unit => 'deg', disp => 'F10.5', comment => 'Declination (Pointing Position)', # $jobpar->read('dec') }, { name => 'roll_angle', # Roll type => '1E', unit => 'deg', disp => 'F10.5', comment => 'Roll Angle (degree)', # $jobpar->read('roll') }, { name => 'start_time', # Start time type => '24A', comment => 'Start Time of the Observation', }, { name => 'stop_time', # Stop time type => '24A', comment => 'Stop Time of the Observation', }, { name => 'orig_obs_segment', # Obs seg type => '1J', disp => 'I3', null => -1, comment => 'Observation Segment as Originally Assigned', # $jobpar->read('obs') }, { name => 'obs_segment', # True Obs seg type => '1J', disp => 'I3', null => -1, comment => 'True Observation Segment (Corrected Value)', # substr(8, $jobpar->read('sequence')) }, { name => 'orig_obsid', # Obs number type => '11A', comment => 'Observation Number as Originally Assigned (OrigTarget_ID + Orig_Obs_Segment)', # $jobpar->read('target') . $jobpar->read('obs'); }, { name => 'obsid', # True Obs num type => '11A', comment => 'Unique Observation Number (Target_ID + Obs_Segment)', # $jobpar->read('sequence') }, { name => 'exposure', type => '1E', comment => 'Total time in seconds for this record', }, { name => 'ratecode', # ratecode type => '4A', comment => 'Flag for rate modes.', }, { name => 'catnum', # Catnum type => '1J', disp => 'I8', comment => 'Target_Id number in the BAT catalog (Mask Tag & Pulsar mode)', }, { name => 'operation_mode', # Observing mode type => '80A', comment => 'Indicates Operating Mode of Instrument', # from DATAMODE }, { name => 'pointing_mode', # Spacecraft obs mode type => '80A', comment => 'Indicates Pointing Mode of Spacecraft', # from OBS_MODE }, { name => 'filename', # Filename type => '80A', comment => 'Name of the File Containing the Data for this Interval', }, ); my $attfile = $filename->get('attitude', 'swift'); if (not $attfile) { $log->error(2, 'Unable to create BAT exposure database without attitude'); return; } my $dbfile = $filename->get('badb', 'proc', '', 0); # print "BAT exposure database will be named $dbfile\n"; my $hkfile = $filename->get('hk', 'proc', 'badb', 0); unless (-f $hkfile) { $log->entry("Unable to locate BAT exposure database housekeeping file $hkfile"); return; } my $batdb = Util::SimpleFITS->readonly($hkfile); my $status = $batdb->status; if (not $batdb or $status) { $log->error(2, "unable to open BAT catalog $hkfile [$status]"); return; } $batdb->move(2); if ($batdb->status) { $log->error(2, 'unable to move to $hkfile database extension'); return; } # slurp the BAT2FITS version my @records; $status = $batdb ->loadTable(\@records) ->status; if ($status) { $log->error(2, 'unable to read data'); return; } my $db = Util::FITStable->new(\@db, log => $log, which => 'bat', ); ################################################ # Add entries for the failed trigger event data ################################################ foreach my $tdfile ($filename->get('tdunfilter', 'bat', '*', '*')){ my %new_rec; my $tdfits = Util::FITSfile->new($tdfile, 0); $new_rec{CATNUM} = 0; $new_rec{SOURCE_NAME} = 'Failed Trigger'; $new_rec{RA} = 'INDEF'; $new_rec{DEC} = 'INDEF'; $new_rec{ROLL_ANGLE} = 'INDEF'; $new_rec{ORIG_TARGET_ID} = $jobpar->read('target'); $new_rec{TARGET_ID} = $tdfits->keyword('TARG_ID'); $new_rec{ORIG_OBS_SEGMENT} = $jobpar->read('obs'); $new_rec{OBS_SEGMENT} = $tdfits->keyword('SEG_NUM'); $new_rec{OPERATION_MODE} = 'Event'; $new_rec{POINTING_MODE} = 'SLEW_POINTING'; $new_rec{FILENAME} = $tdfile; $tdfits->ext(1); $new_rec{EXP_START} = $tdfits->keyword('TSTART'); $new_rec{EXP_STOP} = $tdfits->keyword('TSTOP'); $new_rec{START_TIME} = $new_rec{EXP_START}; $new_rec{STOP_TIME} = $new_rec{EXP_STOP}; $new_rec{INTEGRATION_TIME} = $tdfits->keyword('EXPOSURE'); $new_rec{INTERVAL} = $tdfits->keyword('TELAPSE'); push @records, \%new_rec; } ################################################### # Compile the data needed for the BAT database file ################################################### my $rows = @records; my @indef = ('INDEF') x $rows; $db->{rows} = $rows; # observation values my $object = $jobpar->read('object'); # this is what the pipeline writes for RA_PNT, DEC_PNT... my $nomra = $jobpar->read('ra'); my $nomdec = $jobpar->read('dec'); foreach my $e (@records) { if ($e->{CATNUM} == 0) { $e->{SOURCE_NAME} = $object; $e->{RA} = $nomra; $e->{DEC} = $nomdec; } # if($e->{POINTING_MODE} eq 'SLEW'){ # $e->{RA} = 'INDEF'; # $e->{DEC} = 'INDEF'; # $e->{ROLL_ANGLE} = 'INDEF'; # } } my @object = map { "'$_->{SOURCE_NAME}'" } @records; $db->set(name => \@object); $db->set(orig_target_id => [ map { $_->{ORIG_TARGET_ID} } @records ]); $db->set(target_id => [ map { $_->{TARGET_ID} } @records ]); # find mean roll for each snapshot my $aspect = Util::HEAdas->new('aspect') ->params({ attfile => $attfile, alignfile => 'CALDB' }); my $solved; my @gtidb = ( { name => 'START', type => '1D', }, { name => 'STOP', type => '1D', }, ); my $gtifile = 'aspect.gti'; foreach my $e (@records) { if (defined($solved) and $solved->{INTERVAL} == $e->{INTERVAL}) { $e->{ROLL_ANGLE} = $solved->{ROLL_ANGLE}; # if($e->{POINTING_MODE} eq 'SLEW'){ # $e->{RA} = $solved->{RA}; # $e->{DEC} = $solved->{DEC}; # } next; } my $gti = Util::FITStable->new(\@gtidb, log => $log, which => 'GTI', ); $gti->set(START => [ $e->{EXP_START} ]); $gti->set(STOP => [ $e->{EXP_STOP} ]); unlink($gtifile); $gti->write($gtifile); $aspect->params({ gtis => $gtifile }); $aspect->seriousness(1); $aspect->run(); if ($aspect->had_error) { $log->error([ 1, ASPECT_FAILED ], 'unable to determine mean roll for snapshot'); } else { $e->{ROLL_ANGLE} = $aspect->parfile()->read('roll'); # if($e->{POINTING_MODE} eq 'SLEW'){ # $e->{RA} = $aspect->parfile()->read('ra'); # $e->{DEC} = $aspect->parfile()->read('dec'); # } $solved = $e; # print "roll from $e->{EXP_START} to $e->{EXP_STOP} is $e->{ROLL_ANGLE}\n"; } } unlink($gtifile); my @ra = map { $_->{RA} } @records; my @dec = map { $_->{DEC} } @records; my @roll = map { $_->{ROLL_ANGLE} } @records; ################################################## # Set rate code to 'INDEF' if not in a Rates mode ################################################## foreach my $rec (@records){ $rec->{RATE_CODE} = 'INDEF' unless $rec->{OPERATION_MODE} =~ /Rates/; } #################################################################### # Early observations (before PPSTs) had multiple pointings, so set # pointing to indef #################################################################### if( $jobpar->read('tstart') > 124383600 ){ $db->set(ra => \@ra); $db->set(dec => \@dec); $db->set(roll_angle => \@roll); } else{ $db->set(ra => \@indef); $db->set(dec => \@indef); $db->set(roll_angle => \@indef); } # my @start = map { $db->timeString($_->{START_TIME}) } @records; # my @stop = map { $db->timeString($_->{STOP_TIME}) } @records; my @start; foreach my $e (@records) { push(@start, $db->timeString($e->{START_TIME})); } my @stop; foreach my $e (@records) { push(@stop, $db->timeString($e->{STOP_TIME})); } $db->set(start_time => \@start); $db->set(stop_time => \@stop); $db->set(orig_obs_segment => [ map { $_->{ORIG_OBS_SEGMENT} } @records]); $db->set(obs_segment => [ map { $_->{OBS_SEGMENT} } @records]); $db->set(orig_obsid => [ map { makeSequence($_) } @records ]); $db->set(obsid => [ map { makeSequence($_, 1) } @records ]); my @exposure = map { $_->{INTEGRATION_TIME} } @records; $db->set(exposure => \@exposure); my @catnum = map { $_->{CATNUM} } @records; $db->set(catnum => \@catnum); my @obs_mode = map { $_->{OPERATION_MODE} } @records; $db->set(operation_mode => \@obs_mode); my @rate_code = map { $_->{RATE_CODE} } @records; $db->set(ratecode => \@rate_code); my @pointing_mode = map { $_->{POINTING_MODE} } @records; $db->set(pointing_mode => \@pointing_mode); my @filename = map { $_->{FILENAME} } @records; $db->set(filename => \@filename); $db->write($dbfile); } # end of body method sub makeSequence { my ($href, $true) = @_; my $key1 = $true ? 'TARGET_ID' : 'ORIG_TARGET_ID'; my $key2 = $true ? 'OBS_SEGMENT' : 'ORIG_OBS_SEGMENT'; sprintf('%08d%03d', $_->{$key1}, $_->{$key2}); }