Download

package OMMosaic;
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.30';
$version = $VERSION;
$author="Duncan John Fyfe, Duncan Law-Green, Eduardo Ojero, Ed Chapin";
$date="2013-06-11";

#
# ChangeLog
# =========
#
# Version 2.30 - 2013-06-11 (EC)
# ------------
#
# + Merge changes from SOC version.
#
# Version 2.29 - 2012-06-15 (DLG)
# ------------
#
# + Add {Partial|Full} Frane Engineering Mode PFENG2, FFENG2 to list of OMMosaic modes
#
# Version 2.28 - 2012-05-02 (DLG)
#
# + Eliminate use of GIF bitmaps
#
# ------------
#
# Version 2.27.1 - 2011-08-09 EOP
# --------------
#
# + Removed creation of GIF to avoid crashing on 64-bit. PNG file is created directly and GIF to PNG transformation is removed.
#
# Version 2.27 - 2009-05-01 (DLG)
#
# + explicitly set mincorr=0 per SRR's suggestion
#
# ------------
#
# Version 2.26 - 2009-05-01 (DLG)
#
# - Remove exposure parameter (not required in SAS 9)
#
# ------------
#
# Version 2.25 - 2005-09-13 (RGW)
#
# + shortened intermediate filenames
#
# ------------
#
# Version 2.24 - 2004-01-14 (DJF)
# ------------
#
# + Updated evaluateRules.  The module was not ignoring itself properly.  
#
# Version 2.23 - 2003-12-10 (DJF)
# ------------
#
# + Adapted doCommand to use anonymous lists for list parameters
#
# Version 2.22 - 2002-12-13 (DJF)
# ------------
#
# + implot parameter changes.  Merged plotfile/Device
#
# Version 2.21 - 2002-12-11 (DJF)
# ------------
#
# + Change implot parameter withsrclistset to withsrclisttab (SAS 5.4)
#
# Version 2.20 - 2002-03-11 (DJF)
# ------------
#
# + Amended to look for exposure from rudi-5 side windows if we are missing the central image.
#
# Version 2.19 - 2002-02-22 (DH)
# ------------
# 
# + Minor bug fix.  If statement had => instead of >= .
#
# Version 2.18 - 2002-02-20 (DFJ)
# ------------
# 
# + Removed 100000 second limit in module.  
# 
# Version 2.17 - 2002-01-24 (DFJ)
# ------------
# 
# + Fixed logic for totaling duration
# + Added if/then to deal with exposure times outside of ommosaic task limits
# 
#
# Version 2.20 - 2002-03-11 (DJF)
# ------------
#
# + Amended to look for exposure from rudi-5 side windows if we are missing the central image.
#
# Version 2.19 - 2002-02-22 (DH)
# ------------
# 
# + Minor bug fix.  If statement had => instead of >= .
#
# Version 2.18 - 2002-02-20 (DFJ)
# ------------
# 
# + Removed 100000 second limit in module.  
# 
# Version 2.17 - 2002-01-24 (DFJ)
# ------------
# 
# + Fixed logic for totaling duration
# + Added if/then to deal with exposure times outside of ommosaic task limits
# 
# Version 2.20 - 2002-03-11 (DJF)
# ------------
#
# + Amended to look for exposure from rudi-5 side windows if we are missing the central image.
#
# Version 2.19 - 2002-02-22 (DH)
# ------------
# 
# + Minor bug fix.  If statement had => instead of >= .
#
# Version 2.18 - 2002-02-20 (DFJ)
# ------------
# 
# + Removed 100000 second limit in module.  
# 
# Version 2.17 - 2002-01-24 (DFJ)
# ------------
# 
# + Fixed logic for totaling duration
# + Added if/then to deal with exposure times outside of ommosaic task limits
# 
# Version 2.16 - 2002-01-23 (DFJ)
# ------------
# 
# + Added determination of total exposure and passing of it to ommosaic task
# 
# 
# Version 2.15 - 2001-12-17 (DFJ)
# ------------
# 
# + Changed full frame sky image context strings to get around
#   problem with 'too long' intermedaite file names.
# 
# Version 2.14 - 2001-12-04 (DFJ)
# ------------
# 
# + Added word MOSAIC to prtoduct content strings
# 
# Version 2.13 - 2001-12-03 (DFJ)
# ------------
# 
# + Added condition to stop mosaicing of single ENG2 or ENG4 images
# 
# Version 2.12 - 2001-11-29 (DFJ)
# ------------
# 
# + Fixed and changed evaluate rules.  There need be no dependance on OMFastAnalyse
# 
# Version 2.11 - 2001-11-29 (DFJ)
# ------------
# 
# + Corrected grouping of images. The end conditions meant the 
#   last image got missed.
# 
# Version 2.10 - 2001-11-28 (DFJ)
# ------------
# 
# + Added creation of PNG images from mosaics
# 
# Version 2.09 - 2001-11-28 (DFJ)
# ------------
# 
# + Corrected osw to osw_id in product filename creation
# 
# Version 2.08 - 2001-11-28 (DFJ)
# ------------
# 
# + Removed debugging code.
# + Fixed naming of mosaic products
# + Removed some of the excessive log output
# 
# Version 2.07 - 2001-11-28 (DFJ)
# ------------
# 
# + added debugging code to help track a problem with the per filter processing 
# 
# Version 2.06 - 2001-11-28 (DFJ)
# ------------
# 
# + Fixing per filter processing
# 
# Version 2.05 - 2001-11-28 (DFJ)
# ------------
# 
# + Fix grouping of images prior to mosaicing 
# 
# Version 2.04 - 2001-11-28 (DFJ)
# ------------
# 
# + Correct reading of ASCII files containing image details
# 
# Version 2.03 - 2001-11-27 (DFJ)
# ------------
# 
# + Correct usage of readASCIIFile
# 
# Version 2.02 - 2001-11-27 (DFJ)
# ------------
# 
# + Fix evaluateRules dependence on OMImageAnalyse
# 
# Version 2.01 - 2001-11-26 (DFJ)
# ------------
# 
# + Added new product content strings
# + Changes to accomodate output from OMImageAnalyse of a single ENG2 mode
#
# Version 2.00 - 2001-11-26 (DFJ)
# ------------
#
# + Major rearangement to accomodate per filter and per mode products.
#   This incorporates new rules for OM products devised enhance visibility
#   of products from different OM modes
# + OMImageAnalyse now genererates ASCII lists containing Product file, mode and filter
#   information.  These are used too define and control what mosaiced images are produced.
#
# Version 1.12 - 2001-11-07 (DFJ)
# ------------
#
# + Changed evaluaterules to ignore if all OMImgAnalyse and 
#   OMFastAnalyse streams are ignored
#
# Version 1.11 - 2001-11-06 (DFJ)
# ------------
#
# + Change so module is flagged as ignored on failure of ommosaic task.
#   This is a temporary 'fix' to overcome a buggy ommosaic and allow 
#   testing of the rest of the pipeline
#
# Version 1.10 - 2001-11-05 (DFJ)
# ------------
#
# + Changed to use skyimage which s what ommosaic requires.
#
# Version 1.09 - 2001-11-05 (DFJ)
# ------------
#
# + Added return exception for when ommosaic task fails.
#
# Version 1.08 - 2001-11-05 (DFJ)
# ------------
#
# + Fix selection of osw.  Was failing to recognize 0 as a valid osw.
#
# Version 1.07 - 2001-11-02 (DJF)
# ------------
#
# + Change to logic.  Generate up to three mosaiced images (Rudi5+EN2 , EN4 and FM) rather than 
# + one of three
#
# Version 1.06 - 2001-11-02 (DJF)
# ------------
#
# + Added test for imInfo{'osw'}.  This was not the problem.
#
# Version 1.05 - 2001-11-01 (DJF)
# ------------
#
# + More log details.  Still trying to find the source of a bug.
#
# Version 1.04 - 2001-11-01 (DJF)
# ------------
#
# + Removed check for imInfo{'osw'}. Looks like it isn't propperly null.
# + Left in check for imgIngo('osw_id'}.  Let's see if that works.
#
# Version 1.03 - 2001-11-01 (DJF)
# ------------
#
# + Output extra information to logs
#
# Version 1.02 - 2001-10-31 (DJF)
# ------------
#
# + Output extra information to logs
#
# Version 1.01 - 2001-10-31 (DJF)
# ------------
#
# + Change determination of osw to account for different sources (osw or osw_id)
#
# Version 1.00 - 2001-10-22 (DJF)
# ------------
#
# + Initial version

