Download

package RGSEvents;
use strict;
use English;
use Carp;
use vars
  qw(@ISA $VERSION $name $author $date $version @instList $numberOfStreams);
@ISA = qw(Module);
use ModuleResources;

$name    = __PACKAGE__;
$VERSION = '4.21';
$version = $VERSION;
$author  = 'Duncan John Fyfe,Dean Hinshaw,Ian Stewart,Ed Chapin,Jose V Perea';
$date    = '2015-11-16';

#
# ChangeLog
# =========
#
# version 4.21 - 2015-11-16 PR, JVP
# ------------
#
# + 'attfilter' : Drift limit modified. tolangles = '5.0*#ARCMIN' ==> '5000.0*#ARCMIN'
#
# version 4.20 - 2014-01-31 EC
# ------------
#
# + add withheliocentriccorr and withsunanglecorr to rgsangles (Mantis 0007171)
#
# version 4.19 - 2013-10-02 EC
# ------------
#
# + Switch selection expressions to LAMBDA,PI from BETA_CORR,PI (Mantis 0007140)
#
# version 4.18 - 2007-01-23 DJF
# ------------
#
# + Changed source selection to PRIMESRC + Brightest EPIC source with FLAG == 0 &&  RATE > rate_cutoff && INDEX != PRIMESRC
# + Where we have and EPIC source list add keywords EPMINRTE and EPRGSRCN to reflect the EPIC  rate cutoff and the 
#     number of EPIC sources which could have been selected by the above expression.
# + Changed to make cross-dispersion histogram for selected RGS sources rather than trying to guess.
# + Added attfilter to create an exposure limited GTI and change call to rgssources to use 'expmedian'..
#
# version 4.17 - 2006-10-25 DJF
# ------------
#
# + Add FILTGRPS keyword to filtered event list.  This record which rgsfilter groups have been applied (rejflags=1|AttGTI=2|hkGTI=4).
#
# version 4.16 - 2006-09-13 DJF
# ------------
#
# + Now make Cross-dispersion histogram for the first one of source number 1 , 3  2 (in that order).
#
# version 4.15 - 2006-09-07 DJF
# ------------
#
# + Added withmlambdacolumn => 'Y' to rgsangles as recommended by Andy Pollock.
#
# version 4.14 - 2006-08-11 DJF
# ------------
#
# + Moved event list and exposure map decleration after the empty HK GTI test.
#
# version 4.13 - 2006-07-28 DJF
# ------------
#
# + Implemented plan B event filtering.  Cut down on GTI's applied until
#   none are left.  If still < thesholf GTI don't so any further processing.
#
# version 4.12 - 2006-07-06 DJF
# ------------
#
# + Test for empty event list moved after ONTIME test. It may not be necessary but belt and braces never hurts.
#
# version 4.11 - 2006-07-01 DJF
# ------------
#
# + Updated parameters to reflect changes to rgsproc-1.24.1
#
# version 4.10 - 2006-06-15 DJF
# ------------
#
# + Use rgsfilter generated ONTIME keyword.  If ONTIME < threshhold do not use filtered event list.
#
# version 4.09 - 2005-11-23 DJF
# ------------
#
# + Xdisp histogram content string altered (to include the 'cross'), also the file name now includes order and source number.
#
# version 4.08 - 2005-11-09 DJF
# ------------
#
# + rgsregions parameter procsrcsexpr had an invalid value
#   causing bad parsing of the command line 
#   was "LABEL==\'WHOLE_FIELD\'" now 'LABEL == "WHOLE_FIELD"'
# + Remove excessinve ) from last evselect expression
#
# version 4.07 - 2005-11-09 DJF
# ------------
#
# + Module now raises an exception if rgssources fails.
#   rather than setting itself to ignored.
#

