Index: /trunk/ippScripts/Build.PL
===================================================================
--- /trunk/ippScripts/Build.PL	(revision 18561)
+++ /trunk/ippScripts/Build.PL	(revision 18562)
@@ -42,6 +42,6 @@
         scripts/detrend_norm_apply.pl
         scripts/detrend_norm_exp.pl
-        scripts/detrend_resid.pl
-        scripts/detrend_reject_imfile.pl
+        scripts/detrend_resid_imfile.pl
+        scripts/detrend_resid_exp.pl
         scripts/detrend_reject_exp.pl
         scripts/chip_imfile.pl
Index: /trunk/ippScripts/scripts/camera_exp.pl
===================================================================
--- /trunk/ippScripts/scripts/camera_exp.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/camera_exp.pl	(revision 18562)
@@ -27,19 +27,20 @@
 
 my ( $exp_tag, $cam_id, $camera, $outroot, $recipe, $dbname, $reduction, $dvodb, $verbose, $no_update,
-     $no_op, $save_temps );
+     $no_op, $redirect, $save_temps );
 GetOptions(
-           'exp_tag=s'          => \$exp_tag, # Exposure identifier
-           'cam_id=s'          => \$cam_id, # Camtool identifier
-           'recipe=s'          => \$recipe, # Recipe to use
-           'camera|c=s'        => \$camera, # Camera
-           'dbname|d=s'        => \$dbname, # Database name
-           'outroot|w=s'       => \$outroot, # output file base name
-           'reduction=s'       => \$reduction, # Reduction class
-           'dvodb|w=s'         => \$dvodb,  # output DVO database
-           'verbose'           => \$verbose,   # Print to stdout
-           'no-update'         => \$no_update, # Update the database?
-           'no-op'             => \$no_op, # Don't do any operations?
-           'save-temps'        => \$save_temps, # Save temporary files?
-           ) or pod2usage( 2 );
+    'exp_tag=s'          => \$exp_tag, # Exposure identifier
+    'cam_id=s'          => \$cam_id, # Camtool identifier
+    'recipe=s'          => \$recipe, # Recipe to use
+    'camera|c=s'        => \$camera, # Camera
+    'dbname|d=s'        => \$dbname, # Database name
+    'outroot|w=s'       => \$outroot, # output file base name
+    'reduction=s'       => \$reduction, # Reduction class
+    'dvodb|w=s'         => \$dvodb,  # output DVO database
+    'verbose'           => \$verbose,   # Print to stdout
+    'no-update'         => \$no_update, # Update the database?
+    'no-op'             => \$no_op, # Don't do any operations?
+    'redirect-output'   => \$redirect,
+    'save-temps'        => \$save_temps, # Save temporary files?
+    ) or pod2usage( 2 );
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
@@ -54,4 +55,8 @@
 
 $ipprc->define_camera($camera);
+
+my $logDest = $ipprc->filename("LOG.EXP", $outroot) or &my_die("Missing entry from camera config", $cam_id, $PS_EXIT_CONFIG_ERROR);
+
+$ipprc->redirect_output($logDest) if $redirect;
 
 # Recipes to use based on reduction class
@@ -185,5 +190,4 @@
 my $fpaStats   = $ipprc->filename("PSASTRO.STATS",      $outroot) or &my_die("Missing entry from camera config", $cam_id, $PS_EXIT_CONFIG_ERROR);
 my $traceDest  = $ipprc->filename("TRACE.EXP",          $outroot) or &my_die("Missing entry from camera config", $cam_id, $PS_EXIT_CONFIG_ERROR);
-my $logDest    = $ipprc->filename("LOG.EXP",            $outroot) or &my_die("Missing entry from camera config", $cam_id, $PS_EXIT_CONFIG_ERROR);
 
 # convert supplied DVO database name to UNIX filename
@@ -320,5 +324,9 @@
     carp($msg);
     if (defined $cam_id and not $no_update) {
-        my $command = "$camtool -addprocessedexp -cam_id $cam_id -uri UNKNOWN -code $exit_code";
+        my $command = "$camtool -addprocessedexp";
+	$command .= " -cam_id $cam_id";
+	$command .= " -uri UNKNOWN";
+	$command .= " -code $exit_code";
+	$command .= " -path_base $outroot";
         $command .= " -hostname $host" if defined $host;
         $command .= " -dbname $dbname" if defined $dbname;
Index: /trunk/ippScripts/scripts/chip_imfile.pl
===================================================================
--- /trunk/ippScripts/scripts/chip_imfile.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/chip_imfile.pl	(revision 18562)
@@ -26,18 +26,19 @@
 # Parse the command-line arguments
 my ( $exp_id, $chip_id, $class_id, $uri, $camera, $outroot, $dbname, $reduction, $verbose,
-     $no_update, $no_op );
+     $no_update, $no_op, $redirect );
 GetOptions(
-           'exp_id=s'      => \$exp_id,    # Exposure identifier
-           'chip_id=s'     => \$chip_id,   # Chiptool identifier
-           'class_id=s'    => \$class_id,  # Class identifier
-           'uri|u=s'       => \$uri,       # Input FITS file
-           'camera|c=s'    => \$camera,    # Camera
-           'outroot|w=s'   => \$outroot,   # output file base name
-           'dbname|d=s'    => \$dbname,    # Database name
-           'reduction=s'   => \$reduction, # Reduction class
-           'verbose'       => \$verbose,   # Print to stdout
-           'no-update'     => \$no_update, # Don't update the database?
-           'no-op'         => \$no_op,     # Don't do any operations?
-           ) or pod2usage( 2 );
+    'exp_id=s'      	=> \$exp_id,    # Exposure identifier
+    'chip_id=s'     	=> \$chip_id,   # Chiptool identifier
+    'class_id=s'    	=> \$class_id,  # Class identifier
+    'uri|u=s'       	=> \$uri,       # Input FITS file
+    'camera|c=s'    	=> \$camera,    # Camera
+    'outroot|w=s'   	=> \$outroot,   # output file base name
+    'dbname|d=s'    	=> \$dbname,    # Database name
+    'reduction=s'   	=> \$reduction, # Reduction class
+    'verbose'       	=> \$verbose,   # Print to stdout
+    'no-update'     	=> \$no_update, # Don't update the database?
+    'no-op'         	=> \$no_op,     # Don't do any operations?
+    'redirect-output'   => \$redirect,
+    ) or pod2usage( 2 );
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
@@ -52,4 +53,8 @@
 
 $ipprc->define_camera($camera);
+
+my $logDest = $ipprc->filename("LOG.IMFILE", $outroot, $class_id) or &my_die("Missing entry from camera config", $exp_id, $chip_id, $class_id, $PS_EXIT_CONFIG_ERROR);
+
+$ipprc->redirect_output($logDest) if $redirect;
 
 # Recipes to use based on reduction class
@@ -125,5 +130,4 @@
 my $outputStats   = $ipprc->filename("PPIMAGE.STATS",       $outroot, $class_id) or &my_die("Missing entry from camera config", $exp_id, $chip_id, $class_id, $PS_EXIT_CONFIG_ERROR);
 my $traceDest     = $ipprc->filename("TRACE.IMFILE",        $outroot, $class_id) or &my_die("Missing entry from camera config", $exp_id, $chip_id, $class_id, $PS_EXIT_CONFIG_ERROR);
-my $logDest       = $ipprc->filename("LOG.IMFILE",          $outroot, $class_id) or &my_die("Missing entry from camera config", $exp_id, $chip_id, $class_id, $PS_EXIT_CONFIG_ERROR);
 
 # Run ppImage
Index: /trunk/ippScripts/scripts/detrend_correct_imfile.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_correct_imfile.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/detrend_correct_imfile.pl	(revision 18562)
@@ -108,5 +108,6 @@
 $command .= " -exp_id $exp_id";
 $command .= " -class_id $class_id";
-$command .= " -uri $outputImage -path_base $outputRoot";
+$command .= " -uri $outputImage";
+$command .= " -path_base $outputRoot";
 $command .= " -dbname $dbname" if defined $dbname;
 
@@ -138,4 +139,5 @@
 	$command .= " -exp_id $exp_id"; 
 	$command .= " -class_id $class_id";
+	$command .= " -path_base $outputRoot";
 	$command .= " -code $exit_code";
 	$command .= " -dbname $dbname" if defined $dbname;
Index: /trunk/ippScripts/scripts/detrend_norm_apply.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_norm_apply.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/detrend_norm_apply.pl	(revision 18562)
@@ -212,4 +212,5 @@
         $command .= " -iteration $iter";
         $command .= " -class_id $class_id";
+	$command .= " -path_base $outroot";
         $command .= " -code $exit_code";
         $command .= " -dbname $dbname" if defined $dbname;
Index: /trunk/ippScripts/scripts/detrend_norm_calc.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_norm_calc.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/detrend_norm_calc.pl	(revision 18562)
@@ -20,19 +20,22 @@
 use PS::IPP::Config 1.01 qw( :standard );
 
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+
 use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
 use Pod::Usage qw( pod2usage );
 
 # Parse command-line arguments
-my ($det_id, $iter, $detType, $outroot, $dbname, $verbose, $no_update, $no_op);
+my ($det_id, $iter, $detType, $outroot, $dbname, $verbose, $no_update, $no_op, $redirect );
 GetOptions(
-	'det_id|d=s'	=> \$det_id,    # Detrend id			     
-	'iteration|i=s'	=> \$iter,	# Iteration			     
-	'det_type|t=s'  => \$detType,	# Detrend type			     
-        'outroot|w=s'   => \$outroot,   # output file base name
- 	'dbname|d=s'    => \$dbname,	# Database name			     
-        'verbose'       => \$verbose,   # Print to stdout
-        'no-update'     => \$no_update,	# Don't update the database?	     
-	'no-op'         => \$no_op,	# Don't do operations                
-	) or pod2usage( 2 );
+    'det_id|d=s'	=> \$det_id,    # Detrend id			     
+    'iteration|i=s'	=> \$iter,	# Iteration			     
+    'det_type|t=s'  	=> \$detType,	# Detrend type			     
+    'outroot|w=s'   	=> \$outroot,   # output file base name
+    'dbname|d=s'    	=> \$dbname,	# Database name			     
+    'verbose'       	=> \$verbose,   # Print to stdout
+    'no-update'     	=> \$no_update,	# Don't update the database?	     
+    'no-op'         	=> \$no_op,	# Don't do operations                
+    'redirect-output'   => \$redirect,
+    ) or pod2usage( 2 );
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
@@ -44,4 +47,8 @@
     defined $detType and
     defined $outroot;
+
+my $logfile = $outroot . ".log";
+
+$ipprc->redirect_output($logfile) if $redirect;
 
 use constant STATISTIC => 'bg'; # Background statistic to use from the database
@@ -225,4 +232,5 @@
 	$command .= " -det_id $det_id";
 	$command .= " -iteration $iter";
+	# XXX EAM : we should add this to the db : $command .= " -path_base $outroot";
 	$command .= " -code $exit_code";
 	$command .= " -dbname $dbname" if defined $dbname;
Index: /trunk/ippScripts/scripts/detrend_norm_exp.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_norm_exp.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/detrend_norm_exp.pl	(revision 18562)
@@ -26,18 +26,19 @@
 use Pod::Usage qw( pod2usage );
 
-my ($det_id, $iter, $det_type, $camera, $outroot, $dbname, $reduction, $verbose, $no_update, $no_op, $save_temps);
+my ($det_id, $iter, $det_type, $camera, $outroot, $dbname, $reduction, $verbose, $no_update, $no_op, $redirect, $save_temps);
 GetOptions(
-           'det_id|d=s'        => \$det_id,
-           'iteration|i=s'     => \$iter,
-           'camera|c=s'        => \$camera,
-           'det_type|t=s'      => \$det_type,
-           'outroot|w=s'       => \$outroot,   # output file base name
-           'dbname|d=s'        => \$dbname, # Database name
-           'reduction|=s'      => \$reduction,
-           'verbose'           => \$verbose,   # Print to stdout
-           'no-update'         => \$no_update,
-           'no-op'             => \$no_op,
-           'save-temps'        => \$save_temps, # Save temporary files?
-           ) or pod2usage( 2 );
+    'det_id|d=s'        => \$det_id,
+    'iteration|i=s'     => \$iter,
+    'camera|c=s'        => \$camera,
+    'det_type|t=s'      => \$det_type,
+    'outroot|w=s'       => \$outroot,   # output file base name
+    'dbname|d=s'        => \$dbname, # Database name
+    'reduction|=s'      => \$reduction,
+    'verbose'           => \$verbose,   # Print to stdout
+    'no-update'         => \$no_update,
+    'no-op'             => \$no_op,
+    'redirect-output'   => \$redirect,
+    'save-temps'        => \$save_temps, # Save temporary files?
+    ) or pod2usage( 2 );
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
@@ -49,4 +50,8 @@
     defined $det_type and
     defined $outroot;
+
+my $logfile = $outroot . ".log";
+
+$ipprc->redirect_output($logfile) if $redirect;
 
 $ipprc->define_camera($camera);