# Declare list of instruments this module is interested in
@instList=qw(om);

# Number of streams
sub numberOfStreams{ return 1; }

sub evaluateRules {

	# Start conditions
	return ignore() if ignored(module => 'OMgetFlat'
		,stream => 1
	);

	return ignore() if allIgnored(module=>'OMImageAnalyse'
		,instrument => thisInstrument
	);

	start()
		if allComplete(module => 'OMImageAnalyse'
			,instrument => thisInstrument
	);
}

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

	# OM modes are: USER , RUDI5_LR , RUDI5_HR , ENG2 , PFENG2, FFENG2, ENG4 and FAST
	# We do not Mosaic FAST images

	# Modes written by OMImageAnalyse
	my ($USER,$RUDI5_LR,$RUDI5_HR,$ENG2,$PFENG2,$FFENG2,$ENG4) = ('USER','RUDI5_LR','RUDI5_HR','ENG2','PFENG2','FFENG2','ENG4');

	# Output Modes used by OMMosaic (we don't generate High Resoultion RUDI5 mosaics
	my $MosaicModes = [$USER,$RUDI5_LR,$ENG2,$PFENG2,$FFENG2,$ENG4];

	info("Looking For Images to Mosaic...");
	#Determine what Sky Images were written
	my @SkyImgDetailsFiles = findFile(class =>'intermediate'
		,instrument => thisInstrument
		,format => "ASCII"
		,content => "OM SKY IMAGE DETAILS"
	);
	
	unless (scalar(@SkyImgDetailsFiles)) {
		info("No Sky Images to mosaic.");	
		return success();
	}
	
	my @SkyImgDetails = ();
	foreach my $file (@SkyImgDetailsFiles) {
		my @details = readASCIIFile(name=>$file);
		next unless (scalar(@details));

		foreach my $line (@details) {
			my @tmp = split("\\|",$line);
			push (@SkyImgDetails,\@tmp) if (scalar(@tmp));
		}
	}
	my $count = scalar(@SkyImgDetails);
	unless ($count) {
		info("No Sky Images to mosaic.");	
		return success();
	}
	info("Found $count Images");
	info ("Grouping Images by Mode then Filter");

	# Sort details on: OM Mode, Filter	
	# 0 = Filename , 1 = Img Mode , 2 = Filter ,3 duration, 4 exp_id

	my ($filename_p,$mode_p,$filter_p,$duration_p,$exp_id_p) = (0,1,2,3,4);
	my @SortedSkyImgDetails = sort { ${$a}[$mode_p] cmp ${$b}[$mode_p] || ${$a}[$filter_p] cmp ${$b}[$filter_p] || ${$a}[$filename_p] cmp ${$b}[$filename_p] } @SkyImgDetails;

	# separate into image groups on mode then filter

	my @ImgGroups = ();
	my $Img = shift (@SortedSkyImgDetails);
	while (defined($Img)) {

		my $oldmode = $$Img[$mode_p];
		info("Mode: $oldmode");
		my @mode_tmp=();
		
		while ( (defined($Img)) && ($$Img[$mode_p] eq $oldmode) ) {

			my $oldfilter = $$Img[$filter_p];
			info("Filter: $oldfilter");
			my (@expids,@alt_expids);
			my ($duration,$alt_duration) = (0,0);
			my @filter_tmp = ();

			while ( (defined($Img)) && ($$Img[$filter_p] eq $oldfilter) && ($$Img[$mode_p] eq $oldmode) ) {
			
				info("Image File : $$Img[$filename_p]");

				# Add up a total for the duration here.  We only want duration from one window per exposure.
				# For RUDI5 we use the central image.  We set the side images durations -ve in OMImageAnalyse
				# to allow us to test for it here.
				# For USER mopde we use the first duration from an exposure

				if ( ($$Img[$duration_p] > 0) && !(grep /$$Img[$exp_id_p]/,@expids) ) {

					push(@expids,$$Img[$exp_id_p]);
					$duration += $$Img[$duration_p];
				}
				else {

					# This bit is in case we are missing the central image from a Rudi-5 set.
					# If that is the case we need to get the exposure time from one of the side images.
					#
					# The problem is image is defined across 4 exposures.  The rudi5group
					# returns a new exposure id of th form Rn where n the the Rudi5 group.
					# The  rudi5 groups are:
					# Group		Exposure id's
					#	1		S401 - S404
					#	2		S405 - S409
					#   etc
					my $r5g = &rudi5group($$Img[$exp_id_p]);	
					if ( $r5g && !(grep /$r5g/,@expids) ) {
						$alt_duration += abs($$Img[$duration_p]);
						push(@expids,$r5g);

					}


				}

				# Building up lists of files for each filter within each mode
				push(@filter_tmp,$$Img[$filename_p]);
				$Img = shift (@SortedSkyImgDetails);

			}
			# use $alt_duration if we have duration = 0 and a rudi5 set.
			$duration = $alt_duration if (!$duration && $alt_duration);

			
			push (@mode_tmp,[$oldfilter,$duration,\@filter_tmp]) unless ( (scalar @filter_tmp < 2) && ($oldmode ne $RUDI5_LR) );
		}
		push(@ImgGroups,[$oldmode,\@mode_tmp]);
	}

	&per_mode($MosaicModes,\@ImgGroups);

	return success();
}

