package SlewProcess; use strict; use English; use Carp; use vars qw(@ISA $VERSION $name $author $date $version @instList $numberOfStreams); @ISA = qw(Module); use ModuleResources; use ModuleUtil; # Declare identity, version, author, date, etc. $name = __PACKAGE__; $VERSION = '0.18'; $version = $VERSION; $author = 'Duncan Law-Green, Richard Saxton,Pedro Rodriguez,Jose Vicente Perea'; $date = '2018-04-27'; # # ChangeLog # ========= # # version 0.18 - 2018-04-27 (PR, JVP) # ------------ # # + Skip move the source list file P*PNS003OMSRLI to product/ if the file does not exist # # version 0.17 - 2016-08-04 (PR, JVP) # ------------ # # + FITS Slew step images produced also in PNG format # + Source detection (eslewsearch) produces source lists per image band (bands: 6,7,8) and 1 merged source list per Slew # # version 0.16 - 2016-07-07 PR # ------------ # # + paste slew products tidy from Finalize module # # version 0.15 - 2010-08-10 DLG # ------------ # + insert filter/mode check for slew processing # # version 0.14 - 2009-06-23 DLG # ------------ # + changed instList to 'all' to correspond with MakeCIF # # version 0.13 - 2009-06-19 DLG # ------------ # + numberOfStreams set to 1 # # version 0.12 - 2009-06-19 DLG # ------------ # + added shared vars to fix module crash # # version 0.11 - 2009-06-15 DLG # ------------ # + continue coding, return success() added # # version 0.1 - 2009-03-18 DLG # ----------- # + coding started # # About Slew Processing # --------------------- # SlewProcess calls the SAS wrapper task 'eslewchain'. eslewchain splits an EPIC slew # into small sections, roughly one degree in length, and generates images and exposure # maps for each section. It makes use of the tasks atthkgen, attcalc, evselect and # eexpmap. # Processing to proceed as follows: # # * Copy slew datafile (SDF) into a clean directory, and point at it with the environment # variable SAS_ODF # # * Run ccfbuild and point to the CCF with SAS_CCF # # * Run odfingest # # * Run epproc in a working directory # # * Set SAS_ATTITUDE environment variable to 'RAF' # # * Run eslewchain in the directory containing the event file produced by epproc # For guide to issues involved in interpreting slew images, see Saxton et al. 2008, A&A 480, 611 # Declare list of instruments this module is interested in @instList = qw(all); # Number of streams sub numberOfStreams { return 1; } # Rules method sub evaluateRules { # Ignore conditions # Ignore if not doing slew processing return ignore() if ( ! $ENV{'PCMS_ISSLEW'} ); # Start conditions start() if complete( module => 'MakeCIF' , instrument => 'all' , stream => 1 ); } # Action method sub performAction { info("Module version number: $version"); # Check for slew dataset here (how??), exit ignore() if not found if ( ! $ENV{'PCMS_ISSLEW'} ) { info("PCMS_ISSLEW is not set. Ignoring SlewProcess."); return ignore(); } info("PCMS_ISSLEW is set. Continuing with SlewProcess."); # Work out exposure ID for PN, MOS1, MOS2 my $pn_exp_id = exposureID(instrument => 'epn', stream => 1 ); my $mos1_exp_id = exposureID(instrument => 'emos1', stream => 1 ); my $mos2_exp_id = exposureID(instrument => 'emos2', stream => 1 ); # Fetch filter and mode, trip exception if not correct for slew processing my $pn_filter = getExposureProperty(instrument => 'epn', exp_id => $pn_exp_id, name => 'filter') || "Inactive" ; info("PN Filter: $pn_filter"); my $mos1_filter = getExposureProperty(instrument => 'emos1', exp_id => $mos1_exp_id, name => 'filter') || "Inactive" ; info("MOS1 Filter: $mos1_filter"); my $mos2_filter = getExposureProperty(instrument => 'emos2', exp_id => $mos2_exp_id, name => 'filter') || "Inactive" ; info("MOS2 Filter: $mos2_filter"); my $pn_mode = getExposureProperty(instrument => 'epn', exp_id => $pn_exp_id, name => 'mode') || "Inactive" ; info("PN Mode: $pn_mode"); my $mos1_mode = getExposureProperty(instrument => 'emos1', exp_id => $mos1_exp_id, name => 'mode') || "Inactive" ; info("MOS1 Mode: $mos1_mode"); my $mos2_mode = getExposureProperty(instrument => 'emos2', exp_id => $mos2_exp_id, name => 'mode') || "Inactive" ; info("MOS2 Mode: $mos2_mode"); if ($pn_filter !~ /^Medium/ && $mos1_filter !~ /^Medium/ && $mos2_filter !~ /^Medium/) { info("Incorrect EPIC filter for slew: $pn_filter | $mos1_filter | $mos2_filter, should be Medium."); info("Ignoring SlewProcess..."); return ignore(); } if ($pn_mode !~ /^(PrimeFullWindow|PrimeLargeWindow|PrimeFullWindowExtended)/ && $mos1_mode !~ /^(PrimeFullWindow|PrimeLargeWindow|PrimeFullWindowExtended)/ && $mos2_mode !~ /^(PrimeFullWindow|PrimeLargeWindow|PrimeFullWindowExtended)/) { info("Incorrect EPIC mode for slew: $pn_mode | $mos1_mode | $mos2_mode, should be PrimeFullWindow || PrimeLargeWindow || PrimeFullWindowExtended."); info("Ignoring SlewProcess..."); return ignore(); } # Run epproc # info("Running epproc on slew sequence"); doCommand( 'epproc' , removetemporaries => 1 , removeintermediategtis => 1 , removeintermediateeventlists => 1 , selectccds => 0 ) or return exception(); # Run eslewchain # SAS task has no parameters in documentation info("Running eslewchain on slew sequence"); doCommand( 'eslewchain' , withpng => 'yes' ) or return exception(); # Run eslewsearch # SAS task has no parameters in documentation info("Running eslewsearch on slew sequence"); doCommand( 'eslewsearch' ) or return exception(); # Set up parameters for slew product tidy ---------------- # Modified for eslewchain-1.4, PCMS-"compliant" filenames my $rootdir = $ModuleResources::Seqdb->{'directories'}{'root'}; info("Sequence root directory: $rootdir"); # move files to intermediate subdir # Does the new eslewchain still create these? # moveFile(source => 'histo.fits', # destination => 'intermediate/histo.fits'); # moveFile(source => 'image.fits', # destination => 'intermediate/image.fits'); # moveFile(source => 'spectrum.fits', # destination => 'intermediate/spectrum.fits'); # moveFile(source => "temp_sp_*", # destination => 'intermediate/'); moveFile(source => "*Badpixels.ds", destination => 'intermediate/') unless ignored( module => 'SlewProcess', stream => 1 ); # Identify output products and assign PCMS-compatible filenames # Attitude file:P*OBX000ATTTSR0000.FITS my $obsid = $ENV{'SAS_RAND_SEED'}; my ($attfile) = glob("$rootdir/P*OBX000ATTTSR0000.ds"); my $attdest = newFile(class => 'product' ,instrument => 'ob' ,content => 'SLEW ATTITUDE FILE' ,format => 'FITS' ); moveFile(source => "$attfile" ,destination => "$attdest") unless ignored( module => 'SlewProcess', stream => 1 ); my $sourcename = sprintf("P%010s",$obsid); doCommand( 'addattribute', set => $attdest , attributename => 'OBJECT' , attributetype => 'string' , stringvalue => "$sourcename" # , attributecomment => '"Object name"' ) unless ignored(module => 'SlewProcess', stream => 1 ); # Single raw events file: P*PNS003SLEVLI0000.FITS my ($rawfile) = glob("$rootdir/*ImagingEvts.ds"); # my ($rawfile) = glob("$rootdir/P*PNS003PIEVLI0SLW.ds"); my $rawdest = newFile(class=>'product' ,instrument => 'epn' ,exp_id => 'S003' ,content => 'SLEW SINGLE RAW EVENT LIST' ,format => 'FITS' ); moveFile(source => "$rawfile" ,destination => "$rawdest") unless ignored( module => 'SlewProcess', stream => 1 ); my $sourcename = sprintf("P%010s",$obsid); doCommand( 'addattribute', set => $rawdest , attributename => 'OBJECT' , attributetype => 'string' , stringvalue => "$sourcename" # , attributecomment => '"Object name"' ) unless ignored( module => 'SlewProcess', stream => 1 ); # filtered event files per step: P*PNS003PIEVLI0*.FITS my $filtfile; my $filtdest; my $filtstep = 0; my @filtlist = glob("$rootdir/P*PNS003PIEVLI0*.ds"); foreach $filtfile (@filtlist) { $filtdest = newFile(class => 'product' ,instrument => 'epn' ,exp_id => 'S003' ,content => 'SLEW STEP FILTERED EVENT LIST' ,format => 'FITS' ,src_num => "$filtstep" # this needs to be in decimal, not hex ); moveFile(source => "$filtfile" ,destination => "$filtdest"); my $sourcename = sprintf("P%010s_%03x",$obsid,$filtstep); doCommand( 'addattribute', set => $filtdest , attributename => 'OBJECT' , attributetype => 'string' , stringvalue => "$sourcename" # , attributecomment => '"Object name"' ); $filtstep++; } # Slew step band exposure map: P*PNS003EXPMAPbiii.FITS # Loop over slew bands my $slewband; my $stepfile; my $stepdest; foreach $slewband ( '6', '7', '8' ) { $filtstep = 0; my @steplist = glob("$rootdir/P*PNS003EXPMAP${slewband}*.ds"); foreach $stepfile (@steplist) { my $stepdest = newFile(class => 'product' , instrument => 'epn' , exp_id => 'S003' , content => 'SLEW STEP EXPOSURE MAP' , format => 'FITS' , src_num => "$filtstep" , band => "$slewband" ); moveFile(source => "$stepfile" ,destination=> "$stepdest"); my $sourcename = sprintf("P%010s_%03x",$obsid,$filtstep); doCommand( 'addattribute', set => $stepdest , attributename => 'OBJECT' , attributetype => 'string' , stringvalue => "$sourcename" # , attributecomment => '"Object name"' ); # Slew footprint ... if ( $slewband == '8' ){ my $slewExpmapFootPrint = newFile(class => 'product' , instrument => 'epn' , exp_id => 'S003' , content => 'SLEW STEP EXPOSURE MAP FOOTPRINT' , format => 'ASCII' , src_num => "$filtstep" , band => "$slewband" ); doCommand( 'slewFootCalc.py' , expMap => $stepdest , outFootprint => $slewExpmapFootPrint ); } # Slew footprint $filtstep++; } } # Slew step band images: P*PNS003IMAGE_biii.FITS # Loop over slew bands my $pngfile ; my $pngdest ; foreach $slewband ( "6", "7", "8" ) { $filtstep = 0; my @steplist = glob("$rootdir/P*PNS003IMAGE_${slewband}*.ds"); foreach $stepfile (@steplist) { my $pngfile = $stepfile ; $pngfile =~ s/ds/png/; my $pngdest = newFile(class => 'product' , instrument => 'epn' , exp_id => 'S003' , content => 'SLEW STEP IMAGE' , format => 'PNG' , src_num => "$filtstep" , band => "$slewband" ); moveFile(source => "$pngfile" ,destination=> "$pngdest"); my $stepdest = newFile(class => 'product' , instrument => 'epn' , exp_id => 'S003' , content => 'SLEW STEP IMAGE' , format => 'FITS' , src_num => "$filtstep" , band => "$slewband" ); moveFile(source => "$stepfile" ,destination=> "$stepdest"); # Set OBJECT header to source step name (Nora's request) my $sourcename = sprintf("P%010s_%03x",$obsid,$filtstep); doCommand( 'addattribute', set => $stepdest , attributename => 'OBJECT' , attributetype => 'string' , stringvalue => "$sourcename" # , attributecomment => '"Object name"' ); $filtstep++; } } # Slew band source lists: P*PNS003OMSRLIb000.FITS ( 1 source list per band ) # Loop over slew bands #my $pngfile ; #my $pngdest ; foreach $slewband ( "6", "7", "8" ) { #$filtstep = 0; my ($stepfile) = glob("$rootdir/P*PNS003OMSRLI${slewband}*.FIT"); #foreach $stepfile (@steplist) { #my $pngfile = $stepfile ; #$pngfile =~ s/ds/png/; #my $pngdest = newFile(class => 'product' # , instrument => 'epn' # , exp_id => 'S003' # , content => 'SLEW STEP IMAGE' # , format => 'PNG' # , src_num => "$filtstep" # , band => "$slewband" # ); # #moveFile(source => "$pngfile" # ,destination=> "$pngdest"); my $stepdest = newFile(class => 'product' , instrument => 'epn' , exp_id => 'S003' , content => 'EPIC OBSERVATION ML SOURCE LIST' , format => 'FITS' #, src_num => "$filtstep" , band => "$slewband" ); if ( fileExists( file => $stepfile ) ){ moveFile(source => "$stepfile" ,destination=> "$stepdest"); } else { info("Slew source list file P*PNS003OMSRLI does not exist for Band $slewband. Skipped."); } # Set OBJECT header to source step name (Nora's request) #my $sourcename = sprintf("P%010s_%03x",$obsid,$filtstep); #doCommand( # 'addattribute', set => $stepdest # , attributename => 'OBJECT' # , attributetype => 'string' # , stringvalue => "$sourcename" # , attributecomment => '"Object name"' # ); #$filtstep++; #} } # Merged source list: P*PNS003OMSSLI0000.FITS ( 1 source list per Slew ) my ($mergedSrcListTemp) = glob("$rootdir/P*PNS003OMSSLI0000.FIT"); my $mergedSrcList = newFile(class => 'product' , instrument => 'epn' , exp_id => 'S003' , content => 'EPIC SUMMARY SOURCE LIST FOR SLEW DATA' , format => 'FITS' #, src_num => "$filtstep" #, band => "$slewband" ); ## Write Extension name (SRCLIST) if it does not exist #if (!hasFITSExtension(file => $mergedSrcListTemp, extension => "SRCLIST")){ # doCommand( # 'addattribute', set => $mergedSrcListTemp # , attributename => 'EXTNAME' # , attributetype => 'string' # , stringvalue => "SRCLIST" # #, attributecomment => '"name of this binary table extension"' # ); #} moveFile(source => "$mergedSrcListTemp" ,destination=> "$mergedSrcList"); # Unfiltered step images: P*PNS003UNFDAT8*FITS $filtstep = 0; my $unffile; my $unfdest; my @unflist = glob("$rootdir/P*PNS003UNFDAT8*.ds"); foreach $unffile (@unflist) { $unfdest = newFile(class => 'product' ,instrument => 'epn' ,exp_id => 'S003' ,content => 'UNFILTERED SLEW STEP IMAGE' ,format => 'FITS' ,src_num => "$filtstep" # this needs to be in decimal, not hex ,band => '8' ); moveFile(source => "$unffile" ,destination => "$unfdest"); # Set OBJECT header to source step name (Nora's request) my $sourcename = sprintf("P%010s_%03x",$obsid,$filtstep); doCommand( 'addattribute', set => $unfdest , attributename => 'OBJECT' , attributetype => 'string' , stringvalue => "$sourcename" # , attributecomment => '"Object name"' ); $filtstep++; } # Tidy: Drop all ds files from root directory my @unlinklist = glob("$rootdir/*.ds"); unlink @unlinklist unless ignored( module => 'SlewProcess', stream => 1 ); # -------------------------------------------------------- # +++ StampKeywords +++ # Import portion of StampKeywords module to run here for slew # Add basic headers to all FITS product files info("Starting StampKeywords subroutine..."); my ( @name, @type, @value, @comment, @withcomment ); # Fetch list of product files my @list = findFile( class => 'product' , 'format' => 'FITS' ); # We really really really want to avoid running addattribute on ACDS products. # This can happen if we restart a post ACDS sequence at a pre ACDs stage and apply --acds_magic=1 @list = grep { $_ !~ /CAX000/} @list; return success() unless @list; # Fetch observation properties my $obs = getObservationProperties(); my $odsver = getOdsVer(); my $odfver = getOdfVer(); # Use any old file to get global properties (like seq id) my $info = fileInfo( class => 'product', name => $list[0] ); # Set values of keywords # Reset OBJECT keyword to 'Slew' for slew sequences # push @name, 'OBJECT'; # push @type, 'string'; # push @value, 'Slew'; # push @comment, 'Object name'; # push @withcomment, 'y'; push @name, 'SEQ_ID'; push @type, 'string'; push @value, $info->{sequence}; push @comment, 'Pipeline sequence'; push @withcomment, 'y'; push @name, 'REVOLUT'; push @type, 'string'; push @value, $obs->{orbit}; push @comment, 'Satellite Revolution Number'; push @withcomment, 'y'; push @name, 'PROCDATE'; push @type, 'string'; push @value, $obs->{procdate}; push @comment, 'Processing date'; push @withcomment, 'y'; push @name, 'PROCREV'; push @type, 'string'; push @value, $obs->{procrevision}; push @comment, 'Processing revision'; push @withcomment, 'y'; push @name, 'PPSVERS'; push @type, 'string'; push @value, $obs->{ppsversion}; push @comment, 'PPS configuration'; push @withcomment, 'y'; push @name, 'SASVERS'; push @type, 'string'; push @value, $obs->{sasversion}; push @comment, 'SAS version'; push @withcomment, 'y'; push @name, 'ODSVER'; push @type, 'string'; push @value, "$odsver"; push @comment, 'ODS version'; push @withcomment, 'y'; push @name, 'ORIGIN'; push @type, 'string'; push @value, 'Leicester/SSC'; push @comment, 'Origin of FITS file'; push @withcomment, 'y'; # Added block to hack OBSERVER keyword name in slews - DLG push @name, 'OBSERVER'; push @type, 'string'; push @value, 'XMM-Newton'; push @comment, 'Observer'; push @withcomment, 'y'; push @name, 'ODFVER'; push @type, 'string'; push @value, sprintf('%03d',$odfver); push @comment, 'ODF_VERSION'; push @withcomment, 'y'; # CONTENT keyword must be last in the list, as we set its value in # the loop push @name, 'CONTENT'; push @type, 'string'; push @comment, 'Contents of file'; push @withcomment, 'y'; # Loop over each file foreach my $file (@list) { next unless fileExists( file => $file ); my $l_info = fileInfo( class => 'product', name => $file ); # Set the other keywords doCommand( 'addattribute', set => $file , attributename => [@name] , attributetype => [@type] , stringvalue => [ @value, uc( $l_info->{content} ) ] , attributecomment => [@comment] ) or return exception(); } info("StampKeywords subroutine complete!"); # -------------------------------------------------------- # Return success success(); } # need to rename output files by SSC band names # get translation table? 1;