Download

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.17';
$version = $VERSION;
$author  = 'Duncan Law-Green, Richard Saxton,Pedro Rodriguez,Jose Vicente Perea';
$date    = '2016-08-04';

#
# ChangeLog
# =========
#
# 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"'
			  );

		$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"
				       );

		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++;

	    #}

	}

         # 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;