@@ -87,5 +92,7 @@
 my ($files, $command, $success, $error_code, $full_buf, $stdout_buf, $stderr_buf);
 {
-    $command  = "$dettool -normalizedimfile -det_id $det_id -iteration $iter"; # Command to run
+    $command  = "$dettool -normalizedimfile"; # Command to run
+    $command .= " -det_id $det_id";
+    $command .= " -iteration $iter"; 
     $command .= " -dbname $dbname" if defined $dbname;
     ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
@@ -181,4 +188,5 @@
         $command .= " -det_id $det_id";
         $command .= " -iteration $iter";
+	$command .= " -path_base $outroot ";
         $command .= " -code $exit_code";
         $command .= " -dbname $dbname" if defined $dbname;
Index: /trunk/ippScripts/scripts/detrend_process_exp.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_process_exp.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/detrend_process_exp.pl	(revision 18562)
@@ -200,4 +200,5 @@
         $command .= " -exp_id $exp_id";
         $command .= " -code $exit_code";
+	$command .= " -path_base $outroot";
         $command .= " -dbname $dbname" if defined $dbname;
         system ($command);
Index: /trunk/ippScripts/scripts/detrend_process_imfile.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_process_imfile.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/detrend_process_imfile.pl	(revision 18562)
@@ -58,6 +58,5 @@
 $ipprc->define_camera($camera);
 
-my $logDest     = $ipprc->filename("LOG.IMFILE",     $outroot, $class_id)
-      or &my_die("Missing entry from camera config", $det_id, $exp_id, $class_id, $PS_EXIT_CONFIG_ERROR);
+my $logDest = $ipprc->filename("LOG.IMFILE", $outroot, $class_id) or &my_die("Missing entry from camera config", $det_id, $exp_id, $class_id, $PS_EXIT_CONFIG_ERROR);
 
 $ipprc->redirect_output($logDest) if $redirect;
@@ -174,4 +173,5 @@
         $command .= " -exp_id $exp_id";
         $command .= " -class_id $class_id";
+	$command .= " -path_base $outroot";
         $command .= " -code $exit_code";
         $command .= " -dbname $dbname" if defined $dbname;
Index: /trunk/ippScripts/scripts/detrend_reject_exp.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_reject_exp.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/detrend_reject_exp.pl	(revision 18562)
@@ -28,16 +28,17 @@
 use Pod::Usage qw( pod2usage );
 
-my ($det_id, $iter, $det_type, $camera, $outroot, $filter, $dbname, $verbose, $no_update, $no_op);
+my ($det_id, $iter, $det_type, $camera, $outroot, $filter, $dbname, $verbose, $no_update, $no_op, $redirect);
 GetOptions(
-           'det_id|d=s'        => \$det_id,
-           'iteration=s'       => \$iter,
-           'det_type|t=s'      => \$det_type,
-           'camera=s'          => \$camera,
-           'outroot|w=s'       => \$outroot,   # output file base name
-           'filter=s'          => \$filter,
-           'dbname|d=s'        => \$dbname, # Database name
-           'verbose'           => \$verbose,   # Print to stdout
-           'no-update'         => \$no_update,
-           'no-op'             => \$no_op,
+    'det_id|d=s'        => \$det_id,
+    'iteration=s'       => \$iter,
+    'det_type|t=s'      => \$det_type,
+    'camera=s'          => \$camera,
+    'outroot|w=s'       => \$outroot,   # output file base name
+    'filter=s'          => \$filter,
+    'dbname|d=s'        => \$dbname, # Database name
+    'verbose'           => \$verbose,   # Print to stdout
+    'no-update'         => \$no_update,
+    'no-op'             => \$no_op,
+    'redirect-output'   => \$redirect,
 ) or pod2usage( 2 );
 
@@ -50,4 +51,11 @@
     defined $camera   and
     defined $outroot;
+
+# check for existing directory, generate if needed
+$ipprc->outroot_prepare($outroot);
+
+my $logName = "$outroot.log"; # Name for log
+
+$ipprc->redirect_output($logName) if $redirect;
 
 # values to extract from output metadata and the stats to calculate
@@ -145,15 +153,8 @@
 # neb:///*/gpc1/20080130 (volume not specified)
 
-# check for existing directory, generate if needed
-$ipprc->outroot_prepare($outroot);
-
-my $logName = "$outroot.log"; # Name for log
-
-my $logFile;
 unless ($no_op) {
-    $logFile = $ipprc->file_create_append( $logName );
-    print $logFile "Ensemble mean $ensMeanMean +/- $ensMeanStdev\n";
-    print $logFile "Ensemble stdev $ensStdevMean +/- $ensStdevStdev\n";
-    print $logFile "Ensemble mean rms (over imfiles) $ensMeanStdevMean +/- $ensMeanStdevStdev\n\n";
+    print "Ensemble mean $ensMeanMean +/- $ensMeanStdev\n";
+    print "Ensemble stdev $ensStdevMean +/- $ensStdevStdev\n";
+    print "Ensemble mean rms (over imfiles) $ensMeanStdevMean +/- $ensMeanStdevStdev\n\n";
 }
 
@@ -186,5 +187,5 @@
         # Rejected this at an earlier stage
         unless ($no_op) {
-            print $logFile "Rejecting $expID based on earlier determination.\n";
+            print "Rejecting $expID based on earlier determination.\n";
         }
         $reject = 1;
@@ -205,13 +206,13 @@
         my $delta = abs($mean - $ensMeanMean);
         if ($delta > ($reject_mean * $ensMeanStdev)) {
-            print $logFile "Rejecting $expID based on ensemble mean value: ";
+            print "Rejecting $expID based on ensemble mean value: ";
             $reject = 1;
             #goto UPDATE;
         } else {
-            print $logFile "$expID OK against ensemble mean: ";
-        }
-        print $logFile "$mean --> $delta vs " . $reject_mean * $ensMeanStdev . "\n";
+            print "$expID OK against ensemble mean: ";
+        }
+        print "$mean --> $delta vs " . $reject_mean * $ensMeanStdev . "\n";
     } else {
-        print $logFile "No rejection of $expID for ensemble mean\n";
+        print "No rejection of $expID for ensemble mean\n";
     }
 
@@ -219,13 +220,13 @@
         my $delta = abs($stdev - $ensStdevMean);
         if ($delta > ($reject_stdev * $ensStdevStdev)) {
-            print $logFile "Rejecting $expID based on ensemble stdev: ";
+            print "Rejecting $expID based on ensemble stdev: ";
             $reject = 1;
             #goto UPDATE;
         } else {
-            print $logFile "$expID OK against ensemble stdev: ";
-        }
-        print $logFile "$stdev --> $delta sigma vs " . $reject_stdev * $ensStdevStdev . "\n";
+            print "$expID OK against ensemble stdev: ";
+        }
+        print "$stdev --> $delta sigma vs " . $reject_stdev * $ensStdevStdev . "\n";
     } else {
-        print $logFile "No rejection of $expID for ensemble stdev\n";
+        print "No rejection of $expID for ensemble stdev\n";
     }
 
@@ -233,13 +234,13 @@
         my $delta = abs($meanStdev - $ensMeanStdevMean);
         if ($delta > ($reject_meanstdev * $ensMeanStdevStdev)) {
-            print $logFile "Rejecting $expID based on ensemble mean stdev: ";
+            print "Rejecting $expID based on ensemble mean stdev: ";
             $reject = 1;
             #goto UPDATE;
         } else {
-            print $logFile "$expID OK against ensemble mean stdev: ";
-        }
-        print $logFile "$meanStdev --> $delta sigma vs " . $reject_meanstdev * $ensMeanStdevStdev. "\n";
+            print "$expID OK against ensemble mean stdev: ";
+        }
+        print "$meanStdev --> $delta sigma vs " . $reject_meanstdev * $ensMeanStdevStdev. "\n";
     } else {
-        print $logFile "No rejection of $expID for ensemble mean stdev\n";
+        print "No rejection of $expID for ensemble mean stdev\n";
     }
 