sub per_mode {
	my ($MosaicModes,$Groups) = @_;
	my ($USER,$RUDI5_LR,$ENG2,$PFENG2,$FFENG2,$ENG4) = @$MosaicModes;
	my %Content_Strings = (
		 $USER => "OM USER WINDOWS SKY IMAGE MOSAIC"
		,$RUDI5_LR => "OM RUDI-5 SKY IMAGE MOSAIC"
		,$ENG2 => "OM FULL-FRAME LORES SKY IMAGE MOSAIC"
		,$PFENG2 => "OM PARTIAL-FRAME LORES SKY IMAGE MOSAIC"
		,$FFENG2 => "OM FULL-FRAME LORES SKY IMAGE MOSAIC"
		,$ENG4 => "OM FULL-FRAME HIRES SKY IMAGE MOSAIC"
	);
	info("Creating Images...");	

	foreach my $group (@$Groups) {
		my ($mode,$filters) = @$group;
		info("MODE: $mode");
		if ($mode eq $USER) {
			&per_filter($Content_Strings{"$USER"},$filters);
		}
		elsif ($mode eq $RUDI5_LR) {
			&per_filter($Content_Strings{"$RUDI5_LR"},$filters);
		}
		elsif ($mode eq $ENG2 || $mode eq $PFENG2 || $mode eq $FFENG2) {
			&per_filter($Content_Strings{"$ENG2"},$filters);
		}
		elsif ($mode eq $ENG4) {
			&per_filter($Content_Strings{"$ENG4"},$filters);
		}
		else {
			info("There are no rules for generating Mosaic products for this mode ($mode).");
			info("No Mosaic products will be generated.");
		}
		info("Done: $mode");
	
	}
}

