Download

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

# Declare identity, version, author, date, etc.
$name    = __PACKAGE__;
$VERSION = '2.22';
$version = $VERSION;
$author  = 'Dean Hinshaw,Duncan John Fyfe,Ian Stewart,Eduardo Ojero,Ed Chapin,Jose Vicente Perea';
$date    = '2017-09-05';

#
# ChangeLog
# =========
#
# Version 2.22 - 2017-09-05 (JVP)
# ------------
#
# + footPrintFinder.py : New EPIC footprint search based on matplotlib contours
#   Contour smoothing fixed to 4
#   intermediate/'EPIC Footprint diag plot' in PNG format
#
# Version 2.21 - 2017-08-22 (JVP)
# ------------
#
# + footPrintFinder.py options:
#   Tolerance value fix to 0.2% (for more precise polygons) and minlength to 0.01 (for small window regions)
#
# Version 2.20 - 2017-08-08 (JVP)
# ------------
#
# + Sky footprint produced from EPIC Exposure Map. Python task added: footPrintFinder.py
#   Intermediate products for the time being
#
# Version 2.19 - 2014-04-21 (JVP)
# ------------
# + Fix typo in line 560 replace '=' by '=>'
#
# Version 2.18 - 2014-04-21 (JVP&EOP)
# ------------
# + Added new parameters attfile and minexptime to etruecolor execution call.
#   New etrucolor was included in xcolorcod-1.28 (xmmsas_20140415_1130).
#   SPR 7201.
#
# Version 2.17 - 2014-03-06 (EOP)
# ------------
#
# + implotrgb is now run always without srclisttab regardless of mlList existence.  
#
# Version 2.16 - 2014-02-20 (EOP)
# ------------
#
# + Call implotrgb to produce an annotated image in PPM format.
#   The PPM plot is generated with a special PGPLOT 5.2.2 driver hacked
#   to render RGB plots. Then, a PNG file is obtained by means of the
#   well known tool 'convert' from ImageMagick. 
#
# Version 2.15 - 2014-01-22 (EC)
# ------------
#
# + Call etruecolor to make 3-colour images (PPS SCR #7166)
#
# Version 2.14 - 2014-01-18 (EC)
# ------------
#
# + Rules modified to handle mosaics
#
# Version 2.13 - 2013-06-11 (EC)
# ------------
#
# + Merge changes from SOC version.
#
# version 2.12.1 - 2011-08-09 EOP
# --------------
# 	
# + GIF replaced by PNG to avoid seg. fault on 64-bit
#
# version 2.12 - 2006-02-21 DJF
# ------------
# 
# + Now derive list of images to emosaic from lists saved by earlier modules.
#   This is so emosaic preserves input image keywords.  these are lost if
#   imweightadd output images are used.
#
# version 2.11 - 2005-11-24 IMS
# ------------
# + Makes use of new parameter --forceuniformkwds of emosaic.
#
# version 2.10 - 2005-11-14 IMS
# ------------
# + Needed to add band => 8 for most of the emosaic outputs.
#
# version 2.09 - 2005-11-14 IMS
# ------------
#
# + Added all-source DS9 region product.
# + Deleted some obsolete code (or rather DJF did in one of the previous 2 versions).
# + Implemented DJF's shortened intermediate file names.
#
# version 2.08 - 2005-11-10 DJF
# ------------
#
# + Failure of implot of EPIC_OBSERVATION_BACKGROUND_MAP was not terminating
#   module. return exception() added.
#
# version 2.07 - 2005-11-09 DJF
# ------------
#
# + info statement to say how many merged images , background maps and exposure maps were found for merging.
#   This will help debug the case where one or more lists are empty.
#
# version 2.06 - 2005-11-02 IMS
# ------------
#
# + Input images to emosaic changed from the exposure-level images to the 'merged' images used for source detection. This has meant some fairly major code rearrangement - images and exp maps are now sought in the same way bkg maps have been from version 2.03.
# + Following on from this: delete the requirement that input images must have flare gtis and be full-frame mode.
#
# version 2.05 - 2005-10-14 IMS
# ------------
#
# + Added 'complete' to the list of methods called from ModuleResources.
#
# version 2.04 - 2005-10-07 RGW
# ------------
#
# + use the correct content keyword when looking for the epic
#   observation ML source list
#
# version 2.03 - 2005-09-20 IMS
# ------------
#
# + Now also makes a mosaic (though without source overlays) of the band 8 background maps. (Note that band 8 bkg maps were not made before ExpDetect v2.04).
#
# version 2.02 - 2005-08-16 RGW
# ------------
#
# + fixed bug calling addattribute
# + changed to use the EPIC product images, not intermediate files
#
# version 2.01 - 2005-07-27 IMS
# ------------
#
# + @instList changed from 'all' to 'epic'.
# + Test on completion of ExpDetect added to evaluateRules.
# + FITS and PNG images are now also made of the mosaiced exposure maps.
# + Source circles added to PNG images.
#
# version 2.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 1.17 - 2004-01-14 (DJF)
# ------------
#
# + Really change dependance on MakeImage to MakeMOSImage and MakePNImage this time
#
# Version 1.16 - 2004-01-14 (DJF)
# ------------
#
# + Changed dependance on MakeImage to MakeMOSImage and MakePNImage
#
# Version 1.15 - 2003-12-09 (DJF)
# ------------
#
# + Adapted doCommand to use anonymous lists for list parameters
# + Changed final addattribute to avoid looping over it.
#
# Version 1.14 - 2002-13-11 (DJF)
# ------------
#
# + implot parameter changes.  Merged plotfile/Device
#
# Version 1.13 - 2002-12-11 (DJF)
# ------------
#
# + Change implot parameter withsrclistset to withsrclisttab (SAS 5.4)
#
# Version 1.12 - 2001-05-31 (DH)
# ------------
#
# + More sophisticated selection of images.  Now use only
#   full frame images with flare gti files.  Still defaults
#   to using everything if no images pass the selection.
#
# Version 1.11 - 2001-05-11 (DH)
# ------------
#
# + Add double quotes to value string in addattribute.
#   Needed because parameters are now lists.
#
# Version 1.10 - 2001-03-16 (DH)
# ------------
#
# + Print out version number in performAction() for
#   tracking purposes.
#
# Version 1.09 - 2001-01-31 (DH)
# ------------
#
# + Bug fixes for version 1.08
#
# Version 1.08 - 2001-01-31 (DH)
# ------------
#
# + Use as input special created images, which
#   results in only the MOS fov being included.
#
# Version 1.07 - 2001-01-10 (DH)
# ------------
#
# + Add ignore rule.
#
# Version 1.06 - 2000-12-15 (DH)
# ------------
#
# + First production version.
#
# Declare list of instruments this module is interested in
@instList = qw(epic);