@@ -253,5 +254,5 @@
     if ((not $include and not $reject) or ($include and $reject)) {
         unless ($no_op) {
-            print $logFile "Status of $expID has changed.\n";
+            print "Status of $expID has changed.\n";
         }
         $numChanges++;
@@ -286,7 +287,6 @@
 
 unless ($no_op) {
-    print $logFile "Master: $master\n";
-    print $logFile "Stop: $stop\n";
-    close $logFile;
+    print "Master: $master\n";
+    print "Stop: $stop\n";
 }
 
@@ -309,5 +309,4 @@
 $command .= " -accept" if $master;
 $command .= " -dbname $dbname" if defined $dbname;
-### XXX WE NEED to make this a recipe-driven option
 $command .= " -again" unless $stop;
 $command .= $stats->cmdflags();
@@ -346,4 +345,5 @@
         $command .= " -det_id $det_id";
         $command .= " -iteration $iter";
+	# XXX EAM : we should add this to the db : $command .= " -path_base $outroot";
         $command .= " -code $exit_code";
         $command .= " -dbname $dbname" if defined $dbname;
Index: unk/ippScripts/scripts/detrend_reject_imfile.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_reject_imfile.pl	(revision 18561)
+++ 	(revision )
@@ -1,611 +1,0 @@
-#!/usr/bin/env perl
-
-# this program has two jobs:
-# 1: for the given exp_tag, generate the binned & mosaiced JPEG images
-# 2: examine the collection of per-imfile statistics and reject.  At the moment,
-#    this program (and the database) only allows rejection at the exposure level,
-#    not at the imfile level.
-
-use Carp;
-use warnings;
-use strict;
-
-## report the program and machine
-use Sys::Hostname;
-my $host = hostname();
-print "\n\n";
-print "Starting script $0 on $host\n\n";
-
-use vars qw( $VERSION );
-$VERSION = '0.01';
-
-use IPC::Cmd 0.36 qw( can_run run );             # tools to run UNIX programs with control over I/O
-use PS::IPP::Metadata::Config;                   # tools to parse the psMetadataConfig files
-use PS::IPP::Metadata::Stats;
-
-use PS::IPP::Metadata::List qw( parse_md_list ); # tools to parse a metadata into a hash list
-use Statistics::Descriptive;                     # tools for calculating basic statistical quantities
-use File::Temp qw( tempfile );                   # tools to construct temp files
-use PS::IPP::Config 1.01 qw( :standard );
-
-my $ipprc = PS::IPP::Config->new(); # IPP configuration
-
-use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt ); # option parsing
-use Pod::Usage qw( pod2usage );
-
-# parse the command-line options
-my ( $det_id, $iter, $exp_id, $exp_tag, $det_type, $camera, $filter, $reject, $outroot, $dbname, $reduction,
-     $verbose, $no_update, $no_op, $save_temps, $redirect );
-GetOptions(
-           'det_id|d=s'        => \$det_id,
-           'iteration=s'       => \$iter,
-           'exp_id|e=s'        => \$exp_id,
-           'exp_tag|=s'        => \$exp_tag,
-           'det_type|t=s'      => \$det_type,
-           'camera=s'          => \$camera,
-           'outroot|w=s'       => \$outroot,   # output file base name
-           'filter=s'          => \$filter,
-           'reject'            => \$reject,
-           'dbname|d=s'        => \$dbname, # Database name
-           'reduction|=s'      => \$reduction,
-           'verbose'           => \$verbose,   # Print to stdout
-           'no-update'         => \$no_update,
-           'no-op'             => \$no_op,
-           'save-temps'        => \$save_temps, # Save temporary files?
-           'redirect-output'   => \$redirect,   # redirect output from LOG.IMFILE
-           ) or pod2usage( 2 );
-
-pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
-pod2usage( -msg => "Required options: --det_id --iteration --exp_id --exp_tag --det_type --camera --outroot",
-           -exitval => 3) unless
-    defined $det_id   and
-    defined $iter     and
-    defined $exp_id   and
-    defined $exp_tag  and
-    defined $det_type and
-    defined $camera   and
-    defined $outroot;
-
-# load IPP config information for the specified camera
-$ipprc->define_camera($camera);
-if ($redirect) {
-    # XXX should this really be going to LOG.IMFILE?
-    # That's where detrend.resid.pro was sending it
-    my $logDest     = $ipprc->filename("LOG.IMFILE", $outroot, "NONE")
-       or &my_die("Missing entry from camera config", $det_id, $iter, $exp_id, $PS_EXIT_CONFIG_ERROR);
-    $ipprc->redirect_output($logDest);
-}
-
-
-# Recipes to use based on reduction class
-$reduction = 'DETREND' unless defined $reduction;
-
-my $recipe1 = $ipprc->reduction($reduction, 'JPEG_BIN1_RESID_' . uc($det_type)); # Recipe to use
-&my_die("Unrecognised detrend type: $det_type", $det_id, $iter, $PS_EXIT_PROG_ERROR) unless defined $recipe1;
-
-my $recipe2 = $ipprc->reduction($reduction, 'JPEG_BIN2_RESID_' . uc($det_type)); # Recipe to use
-&my_die("Unrecognised detrend type: $det_type", $det_id, $iter, $PS_EXIT_PROG_ERROR) unless defined $recipe2;
-
-# values to extract from output metadata and the stats to calculate
-# XXX -bg_mean_stdev should take rms of bg_mean_stdev if bg_mean_stdev != 0 (A)
-# XXX -bg_mean_stdev should take stdev of bg_mean if bg_mean_stdev == 0     (B)
-# XXX  (A) if imfile.Ncomp > 1, (B) if imfile.Ncomp == 1
-my $STATS =
-    [
-        #          KEYWORD                 STATISTIC          CHIPTOOL FLAG
-        { name => "bg",             type => "mean",  flag => "-bg",            dtype => "float" },
-        { name => "bg_mean_stdev",  type => "stdev", flag => "-bg_mean_stdev", dtype => "float" },
-        { name => "bg_stdev",       type => "rms",   flag => "-bg_stdev",      dtype => "float" },
-        { name => "bg_skewness",    type => "mean",  flag => "-bg_skewness",   dtype => "float" },
-        { name => "bg_kurtosis",    type => "mean",  flag => "-bg_kurtosis",   dtype => "float" },
-        { name => "bin_stdev",      type => "rms",   flag => "-bin_stdev",     dtype => "float" },
-        { name => "fringe_0",       type => "mean",  flag => "-fringe_0",      dtype => "float" },
-        { name => "fringe_1",       type => "rms",   flag => "-fringe_1",      dtype => "float" },
-        { name => "fringe_0",       type => "stdev", flag => "-fringe_2",      dtype => "float" },
-        { name => "user_1",         type => "mean",  flag => "-user_1",        dtype => "float" }, # fringe residual
-        { name => "user_2",         type => "rms",   flag => "-user_2",        dtype => "float" }, # fringe residual
-        { name => "user_1",         type => "stdev", flag => "-user_3",        dtype => "float" }, # fringe residual
-        ];
-my $stats = PS::IPP::Metadata::Stats->new($STATS); # Stats parser
-
-# 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);
-if ($missing_tools) {
-    warn("Can't find required tools.");
-    exit($PS_EXIT_CONFIG_ERROR);
-}
-
-# Get list of imfile files
-my ($files, $command, $success, $error_code, $full_buf, $stdout_buf, $stderr_buf);
-{
-    # dettool command to select imfile data for this exp_id
-    $command  = "$dettool -residimfile";
-    $command .= " -det_id $det_id";
-    $command .= " -iteration $iter";
-    $command .= " -exp_id $exp_id";
-    $command .= " -dbname $dbname" if defined $dbname;
-    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => $verbose);
-    unless ($success) {
-        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        warn("Unable to perform dettool -residimfile: $error_code\n");
-        exit($error_code);
-    }
-    # XXX report an error message if stdout_buf is empty
-
-    # Parse the stdout buffer into a metadata
-    my $mdcParser = PS::IPP::Metadata::Config->new;
-    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
-        &my_die("Unable to parse metadata config doc", $det_id, $iter, $exp_id, $PS_EXIT_PROG_ERROR);
-
-    # parse the file info in the metadata
-    $files = parse_md_list($metadata) or
-        &my_die("Unable to parse metadata list", $det_id, $iter, $exp_id, $PS_EXIT_PROG_ERROR);
-
-    # Parse the statistics on the residual image
-    $stats->parse($metadata) or &my_die("Unable to find all values in statistics output.", $det_id, $iter, $exp_id, $PS_EXIT_PROG_ERROR);
-}
-
-# outroot examples (HOST components must be set)
-# file://data/ipp004.0/gpc1/20080130
-# neb:///ipp004-v1/gpc1/20080130
-# neb:///*/gpc1/20080130 (volume not specified)
-
-# check for existing directory, generate if needed
-$ipprc->outroot_prepare($outroot);
-
-my $jpeg1Name  = $ipprc->filename("PPIMAGE.JPEG1", $outroot); # Binned JPEG #1
-my $jpeg2Name  = $ipprc->filename("PPIMAGE.JPEG2", $outroot); # Binned JPEG #2
-my $logName    = $ipprc->filename("LOG.EXP",       $outroot); # Name for log
-
-my $logFile;
-unless ($no_op) {
-    $logFile = $ipprc->file_create_append( $logName );
-}
-
-# XXX in debug mode, unlink = 0
-my ($list1File, $list1Name) = tempfile( "$exp_tag.detresid.$det_id.$iter.b1.list.XXXX", UNLINK => !$save_temps );
-my ($list2File, $list2Name) = tempfile( "$exp_tag.detresid.$det_id.$iter.b2.list.XXXX", UNLINK => !$save_temps );
-foreach my $file (@$files) {
-    print $list1File ($ipprc->filename( "PPIMAGE.BIN1", $file->{path_base}, $file->{class_id} ) . "\n");
-    print $list2File ($ipprc->filename( "PPIMAGE.BIN2", $file->{path_base}, $file->{class_id} ) . "\n");
-}
-close $list1File;
-close $list2File;
-
-
-# build the JPEG images
-unless ($no_op) {
-    # Make the jpeg for binning 1
-    $command = "$ppImage -list $list1Name $outroot -recipe PPIMAGE $recipe1"; # Command to run
-    $command .= " -dbname $dbname" if defined $dbname;
-    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => $verbose);
-    unless ($success) {
-        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        &my_die("Unable to run ppImage: $error_code", $det_id, $iter, $exp_id, $error_code);
-    }
-    &my_die("Unable to find expected output file: $jpeg1Name", $det_id, $iter, $exp_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($jpeg1Name);
-
-    # Make the jpeg for binning 2
-    $command = "$ppImage -list $list2Name $outroot -recipe PPIMAGE $recipe2"; # Command to run
-    $command .= " -dbname $dbname" if defined $dbname;
-    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => $verbose);
-    unless ($success) {
-        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        &my_die("Unable to run ppImage: $error_code", $det_id, $iter, $exp_id, $error_code);
-    }
-    &my_die("Unable to find expected output file: $jpeg2Name", $det_id, $iter, $exp_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($jpeg2Name);
-}
-
-#### measure stats and reject if needed ####
-
-# Rejection thresholds & related data
-my $expected                = rejection_limit( 'EXPECTED',         $det_type, $filter );
-my $reject_imfile_mean      = rejection_limit( 'IMFILE.MEAN',      $det_type, $filter );
-my $reject_imfile_flux      = rejection_limit( 'IMFILE.FLUX',      $det_type, $filter );
-my $reject_imfile_stdev     = rejection_limit( 'IMFILE.STDEV',     $det_type, $filter );
-my $reject_imfile_skewness  = rejection_limit( 'IMFILE.SKEWNESS',  $det_type, $filter );
-my $reject_imfile_kurtosis  = rejection_limit( 'IMFILE.KURTOSIS',  $det_type, $filter );
-my $reject_imfile_meanstdev = rejection_limit( 'IMFILE.MEANSTDEV', $det_type, $filter );
-my $reject_imfile_snr       = rejection_limit( 'IMFILE.SNR',       $det_type, $filter );
-my $reject_imfile_bin_stdev = rejection_limit( 'IMFILE.BIN.STDEV', $det_type, $filter );
-my $reject_imfile_bin_snr   = rejection_limit( 'IMFILE.BIN.SNR',   $det_type, $filter );
-my $reject_exp_mean         = rejection_limit( 'EXP.MEAN',         $det_type, $filter );
-my $reject_exp_flux         = rejection_limit( 'EXP.FLUX',         $det_type, $filter );
-my $reject_exp_stdev        = rejection_limit( 'EXP.STDEV',        $det_type, $filter );
-my $reject_exp_meanstdev    = rejection_limit( 'EXP.MEANSTDEV',    $det_type, $filter );
-my $reject_exp_snr          = rejection_limit( 'EXP.SNR',          $det_type, $filter );
-my $reject_exp_bin_stdev    = rejection_limit( 'EXP.BIN.STDEV',    $det_type, $filter );
-my $reject_exp_bin_snr      = rejection_limit( 'EXP.BIN.SNR',      $det_type, $filter );
-
-# storage array
-my @fluxes;
-
-foreach my $file (@$files) {
-    my $name      = $file->{class_id};
-    my $mean      = $file->{bg};        # Mean for this imfile
-    my $stdev     = $file->{bg_stdev}; # Stdev for this imfile
-    my $skewness  = $file->{bg_skewness}; # Skewness for this imfile
-    my $kurtosis  = $file->{bg_kurtosis}; # Kurtosis for this imfile
-    my $meanStdev = $file->{bg_mean_stdev}; # Stdev of Means for this imfile
-    my $binStdev  = $file->{bin_stdev}; # Binned Stdev for this imfile
-
-    # calculate and save the fluxes
-    my $flux;
-    if ($file->{exp_time} == 0.0) {
-        $flux = $mean;
-    } else {
-        $flux = $mean / $file->{exp_time};
-    }
-    push @fluxes, $flux;
-
-    $mean -= $expected;
-
-    last if $no_op;
-
-    # reject exposure if, for any imfiles, the mean residual counts
-    # deviate from the expected value by more than N sigma, (sigma =
-    # total pixel variance).  this test is sensible for images which
-    # should have a predictable nominal residual mean count value (eg,
-    # 0.0 for a bias).   in general, use with ADDITIVE components
-    if ($reject_imfile_mean > 0) {
-        if (abs($mean) > $reject_imfile_mean * $stdev) {
-            print $logFile "Rejecting exposure based on bad imfile mean for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile mean for $name meets requirements: ";
-        }
-        print $logFile "$mean vs $reject_imfile_mean * $stdev\n";
-    }  else {
-        print $logFile "No rejection on imfile mean for $name\n";
-    }
-
-    # reject exposure if, for any imfiles, the mean residual flux
-    # deviates from the expected value by more than N sigma, (sigma =
-    # total pixel variance).  this test is sensible for images which
-    # should have a predictable nominal residual flux value (eg, 0.0
-    # for a bias).  in general, use with ADDITIVE components
-    if ($reject_imfile_flux > 0) {
-        if (abs($flux) > $reject_imfile_flux) {
-            print $logFile "Rejecting exposure based on bad imfile flux for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile flux for $name meets requirements: ";
-        }
-        print $logFile "$flux vs $reject_imfile_flux\n";
-    }  else {
-        print $logFile "No rejection on imfile flux for $name\n";
-    }
-
-    # reject exposure if, for any imfiles, the total pixel variance is
-    # larger than the limit
-    if ($reject_imfile_stdev > 0) {
-        if ($stdev > $reject_imfile_stdev) {
-            print $logFile "Rejecting exposure based on bad imfile stdev for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile stdev for $name meets requirements: ";
-        }
-        print $logFile "$stdev vs $reject_imfile_stdev\n";
-
-    } else {
-        print $logFile "No rejection on imfile stdev for $name\n";
-    }
-
-    # reject exposure if, for any imfiles, the skewness is
-    # larger than the limit
-    if ($reject_imfile_skewness > 0) {
-        if ($stdev > $reject_imfile_skewness) {
-            print $logFile "Rejecting exposure based on bad imfile skewness for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile skewness for $name meets requirements: ";
-        }
-        print $logFile "$skewness vs $reject_imfile_skewness\n";
-
-    } else {
-        print $logFile "No rejection on imfile skewness for $name\n";
-    }
-
-    # reject exposure if, for any imfiles, the kurtosis is
-    # larger than the limit
-    if ($reject_imfile_kurtosis > 0) {
-        if ($stdev > $reject_imfile_kurtosis) {
-            print $logFile "Rejecting exposure based on bad imfile kurtosis for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile kurtosis for $name meets requirements: ";
-        }
-        print $logFile "$kurtosis vs $reject_imfile_kurtosis\n";
-
-    } else {
-        print $logFile "No rejection on imfile kurtosis for $name\n";
-    }
-
-    # reject exposure if, for any imfiles, the variance of the imfile
-    # component means is larger than the limit
-    if ($reject_imfile_meanstdev > 0) {
-        if ($meanStdev > $reject_imfile_meanstdev) {
-            print $logFile "Rejecting exposure based on bad imfile mean stdev for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile mean stdev for $name meets requirements: ";
-        }
-        print $logFile "$meanStdev vs $reject_imfile_meanstdev\n";
-    } else {
-        print $logFile "No rejection on imfile mean stdev for $name\n";
-    }
-
-    # reject exposure if, for any imfiles, the signal-to-noise (ie,
-    # the mean counts / total pixel variance) of the imfile component
-    # means are less than the limit.  this test is sensible for images
-    # which have finite residual flux such as a flat-field image.
-    if ($reject_imfile_snr > 0) {
-        if ($mean < $stdev * $reject_imfile_snr) {
-            print $logFile "Rejecting exposure based on bad imfile S/N for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile S/N for $name meets requirements: ";
-        }
-        print $logFile "mean: $mean vs stdev*SNlimit: " . $stdev * $reject_imfile_snr . "\n";
-    } else {
-        print $logFile "No rejection on imfile S/N for $name\n";
-    }
-
-    # reject exposure if, for any imfiles, the signal-to-noise of the
-    # imfile component means, based on the stdev of the binned image
-    # is less than the limit.  this test is sensible for images which
-    # have finite residual flux such as a flat-field image.
-    if ($reject_imfile_bin_stdev > 0) {
-        if ($binStdev > $reject_imfile_bin_stdev) {
-            print $logFile "Rejecting exposure based on bad imfile binned stdev for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile binned stdev for $name meets requirements: ";
-        }
-        print $logFile "$binStdev vs $reject_imfile_bin_stdev\n";
-    } else {
-        print $logFile "No rejection on imfile binned stdev for $name\n";
-    }
-    if ($reject_imfile_bin_snr > 0) {
-        if ($mean < $binStdev * $reject_imfile_bin_snr) {
-            print $logFile "Rejecting exposure based on bad imfile binned S/N for $name: ";
-            $reject = 1;
-        } else {
-            print $logFile "Imfile binned S/N for $name meets requirements: ";
-        }
-        print $logFile "mean: $mean vs binStdev*SNlimit: " . $binStdev * $reject_imfile_bin_snr . "\n";
-    } else {
-        print $logFile "No rejection on imfile binned S/N for $name\n";
-    }
-}
-
-# basic ensemble stats
-my $mean               = $stats->value_for_flag ("-bg");
-my $meanStdev          = $stats->value_for_flag ("-bg_mean_stdev");
-my $stdev              = $stats->value_for_flag ("-bg_stdev");
-my $binStdev           = $stats->value_for_flag ("-bin_stdev");
-my $fringe_mean        = $stats->value_for_flag ("-fringe_0");
-my $fringe_err         = $stats->value_for_flag ("-fringe_1");
-my $fringe_mean_stdev  = $stats->value_for_flag ("-fringe_2");
-my $dfringe_mean       = $stats->value_for_flag ("-fringe_resid_0");
-my $dfringe_err        = $stats->value_for_flag ("-fringe_resid_1");
-my $dfringe_mean_stdev = $stats->value_for_flag ("-fringe_resid_2");
-
-# other stats (flux depends on bg and exp_time)
-my $fluxStats = Statistics::Descriptive::Sparse->new(); # Statistics calculator for means
-$fluxStats->add_data(@fluxes);
-my $flux = $fluxStats->mean();  # Mean of the imfile means
-
-# other stats
-my $exp_snr = 0.0;
-if ($stdev > 0) { $exp_snr = $mean / $stdev; }
-
-## Reject based on the exposure ensemble stats
-# reject if the exposure ensemble mean is deviant
-unless ($no_op) {
-    print $logFile "Exposure mean $mean, stdev $stdev, mean stdev $meanStdev, exp s/n: $exp_snr\n";
-
-    # reject exposure if the ensemble mean residual counts deviate
-    # from the expected value by more than N sigma, (sigma = total
-    # pixel variance).  this test is sensible for images which should
-    # have a predictable nominal residual mean count value (eg, 0.0
-    # for a bias).  in general, use with ADDITIVE components
-    if ($reject_exp_mean > 0) {
-        if (abs($mean) > $reject_exp_mean * $stdev) {
-            print $logFile "Rejecting exposure based on bad mean counts: ";
-            $reject = 1;
-        } else {
-            print $logFile "Exposure mean counts meets requirements: ";
-        }
-        print $logFile "mean: $mean, stdev: $stdev (limit is: " . $reject_exp_mean * $stdev . ") \n";
-    } else {
-        print $logFile "No rejection for exp mean\n";
-    }
-
-    # reject exposure if, for any imfiles, the mean residual flux
-    # deviates from the expected value by more than N sigma, (sigma =
-    # total pixel variance).  this test is sensible for images which
-    # should have a predictable nominal residual flux value (eg, 0.0
-    # for a bias).  in general, use with ADDITIVE components
-    if ($reject_exp_flux > 0) {
-        if (abs($flux) > $reject_exp_flux * $stdev) {
-            print $logFile "Rejecting exposure based on bad mean flux: ";
-            $reject = 1;
-        } else {
-            print $logFile "Exposure mean flux meets requirements: ";
-        }
-        print $logFile "flux: $flux, stdev: $stdev (limit is: " . $reject_exp_flux * $stdev . ")\n";
-    } else {
-        print $logFile "No rejection for exp mean\n";
-    }
-
-    # reject exposure if the total pixel variance is larger than the
-    # limit
-    if ($reject_exp_stdev > 0) {
-        if ($stdev > $reject_exp_stdev) {
-            print $logFile "Rejecting exposure based on bad stdev: ";
-            $reject = 1;
-        } else {
-            print $logFile "Exposure stdev meets requirements: ";
-        }
-        print $logFile "$stdev vs $reject_exp_stdev\n";
-    } else {
-        print $logFile "No rejection for exp stdev\n";
-    }
-
-    # reject exposure if the variance of the imfile means is larger
-    # than the limit
-    if ($reject_exp_meanstdev > 0) {
-        if ($meanStdev > $reject_exp_meanstdev) {
-            print $logFile "Rejecting exposure based on bad mean stdev: ";
-            $reject = 1;
-        } else {
-            print $logFile "Exposure mean stdev meets requirements: ";
-        }
-        print $logFile "$meanStdev vs $reject_exp_meanstdev\n";
-    } else {
-        print $logFile "No rejection for exp mean stdev\n";
-    }
-
-    # reject if the signal-to-noise is insufficient
-    if ($reject_exp_snr > 0) {
-        if (abs($mean) < abs($stdev * $reject_exp_snr)) {
-            print $logFile "Rejecting exposure based on poor S/N: \n";
-            $reject = 1;
-        } else {
-            print $logFile "Exposure S/N meets requirements: \n";
-        }
-        print $logFile "signal: $mean vs noise: $stdev (s/n limit is: $reject_exp_snr)\n";
-    } else {
-        print $logFile "No rejection for exp S/N\n";
-    }
-    # reject if the exposure ensemble stdev is deviant
-    if ($reject_exp_bin_stdev > 0) {
-        if ($binStdev > $reject_exp_bin_stdev) {
-            print $logFile "Rejecting exposure based on bad binned stdev: ";
-            $reject = 1;
-        } else {
-            print $logFile "Exposure binned stdev meets requirements: ";
-        }
-        print $logFile "$stdev vs $reject_exp_bin_stdev\n";
-    } else {
-        print $logFile "No rejection for exp binned stdev\n";
-    }
-    # reject if the signal-to-noise is insufficient
-    if ($reject_exp_bin_snr > 0) {
-        if (abs($mean) < abs($binStdev * $reject_exp_bin_snr)) {
-            print $logFile "Rejecting exposure based on poor binned S/N: \n";
-            $reject = 1;
-        } else {
-            print $logFile "Exposure binned S/N meets requirements: \n";
-        }
-        print $logFile "signal: $mean vs noise: $binStdev (s/n limit is: $reject_exp_bin_snr)\n";
-    } else {
-        print $logFile "No rejection for exp binned S/N\n";
-    }
-
-    close $logFile;
-}
-
-$command  = "$dettool -addresidexp -det_id $det_id -iteration $iter -exp_id $exp_id";
-$command .= " -recip $recipe1,$recipe2 -path_base $outroot ";
-$command .= ' -reject' if $reject;
-$command .= " -dbname $dbname" if defined $dbname;
-$command .= $stats->cmdflags();
-
-unless ($no_update) {
-    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => $verbose);
-    unless ($success) {
-        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        warn("Unable to perform dettool -addresidexp: $error_code\n");
-        exit($error_code);
-    }
-} else {
-    print "skipping command: $command\n";
-}
-
-END {
-    my $status = $?;
-    system("sync") == 0
-        or die "failed to execute sync: $!" ;
-    $? = $status;
-}
-
-
-sub my_die
-{
-    my $msg = shift; # Warning message on die
-    my $det_id = shift;         # Detrend identifier
-    my $iter = shift;           # Iteration
-    my $exp_id = shift; # Exposure tag
-    my $exit_code = shift; # Exit code to add
-
-    carp($msg);
-    if (defined $det_id and defined $iter and defined $exp_id and not $no_update) {
-        my $command = "$dettool -addresidexp";
-        $command .= " -det_id $det_id";
-        $command .= " -iteration $iter";
-        $command .= " -exp_id $exp_id";
-        $command .= " -code $exit_code";
-        $command .= " -dbname $dbname" if defined $dbname;
-        system ($command);
-    }
-    exit $exit_code;
-}
-
-# Retrieve the requested rejection limit, dying if not extant
-sub rejection_limit
-{
-    my $name = shift;           # Rejection limit to
-    my $type = shift;           # Type of exposure
-    my $filter = shift;         # Filter
-
-    my $value = $ipprc->rejection( $name, $det_type, $filter );
-    if (not defined $value) {
-        $filter = "(no filter)" if not defined $filter;
-        die "Unable to determine $name rejection limit for $det_type with $filter.\n";
-    }
-
-    return $value;
-}
-
-__END__
-
-####
-
-## this function is not well though out.  it loads a collection of
-## values (background mean and stdev) for a collection of imfile
-## subcomponents.  it then measures the mean background, the
-## background stdev (rms of ensemble stdevs), and the background mean
-## stdev (rms of the means).  it then tries to reject based on the
-## following criteria:
-## (background / stdev > limit) for a single component
-##    ---> this will ACCEPT for a poor images (large stdev)
-## (stdev > limit)
-## (mean background / stdev > limit) same problem
-## (mean stdev > limit)
-
-### I would suggest the following:
-## 1) calculate the ensemble mean and stdev
-## 2) for each component, is the (back - mean) / mean stdev > limit?
-##    (ie, is it an outlier?)
-## 3) is the component stdev > limit? (absolute test)
-## 4) calculate the background stdev for the ensemble (excluding rejects)
-## 5) is the mean stdev > limit (poor images)
-## 6) calculate the ensemble stdev (rms) of remaining (excluding rejects)
-## 7) is the ensemble stdev > limit
-
-## for flats, the value used for stdev should be the fractional stdev
-## (stdev/mean) and no rejection should be performed on the basis of
-## the mean value, but could still be done on the mean stdev
-
-## the same logical cuts above can be applied to components in an
-## imfile, imfiles in an exposure, and exposures in a stack
-
-### this function needs to avoid div by zero: compare Signal vs Noise*limit
Index: unk/ippScripts/scripts/detrend_resid.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_resid.pl	(revision 18561)
+++ 	(revision )
@@ -1,264 +1,0 @@
-#!/usr/bin/env perl
-
-use Carp;
-use warnings;
-use strict;
-
-## report the program and machine
-use Sys::Hostname;
-my $host = hostname();
-print "\n\n";
-print "Starting script $0 on $host\n\n";
-
-use vars qw( $VERSION );
-$VERSION = '0.01';
-
-use IPC::Cmd 0.36 qw( can_run run );
-use PS::IPP::Metadata::Config;
-use PS::IPP::Metadata::Stats;
-use PS::IPP::Config 1.01 qw( :standard );
-
-my $ipprc = PS::IPP::Config->new(); # IPP configuration
-
-use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
-use Pod::Usage qw( pod2usage );
-
-my ( $det_id, $iter, $exp_id, $exp_tag, $class_id, $det_type, $detrend, $input_uri, $camera, $mode, $outroot,
-     $dbname, $reduction, $verbose, $no_update, $no_op, $redirect );
-GetOptions(
-    'det_id|d=s'        => \$det_id,
-    'iteration=s'       => \$iter,
-    'exp_id|e=s'        => \$exp_id,
-    'exp_tag|=s'        => \$exp_tag,
-    'class_id|i=s'      => \$class_id,
-    'det_type|t=s'      => \$det_type,
-    'detrend=s'         => \$detrend,
-    'input_uri|u=s'     => \$input_uri,
-    'camera|c=s'        => \$camera,
-    'mode|m=s'          => \$mode,
-    'outroot|w=s'       => \$outroot,   # output file base name
-    'dbname|d=s'        => \$dbname, # Database name
-    'reduction=s'       => \$reduction, # Reduction class
-    'verbose'           => \$verbose,   # Print to stdout
-    'no-update'         => \$no_update,
-    'no-op'             => \$no_op,
-    'redirect-output'   => \$redirect,
-) or pod2usage( 2 );
-
-pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
-pod2usage( -msg => "Required options: --det_id --iteration --exp_id --exp_tag --class_id --det_type --camera --input_uri --mode --detrend --outroot (not for 'verify' mode)",
-           -exitval => 3) unless
-    defined $det_id    and
-    defined $iter      and
-    defined $exp_id    and
-    defined $exp_tag   and
-    defined $class_id  and
-    defined $det_type  and
-    defined $input_uri and
-    defined $camera    and
-    defined $mode      and
-    defined $outroot   and
-    (defined $detrend or lc($mode) eq 'verify');
-
-$ipprc->define_camera($camera);
-my $logDest     = $ipprc->filename("LOG.IMFILE", $outroot, $class_id);
-if ($redirect) {
-    $ipprc->redirect_output($logDest);
-}
-
-# Recipes to use as a function of detrend type and mode
-$reduction = 'DETREND' unless defined $reduction;
-my $recipe;                     # Name of recipe to use
-if ($mode eq 'master') {
-    $recipe = uc($det_type) . '_RESID';
-} elsif ($mode eq 'verify') {
-    $recipe = uc($det_type) . '_VERIFY';
-} else {
-    &my_die("Unrecognised mode: $mode", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
-}
-$recipe = $ipprc->reduction($reduction, $recipe);
-
-# values to extract from output metadata and the stats to calculate
-my $STATS =
-   [
-       #          PPSTATS KEYWORD         STATISTIC          CHIPTOOL FLAG
-       { name => "ROBUST_MEDIAN",      type => "mean",  flag => "-bg",             dtype => "float" },
-       { name => "ROBUST_MEDIAN",      type => "stdev", flag => "-bg_mean_stdev",  dtype => "float" },
-       { name => "ROBUST_STDEV",       type => "rms",   flag => "-bg_stdev",       dtype => "float" },
-       { name => "SAMPLE_SKEWNESS",    type => "mean",  flag => "-bg_skewness",    dtype => "float" },
-       { name => "SAMPLE_KURTOSIS",    type => "mean",  flag => "-bg_kurtosis",    dtype => "float" },
-       { name => "FRINGE_0",           type => "mean",  flag => "-fringe_0",       dtype => "float" },
-       { name => "FRINGE_ERR_0",       type => "rms",   flag => "-fringe_1",       dtype => "float" },
-       { name => "FRINGE_0",           type => "stdev", flag => "-fringe_2",       dtype => "float" },
-       { name => "FRINGE_RESID_0",     type => "mean",  flag => "-fringe_resid_0", dtype => "float" },
-       { name => "FRINGE_RESID_ERR_0", type => "rms",   flag => "-fringe_resid_1", dtype => "float" },
-       { name => "FRINGE_RESID_0",     type => "stdev", flag => "-fringe_resid_2", dtype => "float" },
-   ];
-my $stats = PS::IPP::Metadata::Stats->new($STATS); # Stats parser
-
-my $BINNED_STATS =
-   [
-       { name => "ROBUST_STDEV",   type => "rms",   flag => "-bin_stdev" },
-   ];
-my $binnedStats = PS::IPP::Metadata::Stats->new($BINNED_STATS); # Stats parser
-
-# Flags to specify the particular detrend to use
-use constant DETRENDS => {
-    'bias'     	       => '-bias',      # Specify the bias frame
-    'dark'     	       => '-dark',      # Specify the dark frame
-    'dark_premask'     => '-dark',      # Specify the dark frame
-    'shutter'  	       => '-shutter',   # Specify the shutter frame
-    'flat'     	       => '-flat',      # Specify the flat frame
-    'domeflat' 	       => '-flat',      # Specify the flat frame
-    'skyflat'  	       => '-flat',      # Specify the flat frame
-    'flat_premask'     => '-flat',      # Specify the flat frame
-    'domeflat_premask' => '-flat',      # Specify the flat frame
-    'skyflat_premask'  => '-flat',      # Specify the flat frame
-    'fringe'   	       => '-fringe',    # Specify the fringe frame
-    'mask'     	       => '-mask',      # Specify the mask frame
-    'darkmask' 	       => '-mask',      # Specify the mask frame
-    'flatmask' 	       => '-mask',      # Specify the mask frame
-};
-
-use constant DELETE_STATS => 0; # Delete the statistics file when done?
-
-# 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);
-my $ppStats = can_run('ppStats') or (warn "Can't find ppStats" and $missing_tools = 1);
-if ($missing_tools) {
-    warn("Can't find required tools.");
-    exit($PS_EXIT_CONFIG_ERROR);
-}
-
-# outroot examples (HOST components must be set)
-# file://data/ipp004.0/gpc1/20080130
-# neb:///ipp004-v1/gpc1/20080130
-# neb:///*/gpc1/20080130 (volume not specified)
-
-# check for existing directory, generate if needed
-$ipprc->outroot_prepare($outroot);
-
-# XXX use PPIMAGE.OUTPUT.RESID for output file (compressed, with pos & neg range allowed)
-# my $outputName  = $ipprc->filename("PPIMAGE.OUTPUT", $outroot, $class_id);
-
-my $outputName  = $ipprc->filename("PPIMAGE.OUTPUT.RESID", $outroot, $class_id);
-my $bin1Name    = $ipprc->filename("PPIMAGE.BIN1",   $outroot, $class_id);
-my $bin2Name    = $ipprc->filename("PPIMAGE.BIN2",   $outroot, $class_id);
-my $outputStats = $ipprc->filename("PPIMAGE.STATS",  $outroot, $class_id);
-my $traceDest   = $ipprc->filename("TRACE.IMFILE",   $outroot, $class_id);
-
-# Run ppImage & ppStats
-unless ($no_op) {
-    my $command = "$ppImage -file $input_uri $outroot";
-    $command .= " -recipe PPIMAGE $recipe";
-    $command .= " -recipe PPSTATS RESIDUAL";
-    $command .= " -F PPIMAGE.OUTPUT PPIMAGE.OUTPUT.RESID";
-    $command .= " -stats $outputStats";
-    $command .= " -tracedest $traceDest -log $logDest";
-    $command .= " -dbname $dbname" if defined $dbname;
-
-    # Detrend to use in processing
-    if (lc($mode) ne 'verify') {
-        my $detFlag = DETRENDS->{lc($det_type)};
-        &my_die("Unrecognised detrend type: $det_type", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR) unless defined $detFlag;
-        $command .= " $detFlag $detrend";
-    }
-
-    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => $verbose);
-    unless ($success) {
-        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        &my_die("Unable to perform ppImage: $error_code", $det_id, $iter, $exp_id, $class_id, $error_code);
-    }
-    &my_die("Couldn't find expected output file: $outputName", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($outputName);
-    &my_die("Couldn't find expected output file: $outputStats", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($outputStats);
-    &my_die("Couldn't find expected output file: $bin1Name", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($bin1Name);
-    &my_die("Couldn't find expected output file: $bin2Name", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($bin2Name);
-
-    # Load the raw output stats file
-    my $statsFile;              # File handle
-    open $statsFile, $ipprc->file_resolve($outputStats) or &my_die("Can't open statistics file $outputStats: $!", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR);
-    my @contents = <$statsFile>; # Contents of file
-    close $statsFile;
-
-    # Parse the stats file contents into a metadata
-    my $mdcParser = PS::IPP::Metadata::Config->new;     # Parser for metadata config files
-    my $metadata = $mdcParser->parse(join "", @contents) or &my_die("Unable to parse metadata config doc", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
-
-    # Parse the statistics on the residual image
-    $stats->parse($metadata) or &my_die("Unable to find all values in statistics output.", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
-
-    # run ppStats on the binned image
-    $command = "$ppStats -recipe PPSTATS RESIDUAL $bin2Name";
-    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => $verbose);
-    unless ($success) {
-        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        &my_die("Unable to perform ppStats: $error_code", $det_id, $iter, $exp_id, $class_id, $error_code);
-    }
-
-    # Parse the output contents into a metadata
-    my $binnedMetadata = $mdcParser->parse(join "", @$stdout_buf) or &my_die("Unable to parse metadata output", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
-
-    # parse the binned image statistics
-    $binnedStats->parse($binnedMetadata) or &my_die("Unable to find all values in statistics output.", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
-}
-
-# Command to update the database
-my $command = "$dettool -addresidimfile";
-$command .= " -det_id $det_id";
-$command .= " -iteration $iter";
-$command .= " -exp_id $exp_id";
-$command .= " -class_id $class_id";
-$command .= " -recip $recipe";
-$command .= " -uri $outputName";
-$command .= " -path_base $outroot";
-$command .= " -dbname $dbname" if defined $dbname;
-$command .= $stats->cmdflags();
-$command .= $binnedStats->cmdflags();
-
-# Add the processed file to the database
-unless ($no_update) {
-    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-        run(command => $command, verbose => $verbose);
-    unless ($success) {
-        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        warn("Unable to perform dettool -addresidimfile: $error_code\n");
-        exit($error_code);
-    }
-} else {
-    print "skipping command: $command\n";
-}
-
-sub my_die
-{
-    my $msg = shift; # Warning message on die
-    my $det_id = shift;         # Detrend identifier
-    my $iter = shift;           # Iteration
-    my $exp_id = shift; # Exposure tag
-    my $class_id = shift; # Class identifier
-    my $exit_code = shift; # Exit code to add
-
-    carp($msg);
-    if (defined $det_id and defined $iter and defined $exp_id and not $no_update) {
-        my $command = "$dettool -addresidimfile";
-        $command .= " -det_id $det_id";
-        $command .= " -iteration $iter";
-        $command .= " -exp_id $exp_id";
-        $command .= " -class_id $class_id";
-        $command .= " -code $exit_code";
-        $command .= " -dbname $dbname" if defined $dbname;
-        system ($command);
-    }
-    exit $exit_code;
-}
-
-END {
-    my $exit = $?;
-    system("sync") == 0 or die "failed to execute sync: $!";
-    $? = $exit;
-}
-
-__END__
Index: /trunk/ippScripts/scripts/detrend_resid_exp.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_resid_exp.pl	(revision 18562)
+++ /trunk/ippScripts/scripts/detrend_resid_exp.pl	(revision 18562)
@@ -0,0 +1,601 @@
+#!/usr/bin/env perl
+
+# this program has two jobs:
+# 1: for the given exp_tag, generate the binned & mosaiced JPEG images
+# 2: examine the collection of per-imfile statistics and reject.  At the moment,
+#    this program (and the database) only allows rejection at the exposure level,
+#    not at the imfile level.
+
+use Carp;
+use warnings;
+use strict;
+
+## report the program and machine
+use Sys::Hostname;
+my $host = hostname();
+print "\n\n";
+print "Starting script $0 on $host\n\n";
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd 0.36 qw( can_run run );             # tools to run UNIX programs with control over I/O
+use PS::IPP::Metadata::Config;                   # tools to parse the psMetadataConfig files
+use PS::IPP::Metadata::Stats;
+
+use PS::IPP::Metadata::List qw( parse_md_list ); # tools to parse a metadata into a hash list
+use Statistics::Descriptive;                     # tools for calculating basic statistical quantities
+use File::Temp qw( tempfile );                   # tools to construct temp files
+use PS::IPP::Config 1.01 qw( :standard );
+
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt ); # option parsing
+use Pod::Usage qw( pod2usage );
+
+# parse the command-line options
+my ( $det_id, $iter, $exp_id, $exp_tag, $det_type, $camera, $filter, $reject, $outroot, $dbname, $reduction,
+     $verbose, $no_update, $no_op, $save_temps, $redirect );
+GetOptions(
+           'det_id|d=s'        => \$det_id,
+           'iteration=s'       => \$iter,
+           'exp_id|e=s'        => \$exp_id,
+           'exp_tag|=s'        => \$exp_tag,
+           'det_type|t=s'      => \$det_type,
+           'camera=s'          => \$camera,
+           'outroot|w=s'       => \$outroot,   # output file base name
+           'filter=s'          => \$filter,
+           'reject'            => \$reject,
+           'dbname|d=s'        => \$dbname, # Database name
+           'reduction|=s'      => \$reduction,
+           'verbose'           => \$verbose,   # Print to stdout
+           'no-update'         => \$no_update,
+           'no-op'             => \$no_op,
+           'save-temps'        => \$save_temps, # Save temporary files?
+           'redirect-output'   => \$redirect,   # redirect output to LOG.EXP
+           ) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage( -msg => "Required options: --det_id --iteration --exp_id --exp_tag --det_type --camera --outroot",
+           -exitval => 3) unless
+    defined $det_id   and
+    defined $iter     and
+    defined $exp_id   and
+    defined $exp_tag  and
+    defined $det_type and
+    defined $camera   and
+    defined $outroot;
+
+# load IPP config information for the specified camera
+$ipprc->define_camera($camera);
+if ($redirect) {
+    my $logDest = $ipprc->filename("LOG.EXP", $outroot)
+       or &my_die("Missing entry from camera config", $det_id, $iter, $exp_id, $PS_EXIT_CONFIG_ERROR);
+    $ipprc->redirect_output($logDest);
+}
+
+# Recipes to use based on reduction class
+$reduction = 'DETREND' unless defined $reduction;
+
+my $recipe1 = $ipprc->reduction($reduction, 'JPEG_BIN1_RESID_' . uc($det_type)); # Recipe to use
+&my_die("Unrecognised detrend type: $det_type", $det_id, $iter, $PS_EXIT_PROG_ERROR) unless defined $recipe1;
+
+my $recipe2 = $ipprc->reduction($reduction, 'JPEG_BIN2_RESID_' . uc($det_type)); # Recipe to use
+&my_die("Unrecognised detrend type: $det_type", $det_id, $iter, $PS_EXIT_PROG_ERROR) unless defined $recipe2;
+
+# values to extract from output metadata and the stats to calculate
+# XXX -bg_mean_stdev should take rms of bg_mean_stdev if bg_mean_stdev != 0 (A)
+# XXX -bg_mean_stdev should take stdev of bg_mean if bg_mean_stdev == 0     (B)
+# XXX  (A) if imfile.Ncomp > 1, (B) if imfile.Ncomp == 1
+my $STATS =
+    [
+        #          KEYWORD                 STATISTIC          CHIPTOOL FLAG
+        { name => "bg",             type => "mean",  flag => "-bg",            dtype => "float" },
+        { name => "bg_mean_stdev",  type => "stdev", flag => "-bg_mean_stdev", dtype => "float" },
+        { name => "bg_stdev",       type => "rms",   flag => "-bg_stdev",      dtype => "float" },
+        { name => "bg_skewness",    type => "mean",  flag => "-bg_skewness",   dtype => "float" },
+        { name => "bg_kurtosis",    type => "mean",  flag => "-bg_kurtosis",   dtype => "float" },
+        { name => "bin_stdev",      type => "rms",   flag => "-bin_stdev",     dtype => "float" },
+        { name => "fringe_0",       type => "mean",  flag => "-fringe_0",      dtype => "float" },
+        { name => "fringe_1",       type => "rms",   flag => "-fringe_1",      dtype => "float" },
+        { name => "fringe_0",       type => "stdev", flag => "-fringe_2",      dtype => "float" },
+        { name => "user_1",         type => "mean",  flag => "-user_1",        dtype => "float" }, # fringe residual
+        { name => "user_2",         type => "rms",   flag => "-user_2",        dtype => "float" }, # fringe residual
+        { name => "user_1",         type => "stdev", flag => "-user_3",        dtype => "float" }, # fringe residual
+        ];
+my $stats = PS::IPP::Metadata::Stats->new($STATS); # Stats parser
+
+# 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);
+if ($missing_tools) {
+    warn("Can't find required tools.");
+    exit($PS_EXIT_CONFIG_ERROR);
+}
+
+# Get list of imfile files
+my ($files, $command, $success, $error_code, $full_buf, $stdout_buf, $stderr_buf);
+{
+    # dettool command to select imfile data for this exp_id
+    $command  = "$dettool -residimfile";
+    $command .= " -det_id $det_id";
+    $command .= " -iteration $iter";
+    $command .= " -exp_id $exp_id";
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        warn("Unable to perform dettool -residimfile: $error_code\n");
+        exit($error_code);
+    }
+    # XXX report an error message if stdout_buf is empty
+
+    # Parse the stdout buffer into a metadata
+    my $mdcParser = PS::IPP::Metadata::Config->new;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", $det_id, $iter, $exp_id, $PS_EXIT_PROG_ERROR);
+
+    # parse the file info in the metadata
+    $files = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", $det_id, $iter, $exp_id, $PS_EXIT_PROG_ERROR);
+
+    # Parse the statistics on the residual image
+    $stats->parse($metadata) or &my_die("Unable to find all values in statistics output.", $det_id, $iter, $exp_id, $PS_EXIT_PROG_ERROR);
+}
+
+# outroot examples (HOST components must be set)
+# file://data/ipp004.0/gpc1/20080130
+# neb:///ipp004-v1/gpc1/20080130
+# neb:///*/gpc1/20080130 (volume not specified)
+
+# check for existing directory, generate if needed
+$ipprc->outroot_prepare($outroot);
+
+my $jpeg1Name  = $ipprc->filename("PPIMAGE.JPEG1", $outroot); # Binned JPEG #1
+my $jpeg2Name  = $ipprc->filename("PPIMAGE.JPEG2", $outroot); # Binned JPEG #2
+
+# XXX in debug mode, unlink = 0
+my ($list1File, $list1Name) = tempfile( "$exp_tag.detresid.$det_id.$iter.b1.list.XXXX", UNLINK => !$save_temps );
+my ($list2File, $list2Name) = tempfile( "$exp_tag.detresid.$det_id.$iter.b2.list.XXXX", UNLINK => !$save_temps );
+foreach my $file (@$files) {
+    print $list1File ($ipprc->filename( "PPIMAGE.BIN1", $file->{path_base}, $file->{class_id} ) . "\n");
+    print $list2File ($ipprc->filename( "PPIMAGE.BIN2", $file->{path_base}, $file->{class_id} ) . "\n");
+}
+close $list1File;
+close $list2File;
+
+
+# build the JPEG images
+unless ($no_op) {
+    # Make the jpeg for binning 1
+    $command = "$ppImage -list $list1Name $outroot -recipe PPIMAGE $recipe1"; # Command to run
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        &my_die("Unable to run ppImage: $error_code", $det_id, $iter, $exp_id, $error_code);
+    }
+    &my_die("Unable to find expected output file: $jpeg1Name", $det_id, $iter, $exp_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($jpeg1Name);
+
+    # Make the jpeg for binning 2
+    $command = "$ppImage -list $list2Name $outroot -recipe PPIMAGE $recipe2"; # Command to run
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        &my_die("Unable to run ppImage: $error_code", $det_id, $iter, $exp_id, $error_code);
+    }
+    &my_die("Unable to find expected output file: $jpeg2Name", $det_id, $iter, $exp_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($jpeg2Name);
+}
+
+#### measure stats and reject if needed ####
+
+# Rejection thresholds & related data
+my $expected                = rejection_limit( 'EXPECTED',         $det_type, $filter );
+my $reject_imfile_mean      = rejection_limit( 'IMFILE.MEAN',      $det_type, $filter );
+my $reject_imfile_flux      = rejection_limit( 'IMFILE.FLUX',      $det_type, $filter );
+my $reject_imfile_stdev     = rejection_limit( 'IMFILE.STDEV',     $det_type, $filter );
+my $reject_imfile_skewness  = rejection_limit( 'IMFILE.SKEWNESS',  $det_type, $filter );
+my $reject_imfile_kurtosis  = rejection_limit( 'IMFILE.KURTOSIS',  $det_type, $filter );
+my $reject_imfile_meanstdev = rejection_limit( 'IMFILE.MEANSTDEV', $det_type, $filter );
+my $reject_imfile_snr       = rejection_limit( 'IMFILE.SNR',       $det_type, $filter );
+my $reject_imfile_bin_stdev = rejection_limit( 'IMFILE.BIN.STDEV', $det_type, $filter );
+my $reject_imfile_bin_snr   = rejection_limit( 'IMFILE.BIN.SNR',   $det_type, $filter );
+my $reject_exp_mean         = rejection_limit( 'EXP.MEAN',         $det_type, $filter );
+my $reject_exp_flux         = rejection_limit( 'EXP.FLUX',         $det_type, $filter );
+my $reject_exp_stdev        = rejection_limit( 'EXP.STDEV',        $det_type, $filter );
+my $reject_exp_meanstdev    = rejection_limit( 'EXP.MEANSTDEV',    $det_type, $filter );
+my $reject_exp_snr          = rejection_limit( 'EXP.SNR',          $det_type, $filter );
+my $reject_exp_bin_stdev    = rejection_limit( 'EXP.BIN.STDEV',    $det_type, $filter );
+my $reject_exp_bin_snr      = rejection_limit( 'EXP.BIN.SNR',      $det_type, $filter );
+
+# storage array
+my @fluxes;
+
+foreach my $file (@$files) {
+    my $name      = $file->{class_id};
+    my $mean      = $file->{bg};        # Mean for this imfile
+    my $stdev     = $file->{bg_stdev}; # Stdev for this imfile
+    my $skewness  = $file->{bg_skewness}; # Skewness for this imfile
+    my $kurtosis  = $file->{bg_kurtosis}; # Kurtosis for this imfile
+    my $meanStdev = $file->{bg_mean_stdev}; # Stdev of Means for this imfile
+    my $binStdev  = $file->{bin_stdev}; # Binned Stdev for this imfile
+
+    # calculate and save the fluxes
+    my $flux;
+    if ($file->{exp_time} == 0.0) {
+        $flux = $mean;
+    } else {
+        $flux = $mean / $file->{exp_time};
+    }
+    push @fluxes, $flux;
+
+    $mean -= $expected;
+
+    last if $no_op;
+
+    # reject exposure if, for any imfiles, the mean residual counts
+    # deviate from the expected value by more than N sigma, (sigma =
+    # total pixel variance).  this test is sensible for images which
+    # should have a predictable nominal residual mean count value (eg,
+    # 0.0 for a bias).   in general, use with ADDITIVE components
+    if ($reject_imfile_mean > 0) {
+        if (abs($mean) > $reject_imfile_mean * $stdev) {
+            print "Rejecting exposure based on bad imfile mean for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile mean for $name meets requirements: ";
+        }
+        print "$mean vs $reject_imfile_mean * $stdev\n";
+    }  else {
+        print "No rejection on imfile mean for $name\n";
+    }
+
+    # reject exposure if, for any imfiles, the mean residual flux
+    # deviates from the expected value by more than N sigma, (sigma =
+    # total pixel variance).  this test is sensible for images which
+    # should have a predictable nominal residual flux value (eg, 0.0
+    # for a bias).  in general, use with ADDITIVE components
+    if ($reject_imfile_flux > 0) {
+        if (abs($flux) > $reject_imfile_flux) {
+            print "Rejecting exposure based on bad imfile flux for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile flux for $name meets requirements: ";
+        }
+        print "$flux vs $reject_imfile_flux\n";
+    }  else {
+        print "No rejection on imfile flux for $name\n";
+    }
+
+    # reject exposure if, for any imfiles, the total pixel variance is
+    # larger than the limit
+    if ($reject_imfile_stdev > 0) {
+        if ($stdev > $reject_imfile_stdev) {
+            print "Rejecting exposure based on bad imfile stdev for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile stdev for $name meets requirements: ";
+        }
+        print "$stdev vs $reject_imfile_stdev\n";
+
+    } else {
+        print "No rejection on imfile stdev for $name\n";
+    }
+
+    # reject exposure if, for any imfiles, the skewness is
+    # larger than the limit
+    if ($reject_imfile_skewness > 0) {
+        if ($stdev > $reject_imfile_skewness) {
+            print "Rejecting exposure based on bad imfile skewness for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile skewness for $name meets requirements: ";
+        }
+        print "$skewness vs $reject_imfile_skewness\n";
+
+    } else {
+        print "No rejection on imfile skewness for $name\n";
+    }
+
+    # reject exposure if, for any imfiles, the kurtosis is
+    # larger than the limit
+    if ($reject_imfile_kurtosis > 0) {
+        if ($stdev > $reject_imfile_kurtosis) {
+            print "Rejecting exposure based on bad imfile kurtosis for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile kurtosis for $name meets requirements: ";
+        }
+        print "$kurtosis vs $reject_imfile_kurtosis\n";
+
+    } else {
+        print "No rejection on imfile kurtosis for $name\n";
+    }
+
+    # reject exposure if, for any imfiles, the variance of the imfile
+    # component means is larger than the limit
+    if ($reject_imfile_meanstdev > 0) {
+        if ($meanStdev > $reject_imfile_meanstdev) {
+            print "Rejecting exposure based on bad imfile mean stdev for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile mean stdev for $name meets requirements: ";
+        }
+        print "$meanStdev vs $reject_imfile_meanstdev\n";
+    } else {
+        print "No rejection on imfile mean stdev for $name\n";
+    }
+
+    # reject exposure if, for any imfiles, the signal-to-noise (ie,
+    # the mean counts / total pixel variance) of the imfile component
+    # means are less than the limit.  this test is sensible for images
+    # which have finite residual flux such as a flat-field image.
+    if ($reject_imfile_snr > 0) {
+        if ($mean < $stdev * $reject_imfile_snr) {
+            print "Rejecting exposure based on bad imfile S/N for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile S/N for $name meets requirements: ";
+        }
+        print "mean: $mean vs stdev*SNlimit: " . $stdev * $reject_imfile_snr . "\n";
+    } else {
+        print "No rejection on imfile S/N for $name\n";
+    }
+
+    # reject exposure if, for any imfiles, the signal-to-noise of the
+    # imfile component means, based on the stdev of the binned image
+    # is less than the limit.  this test is sensible for images which
+    # have finite residual flux such as a flat-field image.
+    if ($reject_imfile_bin_stdev > 0) {
+        if ($binStdev > $reject_imfile_bin_stdev) {
+            print "Rejecting exposure based on bad imfile binned stdev for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile binned stdev for $name meets requirements: ";
+        }
+        print "$binStdev vs $reject_imfile_bin_stdev\n";
+    } else {
+        print "No rejection on imfile binned stdev for $name\n";
+    }
+    if ($reject_imfile_bin_snr > 0) {
+        if ($mean < $binStdev * $reject_imfile_bin_snr) {
+            print "Rejecting exposure based on bad imfile binned S/N for $name: ";
+            $reject = 1;
+        } else {
+            print "Imfile binned S/N for $name meets requirements: ";
+        }
+        print "mean: $mean vs binStdev*SNlimit: " . $binStdev * $reject_imfile_bin_snr . "\n";
+    } else {
+        print "No rejection on imfile binned S/N for $name\n";
+    }
+}
+
+# basic ensemble stats
+my $mean               = $stats->value_for_flag ("-bg");
+my $meanStdev          = $stats->value_for_flag ("-bg_mean_stdev");
+my $stdev              = $stats->value_for_flag ("-bg_stdev");
+my $binStdev           = $stats->value_for_flag ("-bin_stdev");
+my $fringe_mean        = $stats->value_for_flag ("-fringe_0");
+my $fringe_err         = $stats->value_for_flag ("-fringe_1");
+my $fringe_mean_stdev  = $stats->value_for_flag ("-fringe_2");
+my $dfringe_mean       = $stats->value_for_flag ("-fringe_resid_0");
+my $dfringe_err        = $stats->value_for_flag ("-fringe_resid_1");
+my $dfringe_mean_stdev = $stats->value_for_flag ("-fringe_resid_2");
+
+# other stats (flux depends on bg and exp_time)
+my $fluxStats = Statistics::Descriptive::Sparse->new(); # Statistics calculator for means
+$fluxStats->add_data(@fluxes);
+my $flux = $fluxStats->mean();  # Mean of the imfile means
+
+# other stats
+my $exp_snr = 0.0;
+if ($stdev > 0) { $exp_snr = $mean / $stdev; }
+
+## Reject based on the exposure ensemble stats
+# reject if the exposure ensemble mean is deviant
+unless ($no_op) {
+    print "Exposure mean $mean, stdev $stdev, mean stdev $meanStdev, exp s/n: $exp_snr\n";
+
+    # reject exposure if the ensemble mean residual counts deviate
+    # from the expected value by more than N sigma, (sigma = total
+    # pixel variance).  this test is sensible for images which should
+    # have a predictable nominal residual mean count value (eg, 0.0
+    # for a bias).  in general, use with ADDITIVE components
+    if ($reject_exp_mean > 0) {
+        if (abs($mean) > $reject_exp_mean * $stdev) {
+            print "Rejecting exposure based on bad mean counts: ";
+            $reject = 1;
+        } else {
+            print "Exposure mean counts meets requirements: ";
+        }
+        print "mean: $mean, stdev: $stdev (limit is: " . $reject_exp_mean * $stdev . ") \n";
+    } else {
+        print "No rejection for exp mean\n";
+    }
+
+    # reject exposure if, for any imfiles, the mean residual flux
+    # deviates from the expected value by more than N sigma, (sigma =
+    # total pixel variance).  this test is sensible for images which
+    # should have a predictable nominal residual flux value (eg, 0.0
+    # for a bias).  in general, use with ADDITIVE components
+    if ($reject_exp_flux > 0) {
+        if (abs($flux) > $reject_exp_flux * $stdev) {
+            print "Rejecting exposure based on bad mean flux: ";
+            $reject = 1;
+        } else {
+            print "Exposure mean flux meets requirements: ";
+        }
+        print "flux: $flux, stdev: $stdev (limit is: " . $reject_exp_flux * $stdev . ")\n";
+    } else {
+        print "No rejection for exp mean\n";
+    }
+
+    # reject exposure if the total pixel variance is larger than the
+    # limit
+    if ($reject_exp_stdev > 0) {
+        if ($stdev > $reject_exp_stdev) {
+            print "Rejecting exposure based on bad stdev: ";
+            $reject = 1;
+        } else {
+            print "Exposure stdev meets requirements: ";
+        }
+        print "$stdev vs $reject_exp_stdev\n";
+    } else {
+        print "No rejection for exp stdev\n";
+    }
+
+    # reject exposure if the variance of the imfile means is larger
+    # than the limit
+    if ($reject_exp_meanstdev > 0) {
+        if ($meanStdev > $reject_exp_meanstdev) {
+            print "Rejecting exposure based on bad mean stdev: ";
+            $reject = 1;
+        } else {
+            print "Exposure mean stdev meets requirements: ";
+        }
+        print "$meanStdev vs $reject_exp_meanstdev\n";
+    } else {
+        print "No rejection for exp mean stdev\n";
+    }
+
+    # reject if the signal-to-noise is insufficient
+    if ($reject_exp_snr > 0) {
+        if (abs($mean) < abs($stdev * $reject_exp_snr)) {
+            print "Rejecting exposure based on poor S/N: \n";
+            $reject = 1;
+        } else {
+            print "Exposure S/N meets requirements: \n";
+        }
+        print "signal: $mean vs noise: $stdev (s/n limit is: $reject_exp_snr)\n";
+    } else {
+        print "No rejection for exp S/N\n";
+    }
+    # reject if the exposure ensemble stdev is deviant
+    if ($reject_exp_bin_stdev > 0) {
+        if ($binStdev > $reject_exp_bin_stdev) {
+            print "Rejecting exposure based on bad binned stdev: ";
+            $reject = 1;
+        } else {
+            print "Exposure binned stdev meets requirements: ";
+        }
+        print "$stdev vs $reject_exp_bin_stdev\n";
+    } else {
+        print "No rejection for exp binned stdev\n";
+    }
+    # reject if the signal-to-noise is insufficient
+    if ($reject_exp_bin_snr > 0) {
+        if (abs($mean) < abs($binStdev * $reject_exp_bin_snr)) {
+            print "Rejecting exposure based on poor binned S/N: \n";
+            $reject = 1;
+        } else {
+            print "Exposure binned S/N meets requirements: \n";
+        }
+        print "signal: $mean vs noise: $binStdev (s/n limit is: $reject_exp_bin_snr)\n";
+    } else {
+        print "No rejection for exp binned S/N\n";
+    }
+}
+
+$command  = "$dettool -addresidexp -det_id $det_id -iteration $iter -exp_id $exp_id";
+$command .= " -recip $recipe1,$recipe2 -path_base $outroot ";
+$command .= ' -reject' if $reject;
+$command .= " -dbname $dbname" if defined $dbname;
+$command .= $stats->cmdflags();
+
+unless ($no_update) {
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        warn("Unable to perform dettool -addresidexp: $error_code\n");
+        exit($error_code);
+    }
+} else {
+    print "skipping command: $command\n";
+}
+
+END {
+    my $status = $?;
+    system("sync") == 0
+        or die "failed to execute sync: $!" ;
+    $? = $status;
+}
+
+
+sub my_die
+{
+    my $msg = shift; # Warning message on die
+    my $det_id = shift;         # Detrend identifier
+    my $iter = shift;           # Iteration
+    my $exp_id = shift; # Exposure tag
+    my $exit_code = shift; # Exit code to add
+
+    carp($msg);
+    if (defined $det_id and defined $iter and defined $exp_id and not $no_update) {
+        my $command = "$dettool -addresidexp";
+        $command .= " -det_id $det_id";
+        $command .= " -iteration $iter";
+        $command .= " -exp_id $exp_id";
+	$command .= " -path_base $outroot";
+        $command .= " -code $exit_code";
+        $command .= " -dbname $dbname" if defined $dbname;
+        system ($command);
+    }
+    exit $exit_code;
+}
+
+# Retrieve the requested rejection limit, dying if not extant
+sub rejection_limit
+{
+    my $name = shift;           # Rejection limit to
+    my $type = shift;           # Type of exposure
+    my $filter = shift;         # Filter
+
+    my $value = $ipprc->rejection( $name, $det_type, $filter );
+    if (not defined $value) {
+        $filter = "(no filter)" if not defined $filter;
+        die "Unable to determine $name rejection limit for $det_type with $filter.\n";
+    }
+
+    return $value;
+}
+
+__END__
+
+####
+
+## this function is not well though out.  it loads a collection of
+## values (background mean and stdev) for a collection of imfile
+## subcomponents.  it then measures the mean background, the
+## background stdev (rms of ensemble stdevs), and the background mean
+## stdev (rms of the means).  it then tries to reject based on the
+## following criteria:
+## (background / stdev > limit) for a single component
+##    ---> this will ACCEPT for a poor images (large stdev)
+## (stdev > limit)
+## (mean background / stdev > limit) same problem
+## (mean stdev > limit)
+
+### I would suggest the following:
+## 1) calculate the ensemble mean and stdev
+## 2) for each component, is the (back - mean) / mean stdev > limit?
+##    (ie, is it an outlier?)
+## 3) is the component stdev > limit? (absolute test)
+## 4) calculate the background stdev for the ensemble (excluding rejects)
+## 5) is the mean stdev > limit (poor images)
+## 6) calculate the ensemble stdev (rms) of remaining (excluding rejects)
+## 7) is the ensemble stdev > limit
+
+## for flats, the value used for stdev should be the fractional stdev
+## (stdev/mean) and no rejection should be performed on the basis of
+## the mean value, but could still be done on the mean stdev
+
+## the same logical cuts above can be applied to components in an
+## imfile, imfiles in an exposure, and exposures in a stack
+
+### this function needs to avoid div by zero: compare Signal vs Noise*limit
Index: /trunk/ippScripts/scripts/detrend_resid_imfile.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_resid_imfile.pl	(revision 18562)
+++ /trunk/ippScripts/scripts/detrend_resid_imfile.pl	(revision 18562)
@@ -0,0 +1,265 @@
+#!/usr/bin/env perl
+
+use Carp;
+use warnings;
+use strict;
+
+## report the program and machine
+use Sys::Hostname;
+my $host = hostname();
+print "\n\n";
+print "Starting script $0 on $host\n\n";
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd 0.36 qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::Stats;
+use PS::IPP::Config 1.01 qw( :standard );
+
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ( $det_id, $iter, $exp_id, $exp_tag, $class_id, $det_type, $detrend, $input_uri, $camera, $mode, $outroot,
+     $dbname, $reduction, $verbose, $no_update, $no_op, $redirect );
+GetOptions(
+    'det_id|d=s'        => \$det_id,
+    'iteration=s'       => \$iter,
+    'exp_id|e=s'        => \$exp_id,
+    'exp_tag|=s'        => \$exp_tag,
+    'class_id|i=s'      => \$class_id,
+    'det_type|t=s'      => \$det_type,
+    'detrend=s'         => \$detrend,
+    'input_uri|u=s'     => \$input_uri,
+    'camera|c=s'        => \$camera,
+    'mode|m=s'          => \$mode,
+    'outroot|w=s'       => \$outroot,   # output file base name
+    'dbname|d=s'        => \$dbname, # Database name
+    'reduction=s'       => \$reduction, # Reduction class
+    'verbose'           => \$verbose,   # Print to stdout
+    'no-update'         => \$no_update,
+    'no-op'             => \$no_op,
+    'redirect-output'   => \$redirect,
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage( -msg => "Required options: --det_id --iteration --exp_id --exp_tag --class_id --det_type --camera --input_uri --mode --detrend --outroot (not for 'verify' mode)",
+           -exitval => 3) unless
+    defined $det_id    and
+    defined $iter      and
+    defined $exp_id    and
+    defined $exp_tag   and
+    defined $class_id  and
+    defined $det_type  and
+    defined $input_uri and
+    defined $camera    and
+    defined $mode      and
+    defined $outroot   and
+    (defined $detrend or lc($mode) eq 'verify');
+
+$ipprc->define_camera($camera);
+my $logDest     = $ipprc->filename("LOG.IMFILE", $outroot, $class_id);
+if ($redirect) {
+    $ipprc->redirect_output($logDest);
+}
+
+# Recipes to use as a function of detrend type and mode
+$reduction = 'DETREND' unless defined $reduction;
+my $recipe;                     # Name of recipe to use
+if ($mode eq 'master') {
+    $recipe = uc($det_type) . '_RESID';
+} elsif ($mode eq 'verify') {
+    $recipe = uc($det_type) . '_VERIFY';
+} else {
+    &my_die("Unrecognised mode: $mode", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
+}
+$recipe = $ipprc->reduction($reduction, $recipe);
+
+# values to extract from output metadata and the stats to calculate
+my $STATS =
+   [
+       #          PPSTATS KEYWORD         STATISTIC          CHIPTOOL FLAG
+       { name => "ROBUST_MEDIAN",      type => "mean",  flag => "-bg",             dtype => "float" },
+       { name => "ROBUST_MEDIAN",      type => "stdev", flag => "-bg_mean_stdev",  dtype => "float" },
+       { name => "ROBUST_STDEV",       type => "rms",   flag => "-bg_stdev",       dtype => "float" },
+       { name => "SAMPLE_SKEWNESS",    type => "mean",  flag => "-bg_skewness",    dtype => "float" },
+       { name => "SAMPLE_KURTOSIS",    type => "mean",  flag => "-bg_kurtosis",    dtype => "float" },
+       { name => "FRINGE_0",           type => "mean",  flag => "-fringe_0",       dtype => "float" },
+       { name => "FRINGE_ERR_0",       type => "rms",   flag => "-fringe_1",       dtype => "float" },
+       { name => "FRINGE_0",           type => "stdev", flag => "-fringe_2",       dtype => "float" },
+       { name => "FRINGE_RESID_0",     type => "mean",  flag => "-fringe_resid_0", dtype => "float" },
+       { name => "FRINGE_RESID_ERR_0", type => "rms",   flag => "-fringe_resid_1", dtype => "float" },
+       { name => "FRINGE_RESID_0",     type => "stdev", flag => "-fringe_resid_2", dtype => "float" },
+   ];
+my $stats = PS::IPP::Metadata::Stats->new($STATS); # Stats parser
+
+my $BINNED_STATS =
+   [
+       { name => "ROBUST_STDEV",   type => "rms",   flag => "-bin_stdev" },
+   ];
+my $binnedStats = PS::IPP::Metadata::Stats->new($BINNED_STATS); # Stats parser
+
+# Flags to specify the particular detrend to use
+use constant DETRENDS => {
+    'bias'     	       => '-bias',      # Specify the bias frame
+    'dark'     	       => '-dark',      # Specify the dark frame
+    'dark_premask'     => '-dark',      # Specify the dark frame
+    'shutter'  	       => '-shutter',   # Specify the shutter frame
+    'flat'     	       => '-flat',      # Specify the flat frame
+    'domeflat' 	       => '-flat',      # Specify the flat frame
+    'skyflat'  	       => '-flat',      # Specify the flat frame
+    'flat_premask'     => '-flat',      # Specify the flat frame
+    'domeflat_premask' => '-flat',      # Specify the flat frame
+    'skyflat_premask'  => '-flat',      # Specify the flat frame
+    'fringe'   	       => '-fringe',    # Specify the fringe frame
+    'mask'     	       => '-mask',      # Specify the mask frame
+    'darkmask' 	       => '-mask',      # Specify the mask frame
+    'flatmask' 	       => '-mask',      # Specify the mask frame
+};
+
+use constant DELETE_STATS => 0; # Delete the statistics file when done?
+
+# 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);
+my $ppStats = can_run('ppStats') or (warn "Can't find ppStats" and $missing_tools = 1);
+if ($missing_tools) {
+    warn("Can't find required tools.");
+    exit($PS_EXIT_CONFIG_ERROR);
+}
+
+# outroot examples (HOST components must be set)
+# file://data/ipp004.0/gpc1/20080130
+# neb:///ipp004-v1/gpc1/20080130
+# neb:///*/gpc1/20080130 (volume not specified)
+
+# check for existing directory, generate if needed
+$ipprc->outroot_prepare($outroot);
+
+# XXX use PPIMAGE.OUTPUT.RESID for output file (compressed, with pos & neg range allowed)
+# my $outputName  = $ipprc->filename("PPIMAGE.OUTPUT", $outroot, $class_id);
+
+my $outputName  = $ipprc->filename("PPIMAGE.OUTPUT.RESID", $outroot, $class_id);
+my $bin1Name    = $ipprc->filename("PPIMAGE.BIN1",   $outroot, $class_id);
+my $bin2Name    = $ipprc->filename("PPIMAGE.BIN2",   $outroot, $class_id);
+my $outputStats = $ipprc->filename("PPIMAGE.STATS",  $outroot, $class_id);
+my $traceDest   = $ipprc->filename("TRACE.IMFILE",   $outroot, $class_id);
+
+# Run ppImage & ppStats
+unless ($no_op) {
+    my $command = "$ppImage -file $input_uri $outroot";
+    $command .= " -recipe PPIMAGE $recipe";
+    $command .= " -recipe PPSTATS RESIDUAL";
+    $command .= " -F PPIMAGE.OUTPUT PPIMAGE.OUTPUT.RESID";
+    $command .= " -stats $outputStats";
+    $command .= " -tracedest $traceDest -log $logDest";
+    $command .= " -dbname $dbname" if defined $dbname;
+
+    # Detrend to use in processing
+    if (lc($mode) ne 'verify') {
+        my $detFlag = DETRENDS->{lc($det_type)};
+        &my_die("Unrecognised detrend type: $det_type", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR) unless defined $detFlag;
+        $command .= " $detFlag $detrend";
+    }
+
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        &my_die("Unable to perform ppImage: $error_code", $det_id, $iter, $exp_id, $class_id, $error_code);
+    }
+    &my_die("Couldn't find expected output file: $outputName", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($outputName);
+    &my_die("Couldn't find expected output file: $outputStats", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($outputStats);
+    &my_die("Couldn't find expected output file: $bin1Name", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($bin1Name);
+    &my_die("Couldn't find expected output file: $bin2Name", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR) unless -f $ipprc->file_resolve($bin2Name);
+
+    # Load the raw output stats file
+    my $statsFile;              # File handle
+    open $statsFile, $ipprc->file_resolve($outputStats) or &my_die("Can't open statistics file $outputStats: $!", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_SYS_ERROR);
+    my @contents = <$statsFile>; # Contents of file
+    close $statsFile;
+
+    # Parse the stats file contents into a metadata
+    my $mdcParser = PS::IPP::Metadata::Config->new;     # Parser for metadata config files
+    my $metadata = $mdcParser->parse(join "", @contents) or &my_die("Unable to parse metadata config doc", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
+
+    # Parse the statistics on the residual image
+    $stats->parse($metadata) or &my_die("Unable to find all values in statistics output.", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
+
+    # run ppStats on the binned image
+    $command = "$ppStats -recipe PPSTATS RESIDUAL $bin2Name";
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        &my_die("Unable to perform ppStats: $error_code", $det_id, $iter, $exp_id, $class_id, $error_code);
+    }
+
+    # Parse the output contents into a metadata
+    my $binnedMetadata = $mdcParser->parse(join "", @$stdout_buf) or &my_die("Unable to parse metadata output", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
+
+    # parse the binned image statistics
+    $binnedStats->parse($binnedMetadata) or &my_die("Unable to find all values in statistics output.", $det_id, $iter, $exp_id, $class_id, $PS_EXIT_PROG_ERROR);
+}
+
+# Command to update the database
+my $command = "$dettool -addresidimfile";
+$command .= " -det_id $det_id";
+$command .= " -iteration $iter";
+$command .= " -exp_id $exp_id";
+$command .= " -class_id $class_id";
+$command .= " -recip $recipe";
+$command .= " -uri $outputName";
+$command .= " -path_base $outroot";
+$command .= " -dbname $dbname" if defined $dbname;
+$command .= $stats->cmdflags();
+$command .= $binnedStats->cmdflags();
+
+# Add the processed file to the database
+unless ($no_update) {
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        warn("Unable to perform dettool -addresidimfile: $error_code\n");
+        exit($error_code);
+    }
+} else {
+    print "skipping command: $command\n";
+}
+
+sub my_die
+{
+    my $msg = shift; # Warning message on die
+    my $det_id = shift;         # Detrend identifier
+    my $iter = shift;           # Iteration
+    my $exp_id = shift; # Exposure tag
+    my $class_id = shift; # Class identifier
+    my $exit_code = shift; # Exit code to add
+
+    carp($msg);
+    if (defined $det_id and defined $iter and defined $exp_id and not $no_update) {
+        my $command = "$dettool -addresidimfile";
+        $command .= " -det_id $det_id";
+        $command .= " -iteration $iter";
+        $command .= " -exp_id $exp_id";
+        $command .= " -class_id $class_id";
+	$command .= " -path_base $outroot";
+        $command .= " -code $exit_code";
+        $command .= " -dbname $dbname" if defined $dbname;
+        system ($command);
+    }
+    exit $exit_code;
+}
+
+END {
+    my $exit = $?;
+    system("sync") == 0 or die "failed to execute sync: $!";
+    $? = $exit;
+}
+
+__END__
Index: /trunk/ippScripts/scripts/detrend_stack.pl
===================================================================
--- /trunk/ippScripts/scripts/detrend_stack.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/detrend_stack.pl	(revision 18562)
@@ -209,5 +209,6 @@
 # Command to update the database
 $command  = "$dettool -addstacked";
-$command .= " -det_id $det_id -iteration $iter";
+$command .= " -det_id $det_id";
+$command .= " -iteration $iter";
 $command .= " -class_id $class_id";
 $command .= " -uri $outputStack";
@@ -243,4 +244,5 @@
         $command .= " -iteration $iter";
         $command .= " -class_id $class_id";
+	# XXX EAM : we should add this to the db : $command .= " -path_base $outroot";
         $command .= " -code $exit_code";
         $command .= " -dbname $dbname" if defined $dbname;
Index: /trunk/ippScripts/scripts/fake_imfile.pl
===================================================================
--- /trunk/ippScripts/scripts/fake_imfile.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/fake_imfile.pl	(revision 18562)
@@ -42,19 +42,20 @@
 # Parse the command-line arguments
 my ( $exp_id, $fake_id, $class_id, $chiproot, $camroot, $camera, $outroot, 
-     $dbname, $reduction, $verbose, $no_update, $no_op );
+     $dbname, $reduction, $verbose, $no_update, $no_op, $redirect  );
 GetOptions(
-	   'exp_id=s'      => \$exp_id,    # Exposure identifier
-	   'fake_id=s'     => \$fake_id,   # Chiptool identifier
-	   'class_id=s'    => \$class_id,  # Class identifier
-	   'chiproot=s'    => \$chiproot,  # Input Chip files (root)
-	   'camroot=s'     => \$camroot,   # Input Camera files (root)
-	   'camera|c=s'    => \$camera,	   # Camera
-	   'outroot|w=s'   => \$outroot,   # output file base name
-	   'dbname|d=s'    => \$dbname,    # Database name
-	   'reduction=s'   => \$reduction, # Reduction class
-	   'verbose'       => \$verbose,   # Print to stdout
-	   'no-update'     => \$no_update, # Don't update the database?
-	   'no-op'         => \$no_op,	   # Don't do any operations?
-	   ) or pod2usage( 2 );
+    'exp_id=s'      	=> \$exp_id,    # Exposure identifier
+    'fake_id=s'     	=> \$fake_id,   # Chiptool identifier
+    'class_id=s'    	=> \$class_id,  # Class identifier
+    'chiproot=s'    	=> \$chiproot,  # Input Chip files (root)
+    'camroot=s'     	=> \$camroot,   # Input Camera files (root)
+    'camera|c=s'    	=> \$camera,	   # Camera
+    'outroot|w=s'   	=> \$outroot,   # output file base name
+    'dbname|d=s'    	=> \$dbname,    # Database name
+    'reduction=s'   	=> \$reduction, # Reduction class
+    'verbose'       	=> \$verbose,   # Print to stdout
+    'no-update'     	=> \$no_update, # Don't update the database?
+    'no-op'         	=> \$no_op,	   # Don't do any operations?
+    'redirect-output'   => \$redirect,
+    ) or pod2usage( 2 );
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
@@ -71,4 +72,8 @@
 $ipprc->define_camera($camera);
 
+my $logDest = $ipprc->filename("LOG.IMFILE", $outroot, $class_id)  or &my_die("Missing entry from camera config", $exp_id, $fake_id, $class_id, $PS_EXIT_CONFIG_ERROR);
+
+$ipprc->redirect_output($logDest) if $redirect;
+
 # Recipes to use based on reduction class
 $reduction = 'DEFAULT' unless defined $reduction;
@@ -116,5 +121,4 @@
 my $cameraObjects = $ipprc->filename("PSASTRO.OUTPUT",      $camroot)             or &my_die("Missing entry from camera config", $exp_id, $fake_id, $class_id, $PS_EXIT_CONFIG_ERROR);
 my $traceDest     = $ipprc->filename("TRACE.IMFILE", 	    $outroot, $class_id)  or &my_die("Missing entry from camera config", $exp_id, $fake_id, $class_id, $PS_EXIT_CONFIG_ERROR);
-my $logDest       = $ipprc->filename("LOG.IMFILE", 	    $outroot, $class_id)  or &my_die("Missing entry from camera config", $exp_id, $fake_id, $class_id, $PS_EXIT_CONFIG_ERROR);
 
 # XXX check for existence of input data
Index: /trunk/ippScripts/scripts/warp_overlap.pl
===================================================================
--- /trunk/ippScripts/scripts/warp_overlap.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/warp_overlap.pl	(revision 18562)
@@ -27,5 +27,5 @@
 my $ipprc = PS::IPP::Config->new(); # IPP configuration
 
-my ($warp_id, $camera, $tess_dir, $dbname, $verbose, $no_update, $no_op, $save_temps);
+my ($warp_id, $camera, $tess_dir, $dbname, $verbose, $no_update, $no_op, $logfile, $save_temps);
 GetOptions(
     'warp_id|i=s'       => \$warp_id, # Warp identifier
@@ -36,6 +36,9 @@
     'no-update'         => \$no_update, # Don't update the database?
     'no-op'             => \$no_op, # Don't do any operations
+    'logfile=s'         => \$logfile,
     'save-temps'        => \$save_temps, # Save temporary files?
 ) or pod2usage( 2 );
+
+$ipprc->redirect_output($logfile) if $logfile;
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
Index: /trunk/ippScripts/scripts/warp_skycell.pl
===================================================================
--- /trunk/ippScripts/scripts/warp_skycell.pl	(revision 18561)
+++ /trunk/ippScripts/scripts/warp_skycell.pl	(revision 18562)
@@ -25,5 +25,5 @@
 my $ipprc = PS::IPP::Config->new(); # IPP configuration
 
-my ($warp_id, $skycell_id, $tess_dir, $camera, $dbname, $outroot, $verbose, $no_update, $no_op, $save_temps);
+my ($warp_id, $skycell_id, $tess_dir, $camera, $dbname, $outroot, $verbose, $no_update, $no_op, $redirect, $save_temps);
 GetOptions(
     'warp_id|i=s'       => \$warp_id, # Warp identifier
@@ -36,4 +36,5 @@
     'no-update'         => \$no_update, # Don't update the database?
     'no-op'             => \$no_op, # Don't do any operations?
+    'redirect-output'   => \$redirect,
     'save-temps'        => \$save_temps, # Save temporary files?
 ) or pod2usage( 2 );
@@ -50,4 +51,8 @@
 
 $ipprc->define_camera($camera);
+
+my $logDest = $ipprc->filename("TRACE.EXP", $outroot, $skycell_id);
+
+$ipprc->redirect_output($logDest) if $redirect;
 
 my $STATS =
@@ -119,5 +124,4 @@
 my $outputStats = $ipprc->filename("SKYCELL.STATS", $outroot, $skycell_id );
 my $traceDest = $ipprc->filename("TRACE.EXP", $outroot, $skycell_id);
-my $logDest = $ipprc->filename("TRACE.EXP", $outroot, $skycell_id);
 
 my $skyFile = $ipprc->filename("SKYCELL.TEMPLATE", $outroot, $skycell_id );