sub per_filter {
	my ($content,$Filters) = @_;

	foreach my $f (@$Filters) {
		my ($filter,$duration,$imgs) = @$f;
		info("FILTER: $filter");
		
		&mosaic($filter,$duration,$content,$imgs);	
	}

}

sub mosaic{
	my ($filter,$duration,$content,$Imgs) = @_;

	my $newImg=newFile(class=>'product'
		,instrument => thisInstrument
		,osw_id => "$filter"
		,content => "$content"
	);

	# Determine total exposure time = duration.
	info("CREATING: $newImg, Duration: $duration");

	#These limits are imposed by the ommosaic task
	# They may change in future
	if ($duration >= 10) {
		doCommand('ommosaic'
			,imagesets => [@$Imgs]
			,mosaicedset => $newImg
			,mincorr => 0
#			,exposure => $duration ## Removed in SAS9
		)
		or return exception();

	# CREATE PNG FROM MOSAICS
		my $intcnt;
		($intcnt=$content)=~s/\s+//g;
		my $gifFile=newFile(class => 'intermediate'
			,instrument => thisInstrument
			,osw_id => "$filter"
			,content => "$intcnt"
			,format => 'GIF'
		);
		my $pngFile=newFile(class => 'product'
			,instrument => thisInstrument
			,osw_id => "$filter"
			,content => "$content"
			,format => 'PNG'
		);

		doCommand('implot'
			,set => $newImg
			,device => "$pngFile/PNG"
			,withsrclisttab => 'no'
		) or return exception();


#		# Convert to PNG format
#		GIFtoPNG(source => $gifFile
#			,destination => $pngFile
#		) or return exception();

	}
	else {

		info("The exposure time ($duration s) is outside of bounds set by the ommosaic task.");
		info("No Image Mosaic will be generated.");
		
	}
}

sub rudi5group {
	my ($expid) = @_;
	my $group = 0;

	return 0 unless ($expid =~ /^S4/);

	$expid =~ s/\D//g;
	while ($expid > 0) {
		$expid -= 4;
		$group++;
	}
	
	return "R${group}";

}
1;