# version 4.06 - 2005-10-28 DJF
# ------------
#
# + The module now sets itself to ignored when rgssources fails.
#   This is to allow testing of later EPIC and OM modules.
#   while the rgssources problem is worked on.
#
# version 4.05 - 2005-10-28 IMS
# ------------
#
# + Added call to make dispersion histogram as requested by AP.
#
# version 4.04 - 2005-10-17 IMS
# ------------
#
# + Added extra call to rgssources to create the row in the source list which will generate the 'whole-field' spectrum.
# + Removed a lot of commented-out code.
# + Added copyFile to the list of used ModuleResources subs.
#
# version 4.03 - 2005-09-21 IMS
# ------------
#
# + Code was in a funny state - as if I had inadvertently overwritten much of my previous mods. I've tried to put it back in the intended state.
#
# version 4.02 - 2005-09-20 IMS
# ------------
#
# + rgssources now uses the observation-level emldetect source list. This replaces the complicated searching for the best exposure-level list.
#
# version 4.01 - 2005-08-08 IMS
# ------------
#
# + Parameter --withdiagoffset of rgsenergy => 'yes' (recommendation of Andy Pollock of SOC on 5 Aug 2005).
#
# version 4.00 - 2005-05-09 DJF
# ------------
#
# + Add explicit perl module headers.  Previously these were supplied
#   at compile time.  This will make debugging and extending the modules
#   through additional perl libraries easier.
#
# + Code layout made more uniform with perltidy
# + Standerdized date format (ccyy-mm-dd)
# + Standerdized author list to use comma separator
# + Make use of perl $VERSION magic.  Now $Version = version = ''
##
# Version 3.23 - 15-Mar-2004 (DJF)
# -------------------------------
#
# + reverted rgssources:attstyle=expmedian changed to median
#   We are not yet producing a necessary Attitude data set for this to work.
#
# Version 3.22 - 04-Mar-2004 (DJF)
# -------------------------------
#
# + rgscources:attstyle=median changed to expmedian
#
# Version 3.21 - 24-Feb-2004 (DJF)
# -------------------------------
#
# evlistcomb, change rgsdatamodes value 'HIGH TIME RESOLUTION' to 'HIGHTIMERESOLUTION'
# See SSC-SPR-3256
#
# Version 3.20 - 21-Feb-2004 (DJF)
# -------------------------------
#
# + Accidentally left NEXT_TO_CCD_BORDER in rgsfilter:rejflag
#
# Version 3.19 - 21-Feb-2004 (DJF)
# -------------------------------
#
# + Changed rgsfilter rejflags.  Replaced depreciated  NEXT_TO_CCD_BORDER
#   with ON_NODE_INTERFACE and ON_WINDOW_BORDER
#
# Version 3.18 - 20-Feb2004 (DJF)
# -------------------------------
#
# + Explicitly pass rgsdatamodes parameters to evlistcomb to overcome
#   bug with default values.
#
# Version 3.17 - 20-Feb2004 (DJF)
# -------------------------------
#
# + Updated rgssources parameter, atthkset => medianset
#
# Version 3.16 - 10-Dec-2003 (DJF)
# -------------------------------
#
# + Adapted doCommand to use anonymous lists for list parameters.
#
# Version 3.15 - 11-Apr-2003 (DJF)
# -------------------------------
#
# + Add EXPIDSTR to flare background via addattribute
#
# Version 3.14 - 11-Nov-2002 (DJF)
# -------------------------------
#
# + Added writedss => N and updateexposure => N to flare background
#   creating evselect
#
# Version 3.13 - 4-Nov-2002 (DJF)
# -------------------------------
#
# + Added region X & Y axis to background timeseries creation to supress
#   an error message.
#
# Version 3.12 - 31-Oct-2002 (DJF)
# -------------------------------
#
# + Added exception call for background timeseries creation errors
#
# Version 3.11 - 31-Oct-2002 (DJF)
# -------------------------------
#
# + Added RGS flare background timeseries
#
# Version 3.10 - 04-July-2002 (DJF)
# -------------------------------
#
# + rgssources attstyle=mean changed to attstyle=median
#
# Version 3.09 - 16-Apr-2002 (DH)
# -------------------------------
#
# + Trap case where final event list is empty, and don't do
#   any further processing.
#
# Version 3.08 - 12-Mar-2002 (DH)
# -------------------------------
#
# + Set rgssources enablefilter option to be true in all cases.
#
# Version 3.07 - 07-Mar-2002 (DH)
# -------------------------------
#
# + Add FLAG==0 to source selection expression for rgsregions.
#
# Version 3.06 - 25-Feb-2002 (DH)
# -------------------------------
#
# + Turn on source confusion checking in rgssources.
#
# Version 3.05 - 19-Feb-2002 (DH)
# -------------------------------
#
# + Stop processing before rgsfilter call if rgs hk gti file is empty.
#
# Version 3.04 - 06-Feb-2002 (DH)
# -------------------------------
#
# + Change evaluateRules so this module depends on InstrumentHK for this
#   exposure.
#
# Version 3.03 - 06-Feb-2002 (DH)
# -------------------------------
#
# + Bug fixes for 3.02
#
# Version 3.02 - 05-Feb-2002 (DH)
# -------------------------------
#
# + Change priorities on which EPIC source list to use.  Now all MOS imaging modes
#   have priority over PN full frame modes, whereas previously the PN full frame
#   had priority over MOS large and small window.
# + Updates to bring in line with rgsproc 1.3 .
#
# Version 3.01 - 24-Oct-2001 (DH)
# -------------------------------
#
# + Bug fixes for version 3.00 .
#
# Version 3.00 - 19-Oct-2001 (DH)
# -------------------------------
#
# + Rework to bring in line with rgsproc 0.107, and the new
#   versions of associated rgs tasks.
#
# Version 2.21 - 1-Oct-2001 (DH)
# -------------------------------
#
# + Replace dslatts call with the hasFITSExtension function.
#
# Version 2.20 - 15-Aug-2001 (DJF)
# -------------------------------
#
# + Add fudge for rgssources.  v 5.2.3 expects the exposure id as an integer the leading S is hardcoded into the task.
#   It does not handle unsheduled exposures.
#
# Version 2.19 - 13-Aug-2001 (DJF)
# -------------------------------
#
# + Removed redundant evselect filtering before call to rgssources.  The filtering is done by rgssources.
#
# Version 2.18 - 09-Aug-2001 (DJF)
# -------------------------------
#
# + Amended parameters passed to rgssources to fit with v 5.2
#
# Version 2.17 - 29-May-2001 (DJF)
# -------------------------------
#
# Removed filtering on band 1 from evselect.
# Added updateexposure=>'no' to evselect
#
# Version 2.16 - 21-May-2001 (DJF)
# -------------------------------
#
# + Added  'primestyle=>brightest' to rgssources
#
# Version 2.15 - 18-May-2001 (DH)
# -------------------------------
#
# + Remove rgsoffset call, as the output files
#   never get used.
#
# Version 2.0 - 01-May-2001 (DJF)
# -------------------------------
#
# + Initial Version. Change required by SAS 5.1
#
# Version 1.13 - 2001-03-21 (DH)
# ------------
#
# + Filter event lists with GTI for good attitude
#   data.
#
# Version 1.12 - 2001-03-16 (DH)
# ------------
#
# + Print out version number in performAction() for
#   tracking purposes.
#
# Version 1.11 - 2001-03-12 (DH)
# ------------
#
# + Change from using 'rgsregion' and 'rgsbackreg' to 'rgsregions'.
#
# Version 1.10 - 2001-02-01 (DH)
# ------------
#
# + Change rate cut in rgssources from 0.4 to 0.2 .
#
# Version 1.09 - 2001-02-01 (DH)
# ------------
#
# + Change rate cut in rgssources from 0.05 to 0.4 .
#
# Version 1.08 - 2001-01-31 (DH)
# ------------
#
# + Bug fixes for version 1.07
#
# Version 1.07 - 2001-01-31 (DH)
# ------------
#
# + Expand RGS fov from 2 acrmins to 5 arcmins.
#   Arrange evselect and rgssources calls so that the brightess source
#   in the RGS fov always gets a spectrum.  Result is that only sources
#   in the RGS fov make it into the RGS srouce list.
#
# Version 1.06 - 2001-01-26 (DH)
# ------------
#
# + If there is a suitable EPIC source list, use sources in the
#   RGS fov.  Do not force a spectra for the brightest source.  If
#   there is no suitable EPIC source list, take the pointing position
#   as the only source.
#
# Version 1.05 - 2001-01-24 (DH)
# ------------
#
# + Check for existance of epic source list before trying to use it.
#
# Version 1.04 - 2000-12-18 (DH)
# ------------
#
# Declare instruments of interest
@instList = qw(rgs1 rgs2);