# Number of streams
sub numberOfStreams
{
    return 1;
}

# Rules method
sub evaluateRules
{
    return ignore()
      if ( allIgnored( module => 'MakeMOSImage' )
        && allIgnored( module => 'MakePNImage' ) );
    start()
      if ( allComplete( module => 'MakeMOSImage' )
        && allComplete( module => 'MakePNImage' )
        && complete(
            module => 'ExpDetect',
            , instrument => 'epic',
            , stream => 1
        ) );
}

# Action method
sub performAction
{
    info("Module version number: $version");

    # get all band 8 images, exp maps and bkg maps.
	info("Searching for components...");

	my @fullImages;
	foreach my $fullImages ( findFile(class => 'intermediate'
			, content => 'raw image list'
			, band => 8
	)){
		push @fullImages , readASCIIFile( name => $fullImages );
	}
	chomp(@fullImages);

	my @fullMaps;
	foreach my $fullMaps ( findFile(class => 'intermediate'
			, content => 'exposure map list'
			, band => 8
	)){
		push @fullMaps ,  readASCIIFile( name => $fullMaps );
	}
	chomp(@fullMaps);

	my @bkgImList;
	foreach my $bkgImList ( findFile(class => 'intermediate'
			, content => 'background map list'
			, band => 8
	)){
		push @bkgImList , readASCIIFile( name => $bkgImList );
	}
	chomp(@bkgImList);

	info('Found: '. scalar(@fullImages) .' merged images , '. scalar(@fullMaps)  .' exposure maps and '. scalar(@bkgImList) .' background maps'  );

    return success() unless (@fullImages && @fullMaps && @bkgImList);

    # Got inputs, now make mosaic image
    my $fitsMosaic = newFile(
        class => 'product'
        , instrument => 'epic'
        , band => 8
        , content => 'EPIC OBSERVATION IMAGE'
    );
    doCommand(
        'emosaic', imagesets => [@fullImages]
        , mosaicedset => $fitsMosaic
        , withexposure => 'N'
        , forceuniformkwds => 'yes'
      )
      or return exception();

    # Now also make mosaic of exposure maps
    my $expmapFitsMosaic = newFile(
        class => 'product'
        , instrument => 'epic'
        , band => 8
        , content => 'EPIC OBSERVATION EXPOSURE MAP'
    );
    doCommand(
        'emosaic', imagesets => [@fullMaps]
        , mosaicedset => $expmapFitsMosaic
        , withexposure => 'N'
        , forceuniformkwds => 'yes'
      )
      or return exception();

    #-------------------------------------------------------------------------
    # Produce the Sky Footprint from the Exposure Map
    my $expmapFootPrint = newFile(
                                  class => 'product'
                                  , instrument => 'epic'
                                  , band => 8
                                  , content => 'EPIC OBSERVATION FOOTPRINT'
                                  , format => 'ASCII'
                                  );
    my $FootPrintDiagPlot = newFile(
                                  class => 'intermediate'
                                  , instrument => 'epic'
                                  , band => 8
                                  , content => 'EPIC Footprint diag plot'
                                  , format => 'PNG'
                                  );

                    my $smoothing = 4;			# Smoothing factor

                    doCommand(
                           'footPrintFinder.py'
                           , infile => $expmapFitsMosaic
			   , outfile => $expmapFootPrint
			   , ds9reg => 'Y'
			   , skycoord => 'Y'
			   , smoothing => $smoothing	# Specifies the number of skipped contour points in the footprint which smooths
							# the polygons contour. smoothing = 1 (default value) is equivalent to include
							# all points in the footprint. smoothing = 2 is equivalent to include only half
							# of the points in each polygon. Rest of points are ignored.
							#
			   , plotting => 'Y'
			   , diagplot => $FootPrintDiagPlot
                           );
    #-------------------------------------------------------------------------

    # Now also make mosaic of background maps
    my $bkgmapFitsMosaic = newFile(
        class => 'product'
        , instrument => 'epic'
        , band => 8
        , content => 'EPIC OBSERVATION BACKGROUND MAP'
    );
    doCommand(
        'emosaic', imagesets => [@bkgImList]
        , mosaicedset => $bkgmapFitsMosaic
        , withexposure => 'N'
        , forceuniformkwds => 'yes'
      )
      or return exception();

# Copy some keywords, as emosaic doesn't do this at the moment
    my @keywords = (
        'INSTRUME', 'BAND', 'DATAMODE', 'TELESCOP'
        , 'OBS_ID', 'DATE-OBS', 'DATE-END', 'OBJECT'
        , 'OBSERVER'
    );
    my @types = (
        'string', 'integer', 'string', 'string', 'string', 'string'
        , 'string', 'string', 'string'
    );
    my @strvalues = ( 'EPIC' );
    my @intvalues=(8);
    my @no=('no') x 9;

    foreach ( @keywords[ 2 .. 8 ] )
    {
        push(
            @strvalues
            , (
                hasFITSKeyword(
                    file => $fullImages[0]
                    , extension => 1
                    , keyword => $_
                )
              )
            ? readFITSKeyword(
                file => $fullImages[0]
                , extension => 1
                , keyword => $_
              )
            : 'UNDEFINED'
        );
    }
    doCommand(
        'addattribute', set => $fitsMosaic
        , attributename => [@keywords]
        , attributetype => [@types]
        , stringvalue => [@strvalues]
        , integervalue => [@intvalues]
      )
      or return exception();
    doCommand(
        'addattribute', set => $expmapFitsMosaic
        , attributename => [@keywords]
        , attributetype => [@types]
        , stringvalue => [@strvalues]
        , integervalue => [@intvalues]
      )
      or return exception();
    doCommand(
        'addattribute', set => $bkgmapFitsMosaic
        , attributename => [@keywords]
        , attributetype => [@types]
        , stringvalue => [@strvalues]
        , integervalue => [@intvalues]
      )
      or return exception();

    # Make graphics images:
    my $gifMosaic = newFile(
        class => 'intermediate'
        , instrument => 'epic'
        , band => 8
        , content => 'IMAGE'
        , 'format' => 'GIF'
    );
    my $pngMosaic = newFile(
        class => 'product'
        , instrument => 'epic'
        , band => 8
        , content => 'EPIC OBSERVATION IMAGE'
        , 'format' => 'PNG'
    );
    my $expmapGifMosaic = newFile(
        class => 'intermediate'
        , instrument => 'epic'
        , band => 8
        , content => 'EXPOSURE MAP'
        , 'format' => 'GIF'
    );
    my $expmapPngMosaic = newFile(
        class => 'product'
        , instrument => 'epic'
        , band => 8
        , content => 'EPIC OBSERVATION EXPOSURE MAP'
        , 'format' => 'PNG'
    );
    my $bkgmapGifMosaic = newFile(
        class => 'intermediate'
        , instrument => 'epic'
        , band => 8
        , content => 'BACKGROUND MAP'
        , format => 'GIF'
    );
    my $bkgmapPngMosaic = newFile(
        class => 'product'
        , instrument => 'epic'
        , band => 8
        , content => 'EPIC OBSERVATION BACKGROUND MAP'
        , format => 'PNG'
    );

    my $ds9SrcRegions = newFile(
        class => 'product'
        , instrument => 'epic'
        , content => 'EPIC SOURCE DS9 REGIONS'
        , format => 'ASCII'
    );

    my $mlList = findFile(
        class => 'product'
        , instrument => thisInstrument
        , content => 'EPIC observation ml source list'
    );
    if (fileExists( file => $mlList ))
    {
        my $tempSrcSet = newFile(
            class => 'intermediate'
            , content => 'Temporary source list'
        );
        doCommand(
            'implot', set => $fitsMosaic
            , device => "$pngMosaic/PNG"
            , withsrclisttab => 'yes'
            , srclisttab => $mlList.':SRCLIST'
            , expression => 'ID_BAND==0 && ID_INST==0'
            , tempset => $tempSrcSet
          )
          or return exception();
        doCommand(
            'implot', set => $expmapFitsMosaic
            , device => "$expmapPngMosaic/PNG"
            , withsrclisttab => 'yes'
            , srclisttab => $mlList.':SRCLIST'
            , expression => 'ID_BAND==0 && ID_INST==0'
            , tempset => $tempSrcSet
          )
          or return exception();
        doCommand(
            'implot', set => $bkgmapFitsMosaic
            , device => "$bkgmapPngMosaic/PNG"
            , withsrclisttab => 'yes'
            , srclisttab => $mlList.':SRCLIST'
            , expression => 'ID_BAND==0 && ID_INST==0'
            , tempset => $tempSrcSet
          )
          or return exception();

        doCommand(
            'slconv'
            , srclisttab => "${mlList}:SRCLIST"
            , expression => 'ID_BAND==0 && ID_INST==0'
            , radiusexpression => 'RATE'
            , radiusstyle => 'auto'
            , withlabels => 'no'
            , colour => 'green'
            , outputstyle => 'ds9'
            , outfilestyle => 'whole'
            , outfile => $ds9SrcRegions
          )
          or return exception();
    }
    else
    {
        info("Source list not found - thus can't add source overlays to png images.");

        doCommand(
            'implot', set => $fitsMosaic
            , device => "$pngMosaic/PNG"
            , withsrclisttab => 'no'
          )
          or return exception();
        doCommand(
            'implot', set => $expmapFitsMosaic
            , device => "$expmapPngMosaic/PNG"
            , withsrclisttab => 'no'
          )
          or return exception();
        doCommand(
            'implot', set => $bkgmapFitsMosaic
            , device => "$bkgmapPngMosaic/PNG"
            , withsrclisttab => 'no'
          )
      or return exception();

    }
#    GIFtoPNG(
#        source => $gifMosaic
#        , destination => $pngMosaic
#      )
#      or return exception();
#    GIFtoPNG(
#        source => $expmapGifMosaic
#        , destination => $expmapPngMosaic
#      )
#      or return exception();
#    GIFtoPNG(
#        source => $bkgmapGifMosaic
#        , destination => $bkgmapPngMosaic
#      )
#      or return exception();

    # Now we're going to make the threecolor image

    my @filteredfiles8 = findFile(class => 'intermediate'
                                  , band => 8
                                  , content => 'image event list'
                                  );
    my @filteredlist8;
    foreach my $file (@filteredfiles8) {
        push @filteredlist8, "${file}:EVENTS";
    }

    my $rgbfileFits = newFile(
                              class        => 'product'
                              , instrument => 'epic'
                              , band       => 8
                              , content    => 'EPIC THREECOLOUR IMAGE'
                              , format     => 'FITS'
                              );

    my $ppmfile = newFile(
                          class            => 'intermediate'
                          , instrument     => 'epic'
                          , band           => 8
                          , content        => 'EPIC THREECOLOUR IMAGE'
                          , format         => 'PPM'
                          );
    
    # Find spacecraft attitude file

    my $attFile=findFile(
                         class             => 'product'
                         , instrument      => 'all' 
                         , content         => 'Attitude time series' 
                         , required        => 'true'
                        );

    doCommand('etruecolor'
              , tablelist                  => \@filteredlist8
              , ppmfile                    => $ppmfile
              , fileset                    => $rgbfileFits
              , attfile                    => $attFile
              , minexptime                 => 500
              ) or return exception();


#    if (fileExists( file => $mlList )){
#       doCommand('implotrgb'
#                 , set                     => $rgbfileFits
#                 , device                  => "$ppmfile/PPM"
#                 , withsrclisttab          => 'yes'
#                 , srclisttab              => $mlList.':SRCLIST'
#                 , expression              => 'ID_BAND==0 && ID_INST==0'
#                ) or return exception();
#    } else {
      doCommand('implotrgb'
                , set                      => $rgbfileFits
                , device                   => "$ppmfile/PPM"
                , withsrclisttab           => 'no'
               ) or return exception();
#    }


    my $pngfile = newFile(
                          class            => 'product'
                          , instrument     => 'epic'
                          , band           => 8
                          , content        => 'EPIC THREECOLOUR IMAGE'
                          , format         => 'PNG'
                         );

    doCommand("convert '$ppmfile' '$pngfile'") or return exception();


    return success();
}
1;