Index: trunk/ippScripts/scripts/detrend_reject_imfile.pl
===================================================================
--- trunk/ippScripts/scripts/detrend_reject_imfile.pl	(revision 8507)
+++ trunk/ippScripts/scripts/detrend_reject_imfile.pl	(revision 8507)
@@ -0,0 +1,171 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Data::Dumper;
+
+use constant RECIPE => 'PPIMAGE_J'; # Recipe to use for ppImage to make JPEGs
+
+# The expected mean, as a function of detrend type
+use constant EXPECTED_MEAN => {
+    'bias' => 0,		# Bias should be zero
+    'dark' => 0,		# Dark should be zero
+    'flat' => undef		# Flat could be anything (depends on exposure level)
+    };
+
+# Rejection threshold for the mean, in terms of the standard deviation
+# This measures how close it is to what's expected
+use constant REJECT_INDIVIDUAL_MEAN => {
+    'bias' => 0.01,		# Should be fairly flat; some CRs
+    'dark' => 0.05,		# Lots of CRs
+    'flat' => undef		# Can't define expected value (depends on exposure level)
+    };
+
+# Rejection threshold for the standard deviation, in ADUs
+# This measures how much variation there is in each component
+use constant REJECT_INDIVIDUAL_STDEV => {
+    'bias' => 0.1,		# Should be fairly flat; some CRs
+    'dark' => 0.5,		# Lots of CRs
+    'flat' => 100		# Stars and galaxies
+    };
+
+# Rejection threshold for the mean of the sample, in terms of the standard deviation of the sample
+# This measures how close it is to what's expected
+use constant REJECT_SAMPLE_MEAN => {
+    'bias' => 0.01,		# Should be little variation between chips
+    'dark' => 0.05,		# Could be some glow on some chips
+    'flat' => undef		# Can't define expected value (depends on exposure level)
+    };
+
+# Rejection threshold for the stdev of the sample, in ADUs
+# This measures how much variation there is across the components
+use constant REJECT_SAMPLE_STDEV => {
+    'bias' => 0.1,		# Should be little variation between chips
+    'dark' => 0.5,		# Could be some glow on some chips
+    'flat' => 10		# Could be features on some chips, but all should be about the same
+    };
+
+
+# Parse command-line arguments
+die "Reject exposures based on the imfile.\n\n" .
+    "Usage: $0 DET_ID ITER EXP_ID DETREND_TYPE\n\n"
+    if scalar @ARGV != 4;
+my $detId = shift @ARGV;	# Detrend ID
+my $iter = shift @ARGV;		# Iteration number
+my $expId = shift @ARGV;	# Exposure ID
+my $detType = shift @ARGV;	# Detrend type
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+
+# Get list of component files
+my $files;			# Array of component files
+{
+    my $command = "$dettool -residimfile -det_id $detId -iter $iter -exp_id $expId"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -processed: $error_code\n" if not $success;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf); # Parsed metadata
+    $files = parse_md_list($metadata);
+}
+
+# Generate the file list
+my $outputName = $detId . '_' . $iter; # Root output name
+my $statName = $outputName . '.stats';
+my $listName = $outputName . '_jpeg.list'; # Name for the input file list
+open my $listFile, '>' . $listName;
+foreach my $file (@$files) {
+    print $listFile $file->{uri} . "\n";
+}
+close $listFile;
+
+# Output products --- need to synch with the camera configuration!
+my $jpeg1Name = $outputName . ".b1.jpeg"; # Binned JPEG #1
+my $jpeg2Name = $outputName . ".b2.jpeg"; # Binned JPEG #2
+
+# Make the jpeg
+{
+    my $command = "$ppImage -list $listName $outputName -stat $statName" .
+	"-recipe PPIMAGE " .  RECIPE; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg1Name\n" if not -f $jpeg1Name;
+    die "Unable to find expected output file: $jpeg2Name\n" if not -f $jpeg2Name;
+    die "Unable to find expected output file: $statName\n" if not -f $statName;
+}
+
+# Parse the statistics
+my $stats;			# Statistics from ppImage
+{
+    open my $statsFile, $statName or die "Can't open statistics file $statName: $!\n";
+    my @contents = <$statsFile>; # Contents of file
+    close $statsFile;
+    my $metadata = $mdcParser->parse(join "", @contents); # Metadata from the stats
+    $stats = PS::IPP::Metadata::Stats->new(); # Stats parser
+    $stats->parse($metadata) or die "Unable to find all values in statistics output.\n";
+}
+
+# Check the existence of the required rejection levels as a function of detrend type
+die "Unknown expected mean for detrend type $detType\n"
+    if not exists EXPECTED_MEAN->{$detType};
+die "Unknown individual mean rejection level for detrend type $detType\n"
+    if not exists REJECT_INDIVIDUAL_MEAN->{$detType};
+die "Unknown individual stdev rejection level for detrend type $detType\n"
+    if not exists REJECT_INDIVIDUAL_STDEV->{$detType};
+die "Unknown sample mean rejection level for detrend type $detType\n"
+    if not exists REJECT_SAMPLE_MEAN->{$detType};
+die "Unknown sample stdev rejection level for detrend type $detType\n"
+    if not exists REJECT_SAMPLE_STDEV->{$detType};
+
+# Reject based on the individual stats
+my @means = $stats->bg_data();	# Array of means
+my @stdevs = $stats->bg_stdev_data(); # Array of stdevs
+my $reject = 0;			# Rejection flag
+die "Number of means and number of stdevs differ!\n" if scalar @means != scalar @stdevs;
+for (my $i = 0; $i < scalar @means; $i++) {
+    my $mean = $means[$i];	# Mean for this component
+    $mean -= EXPECTED_MEAN->{$detType} if defined EXPECTED_MEAN->{$detType};
+    my $stdev = $stdevs[$i];	# Stdev for this component
+
+    if ((defined REJECT_INDIVIDUAL_MEAN->{$detType} and $mean / $stdev > REJECT_INDIVIDUAL_MEAN->{$detType})
+	or
+	(defined REJECT_INDIVIDUAL_STDEV->{$detType} and $stdev > REJECT_INDIVIDUAL_STDEV->{$detType})) {
+	$reject = 1;
+	last;
+    }
+}
+
+# Reject based on the sample stats
+my $mean = $stats->bg_mean;	# Mean of the sample of means
+my $stdev = $stats->bg_stdev; # Stdev of the sample of means
+my $meanStdev = $stats->bg_mean_stdev; # Mean of the sample of stdevs
+
+if ((defined REJECT_SAMPLE_MEAN->{$detType} and $mean / $stdev > REJECT_SAMPLE_MEAN->{$detType})
+    or
+    (defined REJECT_SAMPLE_STDEV->{$detType} and $meanStdev > REJECT_SAMPLE_STDEV->{$detType})) {
+    $reject = 1;
+}
+
+
+# Add the result into the database
+{
+    my $command = "dettool -addresidexp -det_id $detId -iter $iter -exp_id $expId " .
+	"-recip " . RECIPE() . " -b1_uri $jpeg1Name -b2_uri $jpeg2Name -bg $mean -bg_stdev $stdev " .
+	"-bg_mean_stdev $meanStdev";	# Command to run
+    $command .= ' -reject' if $reject;
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -addresidexp: $error_code\n" if not $success;
+}
+
+
+__END__