# Number of Streams
sub numberOfStreams
{
    return numberOfExposures();
}

# Rules evaluated to determine when this modules can run.
sub evaluateRules
{

    # If upstream module has been ignored, so if this one
    return ignore()
      if ignored(
        module => 'ExpChooser'
        , instrument => thisInstrument
        , stream => thisStream
      );

    #
    return start()
      if complete(
        module => 'GlobalHK'
        , instrument => 'all'
        , stream => 1
      )
      and complete(
        module => 'InstrumentHK'
        , instrument => thisInstrument
        , stream => 1
      )
      and complete(
        module => 'ExpChooser'
        , instrument => thisInstrument
        , stream => thisStream
      )
      and allComplete( module => 'ExpDetect' );
}

# The guts of the module
sub performAction
{
    info("Module version number: $version");
    my $srcSelectionExpression;
	my @process_source;

    # Work out which exposure this stream maps on to
    my $exp_id = exposureID(
        instrument => thisInstrument
        , stream => thisStream
    );
    info("Exposure ID: $exp_id");

    # Fetch instrument mode (for info. only)
    my $mode = getExposureProperty(
        exp_id => $exp_id
        , name => 'mode'
    );
    info("Instrument mode: $mode");

#
# Get list of RGS event files to be processed.
#
    # Find event files for this exposure
    my @evFiles = findFile(
        class => 'ODF'
        , instrument => thisInstrument
        , exp_id => $exp_id
        , content => '*events'
    );

    # Return immediately if there are no event files
    unless (@evFiles)
    {
        info("No event files found");
        return success();
    }

#
# Get attitude history file
#
    my $attFile = findFile(
        class => 'product'
        , instrument => 'all'
        , content => 'Attitude time series'
        , required => 'Y'
    );

	# Create an exposure limited attitude GTI.
	# Need to construct a 6 character instexpid string for attfilter.
	my $instexpid = thisInstrument;
	$instexpid =~ /([12])/;
	$instexpid = "R$1$exp_id";

	my $expAttGTI = newFile(
		class => 'intermediate'
        , instrument => thisInstrument
		, exp_id => $exp_id
        , content => 'Exposure Attitude GTI'
	);

	# filtertype ass rgsproc
	# tolangles: rgsproc has a parameter driftlimit which is converted internally to a tolangles entry of "float(X)*#ARCMIN"
	# driftlimit=float(X) becomes
	doCommand('attfilter'
		,instexpid => $instexpid
		,attset => $attFile
		,gtitable => "$expAttGTI:STDGTI"
		,filtertype => 'cone'
		,tolangles => '5000.0*#ARCMIN'
	) or return exception();
#
# Get Good Time Interval
#
    my $goodAttGTI = findFile(
        class => 'intermediate'
        , instrument => 'all'
        , content => 'Attitude GTI'
        , required => 'Y'
    );

#
# Find observation-level EPIC Source list
#

    my $epicList = findFile(
        class => 'product'
        , instrument => 'epic'
        , content => 'EPIC observation ml source list'
    );
	my $haveEpicList =  fileExists(file => $epicList);

# Check that the epic source list exists.  If not, just use pointing position.
    my $srcFile = newFile(
        class => 'product'
        , instrument => thisInstrument
        , exp_id => $exp_id
        , content => 'RGS source list'
    );
	my $primesrc;
	my @rgssources = ( instexpid => $evFiles[0]
		, filemode => 'create'
		, medianset => $attFile
		, srclist => $srcFile
		, expmediantable => "$expAttGTI:STDGTI"
		, attstyle => 'expmedian'
		, primestyle => 'auto'
		, doconfusion => 'Y'
		, enablefilter => 'Y'
		, flagepicsrcoutoffov => 'Y'
	);
	if ( $haveEpicList ) 
	{
		push @rgssources , withepicset => 'Y' , epicset => $epicList.":SRCLIST";
	}
    else
    {
        info( "No suitable EPIC source list found to supply source positions");
        info("Using pointing position instead");
		push @rgssources ,  withepicset => 'N';
    }

	doCommand( 'rgssources' , @rgssources )
		or return exception()
	;
	my @srcindex;
	my $rate_cutoff = 0.2;

	( $srcSelectionExpression , @srcindex ) = ModuleUtil::select_rgssources( $srcFile , 'SRCLIST' , $haveEpicList , $rate_cutoff );
	
#
# Generate RGS source list
#

    my $wholeFieldSrcFile = newFile(
        class => 'intermediate'
        , instrument => thisInstrument
        , exp_id => $exp_id
        , content => 'RGS src list with whole field'
    );
    copyFile(source => $srcFile, destination => $wholeFieldSrcFile);
    doCommand(
        'rgssources'
        , srclist => "${wholeFieldSrcFile}:SOURCES"
        , filemode => 'modify'
        , addusersource => 'yes'
        , label => 'WHOLE_FIELD'
        , positionstyle => 'wrtatt'
        , deltadisp => 0.0
        , deltaxdsp => 0.0
        , process => 'no'
        , bkgexclude => 'no'
      )
      or return exception();

#
# Process Events on a per CCD basis
#
    my @evList;
    foreach my $evFile0 (@evFiles)
    {

        # Find CCD number
        my $ccd = readFITSKeyword(
            file => $evFile0
            , extension => 2
            , keyword => "CCDID"
        );
        info("Processing CCD $ccd");
        my $evFile1 = newFile(
            class => 'intermediate'
            , instrument => thisInstrument
            , exp_id => $exp_id
            , ccd => $ccd
            , content => 'Intermediate events'
            , level => 1
        );

        # Run rgsframes
        #
        doCommand(
            'rgsframes'
            , set => $evFile0
            , ccdset => $evFile1
          )
          or return exception();

        # Run rgsenergy
        #
        doCommand(
            'rgsenergy'
            , ccdset => $evFile1
            , withdiagoffset => 'yes'
          )
          or return exception();

        # Run rgsbadpix
        #
        doCommand( 'rgsbadpix', ccdset => $evFile1 , keepcool => 'Y' )
          or return exception();

        # Run rgsevents
        #
        doCommand( 'rgsevents', ccdset => $evFile1 ), or return exception();
        push( @evList, $evFile1 );
    }

#
#    Merge Event Lists
#
    my @mainattributes = (
        "CCDOCB", "SOURCEID", "DATE-OBS", "DATE-END"
        , "DATATYPE", "TSTART", "TSTOP", "TELAPS"
        , "XMMEA_RG"
    );
    my @othertables = (
        "STDGTI", "BADPIX0", "BADPIX1", "REJPIX0"
        , "REJPIX1", "EXPOSURE"
    );
    my @rgsimgcolnames = (
        "TIME", "FLAG", "BETA", "XDSP", "CHIPX", "CHIPY"
        , "PHA", "SHAPE", "GRADE", "PI"
    );
    my @rgsimgcoltypes = (
        "double", "int32", "single", "single", "int16", "int16"
        , "int16", "int8", "int8", "int16"
    );
    my $combList = newFile(
        class => 'intermediate'
        , instrument => thisInstrument
        , exp_id => $exp_id
        , content => 'Event list'
    );
    doCommand(
        'evlistcomb', eventsets => [@evList]
        , instrument => 'rgs'
        , imagingset => $combList
        , mainattributes => [@mainattributes]
        , othertables => [@othertables]
        , rgsimgcolnames => [@rgsimgcolnames]
        , rgsimgcoltypes => [@rgsimgcoltypes]
        , rgsdatamodes => [ 'SPECTROSCOPY', 'HIGHTIMERESOLUTION' ]
      )
      or return exception();

#
# Process Sources
#
#
# Run rgsangles
#
    doCommand(
        'rgsangles'
        , mergedset => $combList
        , srclist => $srcFile
        , betabinning => 'binSize'
        , betabinref => 3.578524e-2
        , betabinwidth => 1.208e-5
        , nbetabins => 3400
        , nxdispbins => 170
        , xdispbinning => 'binSize'
        , xdispbinref => -9.126e-4
        , xdispbinwidth => 1.08e-5
	, withmlambdacolumn => 'Y'
	, withheliocentriccorr => 'Y'
	, withsunanglecorr => 'Y'
      )
      or return exception();

#
# Do exposure/event filtering plus much much more
#
    my $hkgtiFile = findFile(
        class => 'intermediate'
        , instrument => thisInstrument
        , content => 'HK GTI'
    );

    unless ( numberFITSRows( file => $hkgtiFile, extension => 'STDGTI' ) )
    {
        info(
		"RGS HK GTI file is empty.  No more processing will be done."
        );
        return success();
    }
    my $filteredEventList = newFile(
        class => 'intermediate'
        , instrument => thisInstrument
        , exp_id => $exp_id
        , content => 'FILTERED EVENT LIST'
    );

    my $expFile = newFile(
        class => 'product'
        , instrument => thisInstrument
        , exp_id => $exp_id
        , content => 'RGS EXPOSURE MAP'
    );

    my @rejflags = (
        'BAD_SHAPE', 'ON_BADPIX'
        , 'NEXT_TO_BADPIX', 'BELOW_ACCEPTANCE'
        , 'ON_NODE_INTERFACE', 'ON_WINDOW_BORDER'
    );
	info("Filtering with rejection flags, Attitude GTI and HK GTI.");

	my ($rejflags_f , $goodAttGTI_f , $hkgtiFile_f) = (1 , 2 , 4);
	my $rgsfilter_f = $rejflags_f | $goodAttGTI_f |  $hkgtiFile_f  ;


    doCommand(
        'rgsfilter'
        , mergedset => $combList
        , evlist => $filteredEventList
        , rejflags => [@rejflags]
        , auxgtitables => [ $expAttGTI ,$goodAttGTI, $hkgtiFile ]
        , withexpmaps => 'Y'
        , withcombmap => 'Y'
        , expimageset => $expFile
      )
      or return exception();


# Use ONTIME to decide whether to use the unfiltered/filtered event list.
		my $ontime_threshold = 1000;
		my $ontime = readFITSKeyword( file => $filteredEventList
			, extension => "EVENTS"
			, keyword => "ONTIME"
		);

		if ( $ontime < $ontime_threshold)
		{
			$rgsfilter_f = $rejflags_f | $goodAttGTI_f;
			ppd(id => "000014", data => { ontime => $ontime , threshold => $ontime_threshold } );
			info("Filtering with rejection flags, Attitude GTI and HK GTI leaves < 1000s ONTIME.");
			info("Filtering with rejection flags and Attitude GTI.");
			unlink ( $filteredEventList );
			doCommand(
				'rgsfilter'
				, mergedset => $combList
				, evlist => $filteredEventList
				, rejflags => [@rejflags]
				, auxgtitables => [ $expAttGTI , $goodAttGTI ]
				, withexpmaps => 'Y'
				, withcombmap => 'Y'
				, expimageset => $expFile
			) or return exception();
			$ontime = readFITSKeyword( file => $filteredEventList
				, extension => "EVENTS"
				, keyword => "ONTIME"
			);

			if ( $ontime < $ontime_threshold)
			{
				$rgsfilter_f = $rejflags_f;
				ppd(id => "000015", data => { ontime => $ontime , threshold => $ontime_threshold } );
				info("Filtering with rejection flags and Attitude GTI leaves < 1000s ONTIME.");
				info("Filtering with rejection flags.");
				unlink ( $filteredEventList );
				doCommand(
					'rgsfilter'
					, mergedset => $combList
					, evlist => $filteredEventList
					, rejflags => [@rejflags]
					, auxgtitables => [ $expAttGTI ]
					, withexpmaps => 'Y'
					, withcombmap => 'Y'
					, expimageset => $expFile
				) or return exception();
				$ontime = readFITSKeyword( file => $filteredEventList
					, extension => "EVENTS"
					, keyword => "ONTIME"
				);
				
				if ($ontime  < $ontime_threshold)
				{
					$rgsfilter_f = 0;
					ppd(id => "000016", data => { ontime => $ontime , threshold => $ontime_threshold } );
					info("Filtering with rejection flags leaves < 1000s ONTIME.");
				}
			}
		}

		# Record the filter selection in several places.
		info("ONTIME=$ontime");
		info("FILTGRPS=$rgsfilter_f");
		setExposureProperty( instrument => thisInstrument , exp_id => $exp_id , name => 'filtgrps' , value => $rgsfilter_f );

		# Add the filter flag to the event list.
		doCommand(
			'addattribute', set =>  $filteredEventList
			, attributename => 'FILTGRPS'
			, attributetype => 'integer'
			, attributecomment => "\"\\\"rgsfilter groups applied (rejflags=1|AttGTI=2|hkGTI=4)\\\"\""
			, integervalue => $rgsfilter_f
		);

		# Stop here if we don't have enough ONTIME.
		if ($ontime  < $ontime_threshold)
		{
			info("Filtering with rejection flags < 1000s GTI.");
			info("Ignoring this exposure.");
			return success();
		}
		my $finalEventList = newFile(
			class => 'product'
			, instrument => thisInstrument
			, exp_id => $exp_id
			, content => 'RGS EVENT LIST'
		);
		copyFile( source => $filteredEventList , destination => $finalEventList );

# If the event list is empty, don't do any more processing.
    return success()
      if ( numberFITSRows( file => $finalEventList
        , extension => 'EVENTS' ) == 0);
#
# Process Regions
#
    doCommand(
        'rgsregions'
        , procsrcsexpr => $srcSelectionExpression
        , exclsrcsexpr => $srcSelectionExpression
        , setflags => 'Y'
        , evlist => $finalEventList
        , srclist => $srcFile
      )
      or return exception();
    doCommand(
        'rgsregions'
        , srclist => $wholeFieldSrcFile
        , procsrcsexpr => 'LABEL == "WHOLE_FIELD"'
        , xpsfabove => 100
        , xpsfbelow => 100
        , xpsfexcl => 98
        , setflags => 'Y'
        , evlist => $finalEventList
      )
      or return exception();

#
# Generate flare background time series
    my $flarebkg = newFile(
        class => 'product'
        , instrument => thisInstrument
        , exp_id => $exp_id
        , content => 'RGS FLARE BACKGROUND TIMESERIES'
    );
    my $bgtable = uc(thisInstrument) . "_BACKGROUND";
    doCommand(
        'evselect', table => $finalEventList
        , timebinsize => 100
        , withrateset => 'Y'
        , rateset => $flarebkg
        , makeratecolumn => 'Y'
        , maketimecolumn => 'Y'
        , expression =>
"(CCDNR==9) && (REGION(${srcFile}:$bgtable,M_LAMBDA,XDSP_CORR))"
        , writedss => 'N'
        , updateexposure => 'N'
      )
      or return exception();
    doCommand(
        'addattribute', set => $flarebkg
        , attributename => 'EXPIDSTR'
        , attributetype => 'string'
        , stringvalue => "$exp_id"
    );

    # Create the dispersion histogram:
	foreach my $srcnum ( @srcindex )
	{
		my $src1RegionExtension = uc(thisInstrument) . "_SRC${srcnum}_ORDER_1";
		if (!hasFITSExtension(
			file => $srcFile
			, extension => $src1RegionExtension))
		{
			info("Can't find extension $src1RegionExtension in source list $srcFile");
		}
		else
		{
			my $histogram = newFile(
				class => 'product'
				, instrument => thisInstrument
				, exp_id => $exp_id
				, src_num => $srcnum
				, order => 1
				, rgsorder => 1
				, content => 'RGS CROSS-DISPERSION HISTOGRAM'
			);
			doCommand(
				'evselect', table => $finalEventList
				, expression => "REGION(${srcFile}:${src1RegionExtension},M_LAMBDA,PI)"
				, filtertype => 'expression'
				, histogramset => $histogram
				, histogramcolumn => 'XDSP_CORR'
				, histogrambinsize => 1.0800000382e-05
			) or return exception();
			ppd( id => "000025", data => { srcnum => $srcnum });
		}
	}

#
    return success();
}


1;