Index: /branches/cache/ippScripts/scripts/Makefile.am
===================================================================
--- /branches/cache/ippScripts/scripts/Makefile.am	(revision 9459)
+++ /branches/cache/ippScripts/scripts/Makefile.am	(revision 9459)
@@ -0,0 +1,16 @@
+bin_SCRIPTS = \
+	detrend_norm_apply.pl \
+	detrend_norm_calc.pl \
+	detrend_norm_exp.pl \
+	detrend_process_exp.pl \
+	detrend_process_imfile.pl \
+	detrend_reject_exp.pl \
+	detrend_reject_imfile.pl \
+	detrend_resid.pl \
+	detrend_stack.pl \
+	ipp_workdir.pl \
+	mdc2list.pl \
+	phase0_exp.pl \
+	phase0_imfile.pl \
+	phase2.pl \
+	phase3.pl
Index: /branches/cache/ippScripts/scripts/detrend_norm_apply.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_norm_apply.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_norm_apply.pl	(revision 9459)
@@ -0,0 +1,119 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use PS::IPP::Metadata::Stats;
+use IPC::Cmd qw( can_run run );
+use Data::Dumper;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+# Parse the command-line
+my ($detId,                     # Detrend ID
+    $iter,  			# Iteration
+    $classId,			# Class ID
+    $value,			# Value to multiple (for normalisation)
+    $input,			# Input file
+    $camera,			# Camera
+    $detType,			# Detrend type
+    $no_update			# Don't update the database
+    );
+GetOptions(
+    'det_id|d=s'        => \$detId,
+    'iteration|n=s'	=> \$iter,
+    'class_id|i=s'      => \$classId,
+    'value|v=s'		=> \$value,
+    'input_uri|u=s'     => \$input,
+    'camera|c=s'        => \$camera,
+    'det_type|t=s'      => \$detType,
+    'no-update'         => \$no_update
+    ) or pod2usage( 2 );
+    
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage( -msg => "Required options: --det_id --iteration --class_id --value --input_uri --camera --det_type",
+    -exitval => 3,
+    ) unless defined $detId
+    and defined $iter
+    and defined $classId
+    and defined $value
+    and defined $input
+    and defined $camera
+    and defined $detType;
+
+
+use constant RECIPE => 'PPIMAGE_N'; # Recipe to use with ppImage
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+my ($vol, $dir, $file) = File::Spec->splitpath( $input );
+$input = File::Spec->rel2abs( $input, $ipprc->workdir() );
+
+# Output name
+my $outputRoot = $camera . '.' . $detType . '.norm.' . $detId . '.' . $iter; # Root output name
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+my $output = $outputRoot . '.' . $classId . '.fits'; # Main output file
+my $b1name = $outputRoot . '.' . $classId . '.b1.fits';	# Output file with binning 1
+my $b2name = $outputRoot . '.' . $classId . '.b2.fits';	# Output file with binning 2
+my $statsName = $outputRoot . '.' . $classId . '.stats'; # Statistics file
+
+# Run normalisation
+{
+    my $command = "$ppImage -file $input $outputRoot -norm $value -stat $statsName -recipe PPIMAGE " . RECIPE(); # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform ppImage: $error_code\n" if not $success;
+    die "Can't find expected output file: $output\n" if not -e $output;
+    die "Can't find expected output file: $b1name\n" if not -e $b1name;
+    die "Can't find expected output file: $b2name\n" if not -e $b2name;
+    die "Can't find expected output file: $statsName\n" if not -e $statsName;
+}
+
+# Get the statistics on the normalised image
+my $stats;			# Statistics from ppImage
+{
+    my $statsFile;		# File handle
+    open $statsFile, $statsName or die "Can't open statistics file $statsName: $!\n";
+    my @contents = <$statsFile>; # Contents of file
+    close $statsFile;
+    my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+    my $metadata = $mdcParser->parse(join "", @contents)
+        or die "unable to parse metadata config";
+    $stats = PS::IPP::Metadata::Stats->new(); # Stats parser
+    $stats->parse($metadata) or die "Unable to find all values in statistics output.\n";
+}
+
+# Update the database
+$output = File::Spec->abs2rel( $output, $ipprc->workdir() );
+$b1name = File::Spec->abs2rel( $b1name, $ipprc->workdir() );
+$b2name = File::Spec->abs2rel( $b2name, $ipprc->workdir() );
+unless ($no_update) {
+    my $command = "$dettool -addnormalizedimfile -det_id $detId -iteration $iter -class_id $classId ".
+	"-uri $output -b1_uri $b1name -b2_uri $b2name"; # Command to run
+    # Add the statistics triplet
+    $command .= " -bg " . $stats->bg_mean();
+    if (defined($stats->bg_stdev())) {
+	$command .= " -bg_stdev " . $stats->bg_stdev();
+    } else {
+	# May be undefined if there's only a single imfile
+	$command .= " -bg_stdev 0";
+    }
+    $command .= " -bg_mean_stdev " . $stats->bg_mean_stdev();
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -addnormalizedimfile: $error_code\n"
+	if not $success;
+
+    unlink $statsName;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
Index: /branches/cache/ippScripts/scripts/detrend_norm_calc.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_norm_calc.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_norm_calc.pl	(revision 9459)
@@ -0,0 +1,149 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use IPC::Cmd qw( can_run );
+use IPC::Run qw ( run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Data::Dumper;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+
+# Parse command-line arguments
+my ($detId,			# Detrend id
+    $iter,			# Iteration
+    $detType,			# Detrend type
+    $no_update			# Don't update the database?
+    );
+GetOptions(
+	'det_id|d=s'	=> \$detId,
+	'iteration|i=s'	=> \$iter,
+	'det_type|t=s'  => \$detType,
+        'no-update'     => \$no_update
+	) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage( -msg => "Required options --det_id --iteration --det_type",
+	   -exitval => 3,
+	   ) unless defined $detId
+    and defined $iter
+    and defined $detType;
+
+
+use constant STATISTIC => 'bg'; # Background statistic to use from the database
+# Define which detrend types we normalise
+use constant NORMALIZE => {
+    'bias' => 0,
+    'dark' => 0,
+    'shutter' => 0,
+    'flat' => 1
+    }; 
+
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+my $ppNormCalc = can_run('ppNormCalc') or (warn "Can't find ppNormCalc" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+die "Unrecognised detrend type: $detType\n" unless exists NORMALIZE()->{lc($detType)};
+
+
+my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
+
+# Get the list of inputs
+my $files;			# The input files
+{
+    my $command = "$dettool -processedimfile -det_id $detId"; # Command to run
+    my @command = split /\s+/, $command;
+    my ( $stdin, $stdout, $stderr ); # Buffers for running program
+    print "Running [$command]...\n";
+    run \@command, \$stdin, \$stdout, \$stderr or
+	die "Unable to perform dettool -processedimfile on detrend $detId/$iter: $?";
+    print $stdout . "\n";
+    
+    # Parse the output
+    my $metadata = $mdcParser->parse($stdout)
+        or die "unable to parse metadata config doc";
+    $files = parse_md_list($metadata);
+}
+
+
+my $norms;			# MDC with normalisations
+if (NORMALIZE()->{lc($detType)}) {
+
+    my %matrix; # Matrix of statistics as a function of exposures and classes
+    foreach my $file (@$files) {
+	my $expTag = $file->{'exp_tag'}; # Exposure ID
+	my $classId = $file->{'class_id'}; # Class ID
+	my $stat = $file->{STATISTIC()}; # Statistic of interest
+	
+	# Create matrix elements
+	$matrix{$expTag} = {} if not defined $matrix{$expTag};
+	$matrix{$expTag}->{$classId} = $stat;
+    }
+    
+    # Generate the input for ppNormCalc
+    my $normData;			# Normalisation data
+    foreach my $expTag (keys %matrix) {
+	$normData .= "$expTag\tMETADATA\n";
+	foreach my $classId (keys %{$matrix{$expTag}}) {
+	    $normData .= "\t" . $classId . "\tF32\t" . $matrix{$expTag}->{$classId} . "\n";
+	}
+	$normData .= "END\n\n";
+    }
+
+    # Run ppNormCalc
+    {
+	my ( $stdout, $stderr ); # Buffers for running program
+	my @command = split /\s+/, $ppNormCalc;
+	print "Running [$ppNormCalc]...\n";
+	run \@command, \$normData, \$stdout, \$stderr or
+	    die "Unable to perform ppNormCalc: $?";
+	print $stdout . "\n";
+	
+	# Parse the output
+	$norms = $mdcParser->parse($stdout)
+	    or die "unable to parse metadata config doc";
+    }
+
+} else {
+    # It's something that doesn't need normalisation --- just push in a normalisation of 1
+    my %classes;		# List of unique classes
+    foreach my $file (@$files) {
+	my $classId = $file->{'class_id'}; # Class Id
+	$classes{$classId} = 1;
+    }
+    
+    foreach my $classId (keys %classes) {
+	my %mdValue;	# Metadata value for this class id
+	$mdValue{name} = $classId;
+	$mdValue{value} = 1.0;
+	push @$norms, \%mdValue;
+    }
+}
+
+
+# Process output normalisations
+unless ($no_update) {
+    foreach my $normItem (@$norms) {
+	my $className = $normItem->{name}; # Name of component
+	my $normalisation = $normItem->{value}; # Normalisation for component
+
+	my $command = "$dettool -addnormalizedstat -det_id $detId -iteration $iter -class_id $className ".
+	    "-norm $normalisation"; # Command to run
+	my @command = split /\s+/, $command;
+
+	my ( $stdin, $stdout, $stderr ); # Buffers for running program
+	print "Running [$command]...\n";
+	run \@command, \$stdin, \$stdout, \$stderr or
+	    die "Unable to perform dettool -addnormstat for $className: $?";
+	print $stdout . "\n";
+    }
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
Index: /branches/cache/ippScripts/scripts/detrend_norm_exp.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_norm_exp.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_norm_exp.pl	(revision 9459)
@@ -0,0 +1,152 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Statistics::Descriptive;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($det_id, $iter, $det_type, $camera, $no_update);
+GetOptions(
+    'det_id|d=s'        => \$det_id,
+    'iteration|i=s'     => \$iter,
+    'camera|c=s'        => \$camera,
+    'det_type|t=s'      => \$det_type,
+    'no-update'         => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --det_id --iteration --camera --det_type",
+    -exitval => 3,
+) unless defined $det_id
+     and defined $iter
+     and defined $camera
+     and defined $det_type;
+
+use constant RECIPE1 => 'PPIMAGE_J1'; # Recipe to use for ppImage to make JPEGs
+use constant RECIPE2 => 'PPIMAGE_J2'; # Recipe to use for ppImage to make JPEGs
+
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+
+# Get list of component files
+my $files;			# Array of component files
+{
+    my $command = "$dettool -normalizedimfile -det_id $det_id -iteration $iter"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -normalizedimfile: $error_code\n" if not $success;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) 
+        or die "unable to parse metadata config doc";
+    $files = parse_md_list($metadata);
+}
+
+# Gather the statistics
+my ($bg, $bg_stdev, $bg_mean_stdev); # The statistics triplet
+{
+    my @backgrounds;		# Array of backgrounds in each component
+    my @stdevs;			# Array of standard deviations in each component
+    foreach my $file (@$files) {
+	die "Unable to find class id\n" unless defined $file->{class_id};
+	my $class_id = $file->{class_id};
+	die "Unable to find bg for class_id=$class_id\n" unless defined $file->{bg};
+	die "Unable to find bg_mean_stdev for class_id=$class_id\n" unless defined $file->{bg_mean_stdev};
+	push @backgrounds, $file->{bg};
+	push @stdevs, $file->{bg_mean_stdev};
+    }
+
+    {
+	my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+	$stats->add_data(@backgrounds);
+	$bg = $stats->mean();
+	if (scalar @backgrounds == 1) {
+	    $bg_stdev = 0.0;
+	} else {
+	    $bg_stdev = $stats->standard_deviation();
+	}
+    }
+    {
+	my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+	$stats->add_data(@stdevs);
+	$bg_mean_stdev = $stats->mean();
+    }
+}
+
+my $example = ${$files}[0]->{b1_uri}; # Example file, for path
+my ($vol, $dir, $file) = File::Spec->splitpath( $example );
+
+# Generate the file list, and get the statistics
+my $outputRoot = $camera . '.' . $det_type . '.norm.' . $det_id . '.' . $iter; # Root output name
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+my $list1Name = $outputRoot . '.b1.list'; # Name for the input file list for binning 1
+my $list2Name = $outputRoot . '.b2.list'; # Name for the input file list for binning 2
+my @means;			# Array of means
+my @stdevs;			# Array of stdevs
+open my $list1File, '>' . $list1Name;
+open my $list2File, '>' . $list2Name;
+foreach my $file (@$files) {
+    print $list1File File::Spec->rel2abs( $file->{b1_uri}, $ipprc->workdir() ) . "\n";
+    print $list2File File::Spec->rel2abs( $file->{b2_uri}, $ipprc->workdir() ) . "\n";
+    push @means, $file->{bg};
+    push @stdevs, $file->{bg_stdev};
+}
+close $list1File;
+close $list2File;
+
+# Output products --- need to synch with the camera configuration!
+my $jpeg1Name = $outputRoot . ".b1.jpg"; # Binned JPEG #1
+my $jpeg2Name = $outputRoot . ".b2.jpg"; # Binned JPEG #2
+
+# Make the jpeg for binning 1
+{
+    my $command = "$ppImage -list $list1Name $outputRoot -recipe PPIMAGE " . RECIPE1; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg1Name\n" if not -f $jpeg1Name;
+}
+
+# Make the jpeg for binning 2
+{
+    my $command = "$ppImage -list $list2Name $outputRoot -recipe PPIMAGE " . RECIPE2; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg2Name\n" if not -f $jpeg2Name;
+}
+
+# Add the result into the database
+$jpeg1Name = File::Spec->abs2rel( $jpeg1Name, $ipprc->workdir() );
+$jpeg2Name = File::Spec->abs2rel( $jpeg2Name, $ipprc->workdir() );
+unless ($no_update) {
+    my $command = "$dettool -addnormalizedexp -det_id $det_id -iteration $iter " .
+	"-recip " . RECIPE1() . "," . RECIPE2() . " -b1_uri $jpeg1Name -b2_uri $jpeg2Name " .
+	"-bg $bg -bg_stdev $bg_stdev -bg_mean_stdev $bg_mean_stdev"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -addnormalizedexp: $error_code\n" if not $success;
+
+    unlink $list1Name;
+    unlink $list2Name;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippScripts/scripts/detrend_process_exp.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_process_exp.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_process_exp.pl	(revision 9459)
@@ -0,0 +1,150 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Statistics::Descriptive;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($det_id, $exp_tag, $no_update);
+GetOptions(
+    'det_id|d=s'        => \$det_id,
+    'exp_tag|e=s'       => \$exp_tag,
+    'no-update'         => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --det_id --exp_tag",
+    -exitval => 3,
+) unless defined $det_id
+    and defined $exp_tag;
+
+use constant RECIPE1 => 'PPIMAGE_J1'; # Recipe to use for ppImage to make JPEGs
+use constant RECIPE2 => 'PPIMAGE_J2'; # Recipe to use for ppImage to make JPEGs
+
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+
+# Get list of component files
+my $files;			# Array of component files
+{
+    my $command = "$dettool -processedimfile -det_id $det_id -exp_tag $exp_tag"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -processedimfile: $error_code\n" if not $success;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) 
+        or die "unable to parse metadata config doc";
+    $files = parse_md_list($metadata);
+}
+
+# Gather the statistics
+my ($bg, $bg_stdev, $bg_mean_stdev); # The statistics triplet
+{
+    my @backgrounds;		# Array of backgrounds in each component
+    my @stdevs;			# Array of standard deviations in each component
+    foreach my $file (@$files) {
+	die "Unable to find class id\n" unless defined $file->{class_id};
+	my $class_id = $file->{class_id};
+	die "Unable to find bg for class_id=$class_id\n" unless defined $file->{bg};
+	die "Unable to find bg_mean_stdev for class_id=$class_id\n" unless defined $file->{bg_mean_stdev};
+	push @backgrounds, $file->{bg};
+	push @stdevs, $file->{bg_mean_stdev};
+    }
+
+    {
+	my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+	$stats->add_data(@backgrounds);
+	$bg = $stats->mean();
+	if (scalar @backgrounds == 1) {
+	    $bg_stdev = 0.0;
+	} else {
+	    $bg_stdev = $stats->standard_deviation();
+	}
+    }
+    {
+	my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+	$stats->add_data(@stdevs);
+	$bg_mean_stdev = $stats->mean();
+    }
+}
+
+my $example = ${$files}[0]->{b1_uri}; # Example filename
+my ($vol, $dir, $file) = File::Spec->splitpath( $example );
+
+# Generate the file list, and get the statistics
+my $outputRoot = $exp_tag . '.detproc.' . $det_id; # Root output name
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+my $list1Name = $outputRoot . '.b1.list'; # Name for the input file list for binning 1
+my $list2Name = $outputRoot . '.b2.list'; # Name for the input file list for binning 2
+my @means;			# Array of means
+my @stdevs;			# Array of stdevs
+open my $list1File, '>' . $list1Name;
+open my $list2File, '>' . $list2Name;
+foreach my $file (@$files) {
+    print $list1File (File::Spec->rel2abs( $file->{b1_uri}, $ipprc->workdir() ) . "\n");
+    print $list2File (File::Spec->rel2abs( $file->{b2_uri}, $ipprc->workdir() ) . "\n");
+    push @means, $file->{bg};
+    push @stdevs, $file->{bg_stdev};
+}
+close $list1File;
+close $list2File;
+
+# Output products --- need to synch with the camera configuration!
+my $jpeg1Name = $outputRoot . ".b1.jpg"; # Binned JPEG #1
+my $jpeg2Name = $outputRoot . ".b2.jpg"; # Binned JPEG #2
+
+# Make the jpeg for binning 1
+{
+    my $command = "$ppImage -list $list1Name $outputRoot -recipe PPIMAGE " . RECIPE1; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg1Name\n" if not -f $jpeg1Name;
+}
+
+# Make the jpeg for binning 2
+{
+    my $command = "$ppImage -list $list2Name $outputRoot -recipe PPIMAGE " . RECIPE2; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg2Name\n" if not -f $jpeg2Name;
+}
+
+
+# Add the result into the database
+$outputRoot = File::Spec->abs2rel( $outputRoot, $ipprc->workdir() );
+$jpeg1Name  = File::Spec->abs2rel( $jpeg1Name, $ipprc->workdir() );
+$jpeg2Name  = File::Spec->abs2rel( $jpeg2Name, $ipprc->workdir() );
+unless ($no_update) {
+    my $command = "$dettool -addprocessedexp -det_id $det_id -exp_tag $exp_tag " .
+	"-recip " . RECIPE1() . "," . RECIPE2() . " -b1_uri $jpeg1Name -b2_uri $jpeg2Name " .
+	"-bg $bg -bg_stdev $bg_stdev -bg_mean_stdev $bg_mean_stdev"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -addprocessedexp: $error_code\n" if not $success;
+
+    unlink $list1Name;
+    unlink $list2Name;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippScripts/scripts/detrend_process_imfile.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_process_imfile.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_process_imfile.pl	(revision 9459)
@@ -0,0 +1,124 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::Stats;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($det_id, $exp_tag, $class_id, $det_type, $input_uri, $output_uri, $no_update);
+GetOptions(
+    'det_id|d=s'        => \$det_id,
+    'exp_tag|e=s'        => \$exp_tag,
+    'class_id|i=s'      => \$class_id,
+    'det_type|t=s'      => \$det_type,
+    'input_uri|u=s'     => \$input_uri,
+    'no-update'         => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --det_id --exp_tag --class_id --det_type --input_uri",
+    -exitval => 3,
+) unless defined $det_id
+    and defined $exp_tag
+    and defined $class_id
+    and defined $det_type
+    and defined $input_uri;
+
+# Recipes to use, as a function of the detrend type
+use constant RECIPES => {
+    'bias'    => 'PPIMAGE_O',	 # Overscan only
+    'dark'    => 'PPIMAGE_OB',	 # Overscan and bias only
+    'shutter' => 'PPIMAGE_OBD',	 # Overscan, bias and dark only
+    'flat'    => 'PPIMAGE_OBDS', # Overscan, bias, dark and shutter only
+};
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+# Recipe to use in processing
+my $recipe = RECIPES->{lc($det_type)};
+die "Unrecognised detrend type: $det_type\n" if not defined $recipe;
+
+### Output file name --- must match camera configuration!
+my ($vol, $dir, $file) = File::Spec->splitpath( $input_uri );
+my $outputRoot = $exp_tag . '.detproc.' . $det_id; # Root name
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+$input_uri = File::Spec->rel2abs( $input_uri, $ipprc->workdir() );
+my $outputImage = $outputRoot . '.' . $class_id . '.fits';
+my $outputStats = $outputRoot . '.' . $class_id . '.stats';
+my $outputBin1 = $outputRoot . '.' . $class_id . '.b1.fits';
+my $outputBin2 = $outputRoot . '.' . $class_id . '.b2.fits';
+
+# Run ppImage
+{
+    my $command = "$ppImage -file $input_uri $outputRoot -recipe PPIMAGE $recipe" .
+	" -stat $outputStats"; # Command to run ppImage
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform ppImage on $input_uri: $error_code\n" if not $success;
+    die "Couldn't find expected output file: $outputImage\n" if not -f $outputImage;
+    die "Couldn't find expected output file: $outputStats\n" if not -f $outputStats;
+    die "Couldn't find expected output file: $outputBin1\n" if not -f $outputBin1;
+    die "Couldn't find expected output file: $outputBin2\n" if not -f $outputBin2;
+}
+
+# Get the statistics on the processed image
+my $stats;			# Statistics from ppImage
+{
+    my $statsFile;		# File handle
+    open $statsFile, "$outputStats" or die "Can't open statistics file $outputStats: $!\n";
+    my @contents = <$statsFile>; # Contents of file
+    close $statsFile;
+    my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+    my $metadata = $mdcParser->parse(join "", @contents)
+        or die "unable to parse metadata config";
+    $stats = PS::IPP::Metadata::Stats->new(); # Stats parser
+    $stats->parse($metadata) or die "Unable to find all values in statistics output.\n";
+}
+
+# Take off the absolute path, to stuff into the database
+$outputImage = File::Spec->abs2rel( $outputImage, $ipprc->workdir() );
+$outputBin1 = File::Spec->abs2rel( $outputBin1, $ipprc->workdir() );
+$outputBin2 = File::Spec->abs2rel( $outputBin2, $ipprc->workdir() );
+
+# Add the processed file to the database
+unless ($no_update) {
+    my $command = "$dettool -addprocessedimfile -det_id $det_id -exp_tag $exp_tag " .
+	"-class_id $class_id -recip $recipe -uri $outputImage -b1_uri $outputBin1 " .
+	"-b2_uri $outputBin2"; # Command to run dettool
+    $command .= " -bg " . $stats->bg_mean();
+    if (defined($stats->bg_stdev())) {
+	$command .= " -bg_stdev " . $stats->bg_stdev();
+    } else {
+	# May be undefined if there's only a single imfile
+	$command .= " -bg_stdev 0";
+    }
+    $command .= " -bg_mean_stdev " . $stats->bg_mean_stdev();
+
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -addprocessedimfile for $det_id/$exp_tag/$class_id: $error_code\n"
+	if not $success;
+
+    unlink $outputStats;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippScripts/scripts/detrend_reject_exp.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_reject_exp.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_reject_exp.pl	(revision 9459)
@@ -0,0 +1,219 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Statistics::Descriptive;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($det_id, $iter, $det_type, $no_update);
+GetOptions(
+    'det_id|d=s'        => \$det_id,
+    'iteration=s'       => \$iter,
+    'det_type|t=s'      => \$det_type,
+    'no-update'         => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --det_id --iteration --det_type",
+    -exitval => 3,
+) unless defined $det_id
+    and defined $iter
+    and defined $det_type;
+
+# Rejection threshold for the mean, in terms of the standard deviation
+# This measures how close it is to what's expected
+use constant REJECT_MEAN => {
+    'bias' => 0,		# Should be fairly flat; some CRs
+    'dark' => 0,		# Lots of CRs
+    'shutter' => 10,		# Should be less than 10 sec
+    'flat' => undef		# Can't define expected value (depends on exposure level)
+    };
+
+# Rejection threshold for the standard deviation, in terms of the standard deviation of the stdevs
+# This measures how much variation there is within the components of an exposure, compared to "typical"
+use constant REJECT_STDEV => {
+    'bias' => 0, # Components should have the same degree of variation
+    'dark' => 0, # Components should have the same degree of variation
+    'shutter' => undef,		# Might be significant variation
+    'flat' => 0 # Components should have the same degree of variation
+    };
+
+# Rejection threshold for the mean of the stdev, in terms of the standard deviation of the mean of the stdevs
+# This measures how structured the images are, compared to "typical"
+use constant REJECT_MEAN_STDEV => {
+    'bias' => 0,		# All images should be equally structured
+    'dark' => 0,		# All images should be equally structured
+    'shutter' => 0,		# All images should be equally structured
+    'flat' => 0 		# All images should be equally structured
+    };
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+
+# Get list of component files
+my $exposures;			# Array of exposures
+{
+    my $command = "$dettool -residexp -det_id $det_id -iteration $iter"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -residexp: $error_code\n" if not $success;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf)
+        or die "unable to parse metadata config doc";
+    $exposures = parse_md_list($metadata);
+}
+
+my @expTags;			# Array of exposure IDs
+my @means;			# Array of means
+my @variances;			# Array of variances
+my @meanStdevs;			# Array of mean stdevs
+my @accept;			# Array of accept flags
+my @include;			# Array of include flags
+foreach my $exposure (@$exposures) {
+    die "Unable to find exposure id.\n" if not defined $exposure->{exp_tag};
+    die "Unable to find mean.\n" if not defined $exposure->{bg};
+    die "Unable to find stdev.\n" if not defined $exposure->{bg_stdev};
+    die "Unable to find mean stdev.\n" if not defined $exposure->{bg_mean_stdev};
+    die "Unable to find accept.\n" if not defined $exposure->{accept};
+    die "Unable to find include.\n" if not defined $exposure->{include};
+    push @expTags, $exposure->{exp_tag};
+    push @means, $exposure->{bg};
+    push @variances, ($exposure->{bg_stdev}*$exposure->{bg_stdev});
+    push @meanStdevs, $exposure->{bg_mean_stdev}; ### XXX are we keeping this or stdev(mean)?
+    push @accept, $exposure->{accept};
+    push @include, $exposure->{include};
+}
+my $meanStats = Statistics::Descriptive::Sparse->new(); # Statistics calculator
+$meanStats->add_data(@means);
+my $varianceStats = Statistics::Descriptive::Sparse->new(); # Statistics calculator
+$varianceStats->add_data(@variances);
+my $meanStdevStats = Statistics::Descriptive::Sparse->new(); # Statistics calculator
+$meanStdevStats->add_data(@meanStdevs);
+
+# Check the existence of the required rejection levels as a function of detrend type
+die "Unknown mean rejection level for detrend type $det_type\n"
+    if not exists REJECT_MEAN->{$det_type};
+die "Unknown stdev rejection level for detrend type $det_type\n"
+    if not exists REJECT_STDEV->{$det_type};
+die "Unknown mean stdev rejection level for detrend type $det_type\n"
+    if not exists REJECT_MEAN_STDEV->{$det_type};
+
+# rejections based on comparison with ensemble statistics
+## these should probably be 3-sigma clipped statistics themselves...
+my $mean = $meanStats->mean();
+my $meanStdev = $meanStats->standard_deviation();
+if (not defined $meanStdev) { $meanStdev = 0; }
+
+my $var = $varianceStats->mean();
+my $varStdev = $varianceStats->standard_deviation();
+
+print "Ensemble mean $mean +/- $meanStdev, stdev " . sqrt($var) . " +/- " . sqrt($varStdev) . "\n\n";
+
+# Go through again to do rejection, and update the database for each exposure
+my $numChanges = 0;		# Number of exposures with changed status
+for (my $i = 0; $i < scalar @means; $i++) {
+    my $expTag = $expTags[$i];	# Exposure ID
+    my $command = "$dettool -updateresidexp -det_id $det_id -iteration $iter -exp_tag $expTag"; # Command to run
+    my $reject = 0;		# Reject this exposure?
+
+    if (not $accept[$i]) {
+	# Rejected this at an earlier stage
+	print "Rejecting $expTag based on earlier determination.\n";
+	$reject = 1;
+	goto UPDATE;
+    } 
+    if (REJECT_MEAN->{$det_type} && ($meanStdev > 0)) {
+	my $nSigma = abs($means[$i] - $mean) / $meanStdev;
+	if ($nSigma > REJECT_MEAN->{$det_type}) {
+	    print "Rejecting $expTag based on outlier mean value: " .
+		"$means[$i] is $nSigma vs " . REJECT_MEAN->{$det_type} . "\n";
+	    $reject = 1;
+	    goto UPDATE;
+	}
+    } else {
+	print "no rejection for exposure mean\n";
+    }
+    if (REJECT_STDEV->{$det_type} && ($varStdev > 0)) {
+	my $nSigma = abs($variances[$i] - $var) / $varStdev;
+	if ($nSigma > REJECT_STDEV->{$det_type}) {
+	    print "Rejecting $expTag based on outlier stdev: " .
+		sqrt($variances[$i]) . " is $nSigma vs " . REJECT_STDEV->{$det_type} . "\n";
+	    $reject = 1;
+	    goto UPDATE;
+	}
+    } else {
+	print "no rejection for exposure stdev\n";
+    }
+    
+  UPDATE:
+    if ($reject) {
+	$command .= ' -reject';
+    }
+    
+    # Check for status changes
+    if ((not $include[$i] and not $reject) or ($include[$i] and $reject)) {
+	print "Status of $expTag has changed.\n";
+	$numChanges++;
+    }
+
+    unless ($no_update) {
+	# Update 
+	my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	    run(command => $command, verbose => 1);
+	die "Unable to perform dettool -updateresidexp: $error_code\n" if not $success;
+    }
+}
+    
+# Decide if the current is sufficient to use as a master, and if we can stop iterating
+my $master = 1;			# This is good enough for a master
+my $stop = 1;			# Stop iterating
+
+if ($numChanges > 0) {
+    $master = 0;
+    $stop = 0;
+}
+
+print "Master: $master\n";
+print "Stop: $stop\n";
+
+# Put the result into the database
+unless ($no_update) {
+    my $command = "$dettool -adddetrunsummary -det_id $det_id -iteration $iter" .
+	" -bg " . $mean . " -bg_stdev " . sqrt($var) .
+	" -bg_mean_stdev " . $meanStdev;
+    $command .= " -accept" if $master;
+    
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -adddetrunsummary: $error_code\n" if not $success;
+}
+
+# Re-run processing if required
+unless ($no_update) {
+    my $command = "$dettool -updatedetrun -det_id $det_id";
+    if ($stop) {
+	$command .= ' -stop';
+    } else {
+	$command .= ' -again';
+    }
+    
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -updatedetrun: $error_code\n" if not $success;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippScripts/scripts/detrend_reject_imfile.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_reject_imfile.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_reject_imfile.pl	(revision 9459)
@@ -0,0 +1,302 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Statistics::Descriptive;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($det_id, $iter, $exp_tag, $det_type, $no_update, $reject);
+GetOptions(
+	   'det_id|d=s'        => \$det_id,
+	   'iteration=s'       => \$iter,
+	   'exp_tag|e=s'       => \$exp_tag,
+	   'det_type|t=s'      => \$det_type,
+	   'no-update'         => \$no_update,
+	   'reject'            => \$reject
+	   ) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+	  -msg => "Required options: --det_id --iteration --exp_tag --det_type",
+	  -exitval => 3,
+	  ) unless defined $det_id
+    and defined $iter
+    and defined $exp_tag
+    and defined $det_type;
+
+use constant RECIPE1 => 'PPIMAGE_J1'; # Recipe to use for ppImage to make JPEGs
+use constant RECIPE2 => 'PPIMAGE_J2'; # Recipe to use for ppImage to make JPEGs
+
+#### XXXXX these values must come from the config system, and may depend on filter!!!
+# XXX it is valid to reject on more than one criterion
+
+# The expected mean, as a function of detrend type
+use constant EXPECTED_MEAN => {
+    'bias' => 0,		# Bias should be zero
+    'dark' => 0,		# Dark should be zero
+    'shutter' => undef,		# Shutter could be anything (depends on exposure level)
+    'flat' => 0		        # Flat could be anything (depends on exposure level)
+    };
+
+# Rejection threshold for the mean
+# This measures how close it is to what's expected
+use constant REJECT_IMFILE_MEAN => {
+    'bias' => 0,		# Should be fairly flat; some CRs
+    'dark' => 0,		# Lots of CRs
+    'shutter' => undef,		# Can't define expected value (depends on exposure level)
+    'flat' => 0		# Can't define expected value (depends on exposure level)
+    };
+
+# Rejection threshold for the standard deviation, in ADUs
+# This measures how much variation there is in each imfile
+use constant REJECT_IMFILE_STDEV => {
+    'bias' => 15,		# Should be fairly flat; some CRs
+    'dark' => 0,		# Lots of CRs
+    'shutter' => undef,		# Can be significant structure
+    'flat' => 0	       	# Stars and galaxies
+    };
+
+# Rejection threshold for the mean of the exposure, in terms of the standard deviation of the exposure
+# This measures how close it is to what's expected
+use constant REJECT_EXPOSURE_MEAN => {
+    'bias' => 0,		# Should be little variation between chips
+    'dark' => 0,		# Could be some glow on some chips
+    'shutter' => undef,		# Can't define expected value (depends on exposure level)
+    'flat' => 0		# Can't define expected value (depends on exposure level)
+    };
+
+# Rejection threshold for the stdev of the exposure, in ADUs
+# This measures how much variation there is across the imfiles
+use constant REJECT_EXPOSURE_STDEV => {
+    'bias' => 15,		# Should be little variation between chips
+    'dark' => 0,		# Could be some glow on some chips
+    'shutter' => undef,		# Can be significant structure
+    'flat' => 0		        # Could be features on some chips, but all should be about the same
+    };
+
+# Rejection threshold for the stdev of the exposure, in ADUs
+# This measures how much variation there is across the imfiles
+use constant REJECT_EXPOSURE_MEAN_STDEV => {
+    'bias' => 0,		# Should be little variation between chips
+    'dark' => 0,		# Could be some glow on some chips
+    'shutter' => undef,		# Can be significant structure
+    'flat' => 0		        # Could be features on some chips, but all should be about the same
+    };
+
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+
+# Get list of imfile files
+my $files;			# Array of imfile files
+{
+    my $command = "$dettool -residimfile -det_id $det_id -iteration $iter -exp_tag $exp_tag"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -residimfile: $error_code\n" if not $success;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) 
+        or die "unable to parse metadata config doc";
+    $files = parse_md_list($metadata);
+}
+
+my $example = ${$files}[0]->{b1_uri}; # Example file
+my ($vol, $dir, $file) = File::Spec->splitpath( $example );
+
+# Generate the file list, and get the statistics
+my $outputRoot = $exp_tag . '.detresid.' . $det_id . '.' . $iter; # Root output name
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+my $list1Name = $outputRoot . '.b1.list'; # Name for the input file list for binning 1
+my $list2Name = $outputRoot . '.b2.list'; # Name for the input file list for binning 2
+my @means;			# Array of means
+my @variances;			# Array of variances
+open my $list1File, '>' . $list1Name;
+open my $list2File, '>' . $list2Name;
+foreach my $file (@$files) {
+    print $list1File File::Spec->rel2abs( $file->{b1_uri}, $ipprc->workdir() ) . "\n";
+    print $list2File File::Spec->rel2abs( $file->{b2_uri}, $ipprc->workdir() ) . "\n";
+    push @means, $file->{bg};
+    ## calculate the root-mean-square of the bd_stdevs
+    push @variances, $file->{bg_stdev}*$file->{bg_stdev};
+}
+close $list1File;
+close $list2File;
+
+# Output products --- need to synch with the camera configuration!
+my $jpeg1Name = $outputRoot . ".b1.jpg"; # Binned JPEG #1
+my $jpeg2Name = $outputRoot . ".b2.jpg"; # Binned JPEG #2
+
+# Make the jpeg for binning 1
+{
+    my $command = "$ppImage -list $list1Name $outputRoot -recipe PPIMAGE " . RECIPE1; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg1Name\n" if not -f $jpeg1Name;
+}
+
+# Make the jpeg for binning 2
+{
+    my $command = "$ppImage -list $list2Name $outputRoot -recipe PPIMAGE " . RECIPE2; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg2Name\n" if not -f $jpeg2Name;
+}
+
+# Check the existence of the required rejection levels as a function of detrend type
+die "Unknown expected mean for detrend type $det_type\n"
+    if not exists EXPECTED_MEAN->{$det_type};
+die "Unknown imfile mean rejection level for detrend type $det_type\n"
+    if not exists REJECT_IMFILE_MEAN->{$det_type};
+die "Unknown imfile stdev rejection level for detrend type $det_type\n"
+    if not exists REJECT_IMFILE_STDEV->{$det_type};
+die "Unknown exposure mean rejection level for detrend type $det_type\n"
+    if not exists REJECT_EXPOSURE_MEAN->{$det_type};
+die "Unknown exposure stdev rejection level for detrend type $det_type\n"
+    if not exists REJECT_EXPOSURE_STDEV->{$det_type};
+die "Unknown exposure mean stdev rejection level for detrend type $det_type\n"
+    if not exists REJECT_EXPOSURE_MEAN_STDEV->{$det_type};
+
+# Reject based on the stats of the imfiles
+# it is VALID to reject on more than one criterion
+die "Number of means and number of variances differ!\n" if scalar @means != scalar @variances;
+for (my $i = 0; $i < scalar @means; $i++) {
+    my $mean = $means[$i];	# Mean for this imfile
+    $mean -= EXPECTED_MEAN->{$det_type} if defined EXPECTED_MEAN->{$det_type};
+    my $stdev = sqrt($variances[$i]);	# Stdev for this imfile
+
+    if (REJECT_IMFILE_MEAN->{$det_type}) {
+	if (abs($mean) > REJECT_IMFILE_MEAN->{$det_type}) {
+	    print "Rejecting exposure based on bad imfile mean for imfile $i: " .
+		$mean . " vs " . REJECT_IMFILE_MEAN->{$det_type} . "\n";
+	    $reject = 1;
+	    last;
+	}
+    }  else {
+	print "no rejection for imfile mean\n";
+    }
+    if (REJECT_IMFILE_STDEV->{$det_type}) {
+	if ($stdev > REJECT_IMFILE_STDEV->{$det_type}) {
+	    print "Rejecting exposure based on bad imfile stdev for imfile $i: " .
+		$stdev . " vs " . REJECT_IMFILE_STDEV->{$det_type} . "\n";
+	    $reject = 1;
+	    last;
+	}
+    } else {
+	print "no rejection for imfile stdev\n";
+    }
+}
+
+# calculate the exposure ensemble statistics
+my $meanStats = Statistics::Descriptive::Sparse->new();	# Statistics calculator for means
+$meanStats->add_data(@means);
+my $varianceStats = Statistics::Descriptive::Sparse->new(); # Statistics calculator for variances
+$varianceStats->add_data(@variances);
+
+my $mean = $meanStats->mean();	# Mean of the imfile means
+my $meanStdev = $meanStats->standard_deviation(); # Stdev of the imfile means
+if (not defined $meanStdev) {
+    # this is the case for Nimfile == 1
+    $meanStdev = 0;
+}
+my $stdev = sqrt($varianceStats->mean()); # Root-Mean-Square of the imfile stdevs (root mean of variances)
+print "exposure mean $mean, stdev $stdev, mean stdev $meanStdev\n";
+
+## Reject based on the exposure ensemble stats
+# reject if the exposure ensemble mean is deviant
+if (REJECT_EXPOSURE_MEAN->{$det_type}) {
+    if (abs($mean) > REJECT_EXPOSURE_MEAN->{$det_type}) {
+	print "Rejecting exposure based on bad mean: " . ($mean / $stdev) . " vs " .
+	    REJECT_EXPOSURE_MEAN->{$det_type} . "\n";
+	$reject = 1;
+    } 
+} else {
+    print "no rejection for imfile mean\n";
+}
+# reject if the exposure ensemble stdev is deviant
+if (REJECT_EXPOSURE_STDEV->{$det_type}) {
+    if ($stdev > REJECT_EXPOSURE_STDEV->{$det_type}) {
+	print "Rejecting exposure based on bad mean stdev: " . $stdev . " vs " .
+	    REJECT_EXPOSURE_STDEV->{$det_type} . "\n";
+	$reject = 1;
+    }
+} else {
+    print "no rejection for imfile stdev\n";
+}
+# reject if the exposure ensemble mean stdev is deviant
+if (REJECT_EXPOSURE_MEAN_STDEV->{$det_type}) {
+    if ($meanStdev > REJECT_EXPOSURE_MEAN_STDEV->{$det_type}) {
+	print "Rejecting exposure based on bad mean stdev: " . $meanStdev . " vs " .
+	    REJECT_EXPOSURE_MEAN_STDEV->{$det_type} . "\n";
+	$reject = 1;
+    }
+} else {
+    print "no rejection for imfile mean stdev\n";
+}
+
+# Add the result into the database
+$jpeg1Name = File::Spec->abs2rel( $jpeg1Name, $ipprc->workdir() );
+$jpeg2Name = File::Spec->abs2rel( $jpeg2Name, $ipprc->workdir() );
+unless ($no_update) {
+    my $command = "$dettool -addresidexp -det_id $det_id -iteration $iter -exp_tag $exp_tag " .
+	"-recip " . RECIPE1() . "," . RECIPE2() . " -b1_uri $jpeg1Name -b2_uri $jpeg2Name " .
+	"-bg $mean -bg_stdev $stdev -bg_mean_stdev $meanStdev";	# Command to run
+    $command .= ' -reject' if $reject;
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -addresidexp: $error_code\n" if not $success;
+
+    unlink $list1Name;
+    unlink $list2Name;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__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
Index: /branches/cache/ippScripts/scripts/detrend_resid.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_resid.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_resid.pl	(revision 9459)
@@ -0,0 +1,150 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::Stats;
+use Data::Dumper;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($det_id, $iter, $exp_tag, $class_id, $det_type, $detrend,
+        $input_uri, $no_update);
+GetOptions(
+    'det_id|d=s'        => \$det_id,
+    'iteration=s'       => \$iter,
+    'exp_tag|e=s'        => \$exp_tag,
+    'class_id|i=s'      => \$class_id,
+    'det_type|t=s'      => \$det_type,
+    'detrend=s'         => \$detrend,
+    'input_uri|u=s'     => \$input_uri,
+    'no-update'         => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --det_id --iteration --exp_tag --class_id --det_type --detrend --input_uri",
+    -exitval => 3,
+) unless defined $det_id
+    and defined $iter
+    and defined $exp_tag
+    and defined $class_id
+    and defined $det_type
+    and defined $detrend
+    and defined $input_uri;
+
+# Recipes to use, as a function of the detrend type
+use constant RECIPES => {
+    'bias' => 'PPIMAGE_B',	# Bias only
+    'dark' => 'PPIMAGE_D',	# Dark only
+    'shutter' => 'PPIMAGE_S',	# Shutter only
+    'flat' => 'PPIMAGE_F',	# Flat-field only
+};
+
+# Flags to specify the particular detrend to use
+use constant DETRENDS => {
+    'bias' => '-bias',		# Specify the bias frame
+    'dark' => '-dark',		# Specify the dark frame
+    'shutter' => '-shutter',	# Specify the shutter frame
+    'flat' => '-flat',		# Specify the flat 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);
+die "Can't find required tools.\n" if $missing_tools;
+
+# Recipe to use in processing
+my $recipe = RECIPES->{$det_type};
+die "Unrecognised detrend type: $det_type\n" if not defined $recipe;
+# Detrend to use in processing
+my $detFlag = DETRENDS->{$det_type};
+die "Unrecognised detrend type: $det_type\n" if not defined $detFlag;
+
+### Output file names --- must match camera configuration!
+my ($vol, $dir, $file) = File::Spec->splitpath( $input_uri );
+my $outputRoot = $exp_tag . '.detresid.' . $det_id . '.' . $iter; # Root name
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+$input_uri = File::Spec->rel2abs( $input_uri, $ipprc->workdir() );
+$detrend = File::Spec->rel2abs( $detrend, $ipprc->workdir() );
+my $outputName = $outputRoot . '.' . $class_id . '.fits'; # Name for 
+my $outputStats = $outputRoot . '.' . $class_id . '.stats';
+my $bin1Name = $outputRoot . '.' . $class_id . '.b1.fits';
+my $bin2Name =  $outputRoot . '.' . $class_id . '.b2.fits';
+
+# Run ppImage
+{
+    my $command = "$ppImage -file $input_uri $outputRoot -recipe PPIMAGE $recipe" .
+	" -stat $outputStats $detFlag $detrend"; # Command to run ppImage
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform ppImage on $input_uri: $error_code\n" if not $success;
+    die "Couldn't find expected output file: $outputName\n" if not -f $outputName;
+    die "Couldn't find expected output file: $outputStats\n" if not -f $outputStats;
+    die "Couldn't find expected output file: $bin1Name\n" if not -f $bin1Name;
+    die "Couldn't find expected output file: $bin2Name\n" if not -f $bin2Name;
+}
+
+# Get the statistics on the residual image
+my $stats;			# Statistics from ppImage
+{
+    my $statsFile;		# File handle
+    open $statsFile, $outputStats or die "Can't open statistics file $outputStats: $!\n";
+    my @contents = <$statsFile>; # Contents of file
+    close $statsFile;
+    my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+    my $metadata = $mdcParser->parse(join "", @contents)
+        or die "unable to parse metadata config doc";
+    $stats = PS::IPP::Metadata::Stats->new(); # Stats parser
+    $stats->parse($metadata) or die "Unable to find all values in statistics output.\n";
+}
+
+# Add the processed file to the database
+# XXX I think this has the names "bg_stdev" and "bg_mean_stdev" exchanged
+#     bg_stdev : standard deviation of the background
+#     bg_mean_stdev : standard deviation of the background means
+$outputName = File::Spec->abs2rel ($outputName, $ipprc->workdir() );
+$bin1Name = File::Spec->abs2rel( $bin1Name, $ipprc->workdir() );
+$bin2Name = File::Spec->abs2rel( $bin2Name, $ipprc->workdir() );
+unless ($no_update) {
+    my $command = "$dettool -addresidimfile -det_id $det_id -iteration $iter -exp_tag $exp_tag " .
+	"-class_id $class_id -recip $recipe -uri $outputName -b1_uri $bin1Name " .
+	"-b2_uri $bin2Name"; # Command to run dettool
+    $command .= " -bg " . $stats->bg_mean();
+
+    # XXX note bg_stdev <--> bg_mean_stdev
+    if (defined($stats->bg_stdev())) {
+	$command .= " -bg_mean_stdev " . $stats->bg_stdev();
+    } else {
+	# May be undefined if there is only a single imfile
+	$command .= ' -bg_stdev 0';
+    }
+
+    # XXX note bg_stdev <--> bg_mean_stdev
+    $command .= " -bg_stdev " . $stats->bg_mean_stdev();
+
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -addprocessed for $det_id/$exp_tag/$class_id: $error_code\n"
+	if not $success;
+
+    unlink $outputStats;    
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippScripts/scripts/detrend_stack.pl
===================================================================
--- /branches/cache/ippScripts/scripts/detrend_stack.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/detrend_stack.pl	(revision 9459)
@@ -0,0 +1,135 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use PS::IPP::Metadata::Stats;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($det_id, $iter, $class_id, $det_type, $camera, $no_update);
+GetOptions(
+    'det_id|d=s'        => \$det_id,
+    'iteration=s'       => \$iter,
+    'class_id|i=s'      => \$class_id,
+    'det_type|t=s'      => \$det_type,
+    'camera|c=s'        => \$camera,
+    'no-update'         => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --det_id --iteration --class_id --det_type --camera",
+    -exitval => 3,
+) unless defined $det_id
+    and defined $iter
+    and defined $class_id
+    and defined $det_type
+    and defined $camera;
+
+# Recipes to use as a function of detrend type
+use constant RECIPES => {
+    'bias' => 'PPMERGE_BIAS',
+    'dark' => 'PPMERGE_DARK',
+    'shutter' => 'PPMERGE_SHUTTER',
+    'flat' => 'PPMERGE_FLAT'
+    };
+
+die "Unrecognised detrend type: $det_type\n" if not defined RECIPES()->{$det_type};
+my $recipe = RECIPES()->{$det_type}; # Recipe to use in stacking
+
+# Look for programs we need
+my $missing_tools;
+my $dettool = can_run('dettool') or (warn "Can't find dettool" and $missing_tools = 1);
+my $ppMerge = can_run('ppMerge') or (warn "Can't find ppMerge" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+
+# Get list of files to stack
+my $files;			# Array of files to be stacked
+{
+    my $command = "$dettool -processedimfile -det_id $det_id -class_id $class_id -included"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -processedimfile: $error_code\n" if not $success;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf)
+        or die "unable to parse metadata config doc";
+    $files = parse_md_list($metadata);
+}
+
+my $example = ${$files}[0]->{uri}; # Example file
+my ($vol, $dir, $file) = File::Spec->splitpath( $example );
+
+# Stack the files
+my $outputRoot = $camera . '.' . $det_type . '.' . $det_id . '.' . $iter . '.' . $class_id; # Root name
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+my $outputStack = $outputRoot . '.fits'; # Output name
+my $outputStats = $outputRoot . '.stats'; # Statistics name
+{
+    my $command = "$ppMerge $outputStack"; # Command to run
+    foreach my $file (@$files) {
+	my $uri = $file->{uri};	# URI for input file
+	$uri = File::Spec->rel2abs( $uri, $ipprc->workdir() );
+	$command .= ' ' . $uri;
+    }
+    $command .= " -recipe PPMERGE $recipe";
+    $command .= ' -type ' . uc($det_type); # Type of stacking to perform
+    $command .= " -stats $outputStats";	# Statistics output filename
+
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform ppMerge: $error_code\n" if not $success;
+    die "Unable to find expected output file: $outputStack\n" if not -f $outputStack;
+    die "Unable to find expected output file: $outputStats\n" if not -f $outputStats;
+}
+
+# Get the statistics on the stacked image
+my $stats;			# Statistics from ppImage
+{
+    open(my $statsFile, "$outputStats")
+        or die "Can't open statistics file $outputStats: $!\n";
+    my $contents = do { local $/; <$statsFile> }; # Contents of file
+    close($statsFile);
+
+    my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+    my $metadata = $mdcParser->parse($contents)
+        or die "unable to parse metadata config doc";
+    $stats = PS::IPP::Metadata::Stats->new(); # Stats parser
+    $stats->parse($metadata) or die "Unable to find all values in statistics output.\n";
+}
+
+# Add the resultant into the database
+$outputStack = File::Spec->abs2rel( $outputStack, $ipprc->workdir() );
+unless ($no_update) {
+    my $command = "$dettool -addstacked -det_id $det_id -iteration $iter -class_id $class_id" .
+	" -uri $outputStack -recip $recipe"; # Command to run
+    $command .= ' -bg ' . $stats->bg_mean();
+    if (defined($stats->bg_stdev())) {
+    $command .= ' -bg_stdev ' . $stats->bg_stdev();
+    } else {
+	# May be undefined if there is only a single imfile
+	$command .= ' -bg_stdev 0';
+    }
+    $command .= ' -bg_mean_stdev ' . $stats->bg_mean_stdev();
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform dettool -addstacked: $error_code\n" if not $success;
+
+    unlink $outputStats;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippScripts/scripts/ipp_workdir.pl
===================================================================
--- /branches/cache/ippScripts/scripts/ipp_workdir.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/ipp_workdir.pl	(revision 9459)
@@ -0,0 +1,12 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new();
+print $ipprc->workdir() . "\n";
+
+1;
+
+__END__
Index: /branches/cache/ippScripts/scripts/mdc2list.pl
===================================================================
--- /branches/cache/ippScripts/scripts/mdc2list.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/mdc2list.pl	(revision 9459)
@@ -0,0 +1,72 @@
+#!/usr/bin/env perl
+
+# Program to convert a PS metadata config syntax (usually from one of
+# the IPP tools) into a flat tab-delimited list suitable for parsing
+# using "split".
+
+# Copyright (C) 2006  Joshua Hoblitt, Paul A. Price.
+
+use strict;
+use warnings;
+
+use PS::IPP::Metadata::Config;	# Supplies the metadata config parser.
+
+die "Program to convert a PS metadata config file (usually from one of the IPP\n" .
+    "tools) into a flat tab-delimited list suitable for parsing using \'split\'.\n\n" .
+    "Usage: $0 [INFILE [OUTFILE]]\n" if ((join "", @ARGV) =~ /--help/ or scalar @ARGV > 2);
+
+my $inFile;			# Input file
+my $outFile;			# Output file
+if (scalar @ARGV >= 1) {
+    my $inName = shift @ARGV;
+    open $inFile, $inName or die "Can't open $inName: $!\n";
+    if (scalar @ARGV == 1) {
+	my $outName = shift @ARGV;
+	open $outFile, ">", $outName or die "Can't open $outName: $!\n";
+    } else {
+	$outFile = *STDOUT;
+    }
+} else {
+    $inFile = *STDIN;
+    $outFile = *STDOUT;
+}
+
+my @input = <$inFile>;		# Contents of the metadata config file
+my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
+my $md = $mdcParser->parse(join "", @input)
+        or die "unable to parse metadata config doc";
+my $hashes = mds2hashes($md);	# An array of hashes
+foreach my $pending (@$hashes) {
+    foreach my $key (keys %$pending) {
+	print $outFile ( $pending->{$key} . "\t");
+    }
+    print $outFile "\n";
+}
+
+### Pau.
+
+
+# Given an array of MDs, return an array of hashes
+sub mds2hashes
+{
+    my $mds = shift;		# Reference to the metadatas
+    my @array;			# The array of hashes, to be returned
+    foreach my $md (@$mds) {
+        my $values = md2hash($md->{value});
+        push @array, $values;
+    }
+    return \@array;
+}
+
+# Convert the metadata to a hash; in effect, strips out the comment, type and class fields.
+sub md2hash
+{
+    my $values = shift;		# Reference to the metadata
+    my %hash;			# Hash, to be returned
+    foreach my $data (@$values) {
+        $hash{$data->{name}} = $data->{value};
+    }
+    return \%hash;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
Index: /branches/cache/ippScripts/scripts/phase0_exp.pl
===================================================================
--- /branches/cache/ippScripts/scripts/phase0_exp.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/phase0_exp.pl	(revision 9459)
@@ -0,0 +1,178 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Statistics::Descriptive;
+use Data::Dumper;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($exptag, $no_update);
+
+GetOptions(
+    'exp_tag|e=s'    => \$exptag,
+    'no-update'     => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --exp_tag",
+    -exitval => 3,
+) unless defined $exptag;
+
+# Define setup
+use constant TYPE => "exp_type"; # Observation type keyword
+use constant DETRENDS => [ "bias", "dark", "shutter", "flat", "fringe" ]; # Observation types to mark as detrend
+use constant DETREND_FLAG => "-detrend"; # Flag to use to mark detrend exposure
+
+use constant PHASE0_URI => 'uri'; # Key for the URI
+use constant PHASE0_CLASSID => 'class_id'; # Key for the class id
+use constant PHASE0_BG => 'bg';        # Key for the background
+use constant PHASE0_BG_STDEV => 'bg_stdev'; # Key for the background standard deviation
+use constant PHASE0_BG_MEAN_STDEV => 'bg_mean_stdev'; # Key for the mean of the background standard deviation
+
+use constant EXP_BG => '-background'; # Switch to add background for exposure
+use constant EXP_BGSD => '-background_stdev'; # Switch to add background standard deviation
+use constant EXP_BGMEANSD => '-background_mean_stdev'; # Switch to add mean of background standard deviation
+
+# These values should be constant for all components
+use constant CONSTANTS => [
+			   "object", # Object
+                           "exp_type", # Exposure type
+                           "filter", # Filter used
+                           "airmass", # Airmass
+                           "ra", # Right ascension
+                           "decl", # Declination
+                           "posang", # Position angle
+                           "alt", # Altitude
+                           "az", # Azimuth
+                           "ccd_temp" # CCD temperature
+                       ];
+
+# These values may vary across components; we will take the average
+use constant VARIABLES => [
+                           "exp_time", # Exposure time
+###                           "time" # Time of exposure --- not yet implemented
+                           ];
+
+
+# Look for commands we need
+my $missing_tools;
+my $p0tool = can_run('p0tool')
+    or (warn "can't find p0tool" and $missing_tools = 1);
+my $ppStats = can_run('ppStats')
+    or (warn "can't find ppStats" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+my $mdcParser = PS::IPP::Metadata::Config->new;        # Parser for metadata config files
+
+# Get the list of imfiles
+my $imfiles;
+{
+    my $command = "$p0tool -rawimfile -exp_tag $exptag";
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => 1);
+    die "Unable to perform p0tool on exposure id $exptag: $error_code\n" if not $success;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf)
+            or die "unable to parse metadata config doc";
+    $imfiles = parse_md_list($metadata); # Data for imfiles
+}
+
+# Process the values
+my %values;                        # Values to update
+foreach my $variable (@{VARIABLES()}) {
+    $values{$variable} = [];
+}
+my @backgrounds;                # Array of backgrounds
+my @stdevs;                        # Array of background standard deviations\
+my $obsType;                        # Observation type
+  
+foreach my $imfile (@$imfiles) {
+    foreach my $constant (@{CONSTANTS()}) {
+        my $value = get_value($imfile, $constant); # Value for imfile
+        if (not defined $values{$constant}) {
+            $values{$constant} = $value;
+        } elsif ($values{$constant} ne $value) {
+            die "Value of $constant for " . $imfile->{PHASE0_CLASSID} .
+                " doesn't match previous value.\n";
+        }
+    }
+    
+    foreach my $variable (@{VARIABLES()}) {
+        my $value = get_value($imfile, $variable); # Value for imfile
+        my $array = $values{$variable};        # Array of data
+        push @$array, $value;
+    }
+    
+    my $bg = get_value($imfile, PHASE0_BG());
+    push @backgrounds, $bg;
+    
+    my $stdev = get_value($imfile, PHASE0_BG_MEAN_STDEV());
+    push @stdevs, $stdev;
+}
+
+# Output results to the database
+unless ($no_update) {
+    my @command;
+    push @command, $p0tool, '-updateexp', '-exp_tag', $exptag; # Command to execute to update exposure parameters
+    
+    # Add the values of interest
+    foreach my $constant (@{CONSTANTS()}) {
+	push @command, ( '-' . $constant ), $values{$constant};
+    }
+    foreach my $variable (@{VARIABLES()}) {
+        my $array = $values{$variable};        # Array of values
+        my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+        $stats->add_data(@$array);
+	push @command, ( '-' . $variable ), $stats->mean();
+    }
+
+    # Add the statistics
+    {
+        my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+        $stats->add_data(@backgrounds);
+	push @command, ( '-' . PHASE0_BG() ), $stats->mean(), ( '-' . PHASE0_BG_STDEV() );
+        if (scalar @backgrounds == 1) {
+	    push @command, 1;
+        } else {
+	    push @command, $stats->standard_deviation();
+        }
+    }
+    {
+        my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+        $stats->add_data(@stdevs);
+	push @command, ( '-' . PHASE0_BG_MEAN_STDEV() ), $stats->mean();
+    }
+    
+    # Add the detrend flag
+    foreach my $detrendType (@{DETRENDS()}) {
+        if (lc($values{TYPE()}) eq lc($detrendType)) {
+	    push @command, DETREND_FLAG;
+            last;
+        }
+    }
+ 
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => \@command, verbose => 1);
+    die "Unable to run phase0 update for $exptag: $error_code\n" if not $success;
+}
+
+### Pau.
+
+
+# Get the value for a particular imfile, along with a strong check for its existence
+sub get_value {
+    my $imfile = shift;                # The hash of values
+    my $name = shift;                # The name of the value to check
+
+    my $source = $imfile->{PHASE0_CLASSID()}; # Where it comes from
+    die "Couldn't find value of $name for class_id=$source\n" if not defined $imfile->{$name};
+    return $imfile->{$name};
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
Index: /branches/cache/ippScripts/scripts/phase0_imfile.pl
===================================================================
--- /branches/cache/ippScripts/scripts/phase0_imfile.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/phase0_imfile.pl	(revision 9459)
@@ -0,0 +1,128 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::Stats;
+use Data::Dumper;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($exp_tag, $class_id, $uri, $no_update);
+
+GetOptions(
+    'exp_tag|e=s'    => \$exp_tag,
+    'class_id|i=s'  => \$class_id,
+    'uri|u=s'       => \$uri,
+    'no-update'     => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --exp_tag --class_id --uri",
+    -exitval => 3,
+) unless defined $exp_tag 
+    and defined $class_id 
+    and defined $uri;
+
+use constant RECIPE => "PPSTATS_PHASE0"; # Recipe to use for ppStats
+
+# These values should be constant for all components
+# The key is the name in the ppStats output; the value is the switch for "phase0 -updateexp"
+use constant CONSTANTS => {
+    "FPA.OBJECT"   => "-object", # Object
+    "FPA.OBSTYPE"  => "-exp_type", # Exposure type
+    "FPA.FILTER"   => "-filter", # Filter used
+    "FPA.AIRMASS"  => "-airmass", # Airmass
+    "FPA.RA"       => "-ra",        # Right ascension
+    "FPA.DEC"      => "-decl",        # Declination
+    "FPA.ALT"      => "-alt",        # Altitude
+    "FPA.AZ"       => "-az",        # Azimuth
+    "FPA.POSANGLE" => "-posang" # Position angle
+    };
+
+# These values may vary across components; we will take the average
+# The key is the name in the ppStats output; the value is the switch for "phase0 -updateexp"
+use constant VARIABLES => {
+    "CHIP.TEMP"    => "-ccd_temp", # CCD temperature
+    "CELL.EXPOSURE" => "-exp_time" # Exposure time
+    };
+
+
+# Switches for p0tool
+use constant P0TOOL_MODE => '-updateimfile'; # Mode for p0tool
+use constant P0TOOL_EXPTAG => '-exp_tag'; # Switch to specify the exposure id
+use constant P0TOOL_CLASSID => '-class_id'; # Switch to specify the class id
+use constant P0TOOL_BG_MEAN => '-bg'; # Switch to add the background
+use constant P0TOOL_BG_STDEV => '-bg_stdev'; # Switch to add the bg stdev
+use constant P0TOOL_BG_MEAN_STDEV => '-bg_mean_stdev'; # Switch to add the bg mean stdev
+
+# Look for programs we need
+my $missing_tools;
+my $p0tool = can_run('p0tool') or (warn "Can't find p0tool" and $missing_tools = 1);
+my $ppStats = can_run('ppStats') or (warn "Can't find ppStats" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+# Resolve the input URI
+$uri = File::Spec->rel2abs( $uri, $ipprc->workdir() );
+
+# Run ppStats on the input file
+my $stats;
+{
+    my $command = "$ppStats $uri -recipe PPSTATS " . RECIPE; # Command to run ppStats
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => 1);
+    die "Unable to perform ppStats on exposure id $exp_tag: $error_code\n" if not $success;
+    
+    # Parse the output
+    my $mdcParser = PS::IPP::Metadata::Config->new;        # Parser for metadata config files
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf)
+            or die "unable to parse metadata config doc";
+    my @constants = keys %{CONSTANTS()}; # List of constants to parse out
+    my @variables = keys %{VARIABLES()}; # List of variables to parse out
+    $stats = PS::IPP::Metadata::Stats->new(\@constants, \@variables); # Stats parser
+    $stats->parse($metadata) or die "Unable to find all values.\n";
+}
+
+# Push the results into the database
+unless ($no_update) {
+    my @command;
+    push @command, $p0tool, P0TOOL_MODE(), P0TOOL_EXPTAG(), $exp_tag, P0TOOL_CLASSID(), $class_id; # Command to run p0tool
+
+    foreach my $constant (keys %{CONSTANTS()}) {
+	push @command, CONSTANTS->{$constant}, ($stats->data($constant))->{value};
+    }
+    foreach my $variable (keys %{VARIABLES()}) {
+        # Just use the mean value
+	push @command, VARIABLES->{$variable}, ($stats->data($variable))->{mean};
+    }
+    
+    push @command, P0TOOL_BG_MEAN(), $stats->bg_mean(), P0TOOL_BG_STDEV();
+    if (defined($stats->bg_stdev())) {
+	push @command, $stats->bg_stdev();
+    } else {
+	# Will not be defined if there is only a single imfile
+	push @command, 0;
+    }
+    push @command,  P0TOOL_BG_MEAN_STDEV(), $stats->bg_mean_stdev();
+ 
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => \@command, verbose => 1);
+    die "Unable to perform p0tool -updateimfile: $error_code\n" if not $success;
+}
+
+# Pau.
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippScripts/scripts/phase2.pl
===================================================================
--- /branches/cache/ippScripts/scripts/phase2.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/phase2.pl	(revision 9459)
@@ -0,0 +1,110 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::Stats;
+use Data::Dumper;
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+use constant RECIPE => 'PPIMAGE_OBDSF'; # Recipe to use
+
+# Parse the command-line arguments
+my ($expTag,			# Exposure tag
+    $classId,			# Class Id
+    $input,			# Input FITS file
+    $no_update			# Don't update the database?
+    );
+GetOptions(
+    'exp_tag|e=s'   => \$expTag,
+    'class_id|i=s'  => \$classId,
+    'uri|u=s'       => \$input,
+    'no-update'     => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --exp_tag --class_id --uri",
+    -exitval => 3,
+) unless defined $expTag 
+    and defined $classId 
+    and defined $input;
+
+# Look for programs we need
+my $missing_tools;
+my $p2tool = can_run('p2tool') or (warn "Can't find p2tool" and $missing_tools = 1);
+my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+### Output file name --- must match camera configuration!
+my ($vol, $dir, $file) = File::Spec->splitpath( $input );
+my $outputRoot =  $expTag . '.p2';
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+$input = File::Spec->rel2abs( $input, $ipprc->workdir() );
+my $outputImage = $outputRoot  . '.' . $classId . '.fits';
+my $outputStats = $outputRoot  . '.' . $classId . '.stats';
+my $outputBin1Name = $outputRoot . '.' . $classId . '.b1.fits';
+my $outputBin2Name = $outputRoot . '.' . $classId . '.b2.fits';
+
+# Run ppImage
+{
+    my $command = "$ppImage -file $input $outputRoot -recipe PPIMAGE " . RECIPE .
+	" -stat $outputStats"; # Command to run ppImage
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform ppImage on $input: $error_code\n" if not $success;
+    die "Couldn't find expected output file: $outputImage\n" if not -f $outputImage;
+    die "Couldn't find expected output file: $outputBin1Name\n" if not -f $outputBin1Name;
+    die "Couldn't find expected output file: $outputBin2Name\n" if not -f $outputBin2Name;
+    die "Couldn't find expected output file: $outputStats\n" if not -f $outputStats;
+}
+
+# Get the statistics on the processed image
+my $stats;			# Statistics from ppImage
+{
+    my $statsFile;		# File handle
+    open $statsFile, $outputStats or die "Can't open statistics file $outputStats: $!\n";
+    my @contents = <$statsFile>; # Contents of file
+    close $statsFile;
+    my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+    my $metadata = $mdcParser->parse(join "", @contents)
+            or die "unable to parse metadata config doc";
+    $stats = PS::IPP::Metadata::Stats->new(); # Stats parser
+    $stats->parse($metadata) or die "Unable to find all values in statistics output.\n";
+}
+
+# Add the processed file to the database
+$outputImage = File::Spec->abs2rel( $outputImage, $ipprc->workdir() );
+$outputBin1Name = File::Spec->abs2rel( $outputBin1Name, $ipprc->workdir() );
+$outputBin2Name = File::Spec->abs2rel( $outputBin2Name, $ipprc->workdir() );
+unless ($no_update) {
+    # Command to run dettool
+    my $command = "$p2tool -addprocessedimfile";
+    $command .= " -exp_tag $expTag";
+    $command .= " -class_id $classId";
+    $command .= " -recip " . RECIPE;
+    $command .= " -uri $outputImage";
+    $command .= " -b1_uri $outputBin1Name";
+    $command .= " -b2_uri $outputBin2Name";
+    $command .= " -bg " . $stats->bg_mean();
+    $command .= " -bg_stdev " . $stats->bg_stdev();
+    $command .= " -bg_mean_stdev " . $stats->bg_mean_stdev();
+
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform p2tool -addprocessedimfile for $expTag/$classId: $error_code\n"
+	if not $success;
+
+    unlink $outputStats;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippScripts/scripts/phase3.pl
===================================================================
--- /branches/cache/ippScripts/scripts/phase3.pl	(revision 9459)
+++ /branches/cache/ippScripts/scripts/phase3.pl	(revision 9459)
@@ -0,0 +1,155 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Statistics::Descriptive;
+
+use PS::IPP::Config;
+my $ipprc = PS::IPP::Config->new(); # IPP configuration
+use File::Spec;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+my ($exp_tag, $no_update);
+GetOptions(
+    'exp_tag|e=s'       => \$exp_tag,
+    'no-update'         => \$no_update
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --exp_tag",
+    -exitval => 3,
+) unless defined $exp_tag;
+
+use constant RECIPE1 => 'PPIMAGE_J1'; # Recipe to use for ppImage to make JPEGs
+use constant RECIPE2 => 'PPIMAGE_J2'; # Recipe to use for ppImage to make JPEGs
+
+
+# Look for programs we need
+my $missing_tools;
+my $p3tool = can_run('p3tool') or (warn "Can't find p3tool" and $missing_tools = 1);
+my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+die "Can't find required tools.\n" if $missing_tools;
+
+my $mdcParser = PS::IPP::Metadata::Config->new;	# Parser for metadata config files
+
+# Get list of component files
+my $files;			# Array of component files
+{
+    my $command = "$p3tool -pendingimfile -exp_tag $exp_tag"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform p3tool -pendingimfile: $error_code\n" if not $success;
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) 
+        or die "unable to parse metadata config doc";
+    $files = parse_md_list($metadata);
+}
+
+# Gather the statistics
+my ($bg, $bg_stdev, $bg_mean_stdev); # The statistics triplet
+{
+    my @backgrounds;		# Array of backgrounds in each component
+    my @stdevs;			# Array of standard deviations in each component
+#    my @ra;			# Array of ra errors
+#    my @dec;			# Array of dec errors
+#    my @zp;			# Array of photometric zero points
+    foreach my $file (@$files) {
+	die "Unable to find class id\n" unless defined $file->{class_id};
+	my $class_id = $file->{class_id};
+	die "Unable to find bg for class_id=$class_id\n" unless defined $file->{bg};
+	die "Unable to find bg_mean_stdev for class_id=$class_id\n" unless defined $file->{bg_mean_stdev};
+#	die "Unable to find sigma_ra for class_id=$class_id\n" unless defined $file->{sigma_ra};
+#	die "Unable to find sigma_dec for class_id=$class_id\n" unless defined $file->{sigma_dec};
+#	die "Unable to find zp for class_id=$class_id\n" unless defined $file->{zp};
+	push @backgrounds, $file->{bg};
+	push @stdevs, $file->{bg_mean_stdev};
+    }
+
+    {
+	my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+	$stats->add_data(@backgrounds);
+	$bg = $stats->mean();
+	if (scalar @backgrounds == 1) {
+	    $bg_stdev = 0.0;
+	} else {
+	    $bg_stdev = $stats->standard_deviation();
+	}
+    }
+    {
+	my $stats = Statistics::Descriptive::Sparse->new; # Statistics calculator
+	$stats->add_data(@stdevs);
+	$bg_mean_stdev = $stats->mean();
+    }
+}
+
+my $example = ${$files}[0]->{b1_uri}; # Example filename
+my ($vol, $dir, $file) = File::Spec->splitpath( $example );
+
+# Generate the file list, and get the statistics
+my $outputRoot = $exp_tag . '.p3'; # Root output name
+$outputRoot = File::Spec->rel2abs( File::Spec->catpath( $vol, $dir, $outputRoot ), $ipprc->workdir() );
+my $list1Name = $outputRoot . '.b1.list'; # Name for the input file list for binning 1
+my $list2Name = $outputRoot . '.b2.list'; # Name for the input file list for binning 2
+my @means;			# Array of means
+my @stdevs;			# Array of stdevs
+open my $list1File, '>' . $list1Name;
+open my $list2File, '>' . $list2Name;
+foreach my $file (@$files) {
+    print $list1File (File::Spec->rel2abs( $file->{b1_uri}, $ipprc->workdir() ) . "\n");
+    print $list2File (File::Spec->rel2abs( $file->{b2_uri}, $ipprc->workdir() ) . "\n");
+    push @means, $file->{bg};
+    push @stdevs, $file->{bg_stdev};
+}
+close $list1File;
+close $list2File;
+
+# Output products --- need to synch with the camera configuration!
+my $jpeg1Name = $outputRoot . ".b1.jpg"; # Binned JPEG #1
+my $jpeg2Name = $outputRoot . ".b2.jpg"; # Binned JPEG #2
+
+# Make the jpeg for binning 1
+{
+    my $command = "$ppImage -list $list1Name $outputRoot -recipe PPIMAGE " . RECIPE1; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg1Name\n" if not -f $jpeg1Name;
+}
+
+# Make the jpeg for binning 2
+{
+    my $command = "$ppImage -list $list2Name $outputRoot -recipe PPIMAGE " . RECIPE2; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to find expected output file: $jpeg2Name\n" if not -f $jpeg2Name;
+}
+
+
+# Add the result into the database
+$outputRoot = File::Spec->abs2rel( $outputRoot, $ipprc->workdir() );
+$jpeg1Name  = File::Spec->abs2rel( $jpeg1Name, $ipprc->workdir() );
+$jpeg2Name  = File::Spec->abs2rel( $jpeg2Name, $ipprc->workdir() );
+unless ($no_update) {
+    my $command = "$p3tool -addprocessedexp -exp_tag $exp_tag -uri UNKNOWN " .
+	"-recip " . RECIPE1() . "," . RECIPE2() . " -b1_uri $jpeg1Name -b2_uri $jpeg2Name " .
+	"-bg $bg -bg_stdev $bg_stdev -bg_mean_stdev $bg_mean_stdev " .
+	"-sigma_ra 0.0 -sigma_dec 0.0 -nastro 0 -zp_mean 0.0 -zp_stdev 0.0"; # Command to run
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	run(command => $command, verbose => 1);
+    die "Unable to perform p3tool -addprocessedexp: $error_code\n" if not $success;
+
+    unlink $list1Name;
+    unlink $list2Name;
+}
+
+END { system("sync") == 0 or die "failed to execute sync: $!" }
+
+__END__
Index: /branches/cache/ippTools/scripts/.cvsignore
===================================================================
--- /branches/cache/ippTools/scripts/.cvsignore	(revision 9459)
+++ /branches/cache/ippTools/scripts/.cvsignore	(revision 9459)
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
Index: /branches/cache/ippTools/scripts/camtest.sh
===================================================================
--- /branches/cache/ippTools/scripts/camtest.sh	(revision 9459)
+++ /branches/cache/ippTools/scripts/camtest.sh	(revision 9459)
@@ -0,0 +1,11 @@
+#!//bin/sh
+
+set -o verbose
+
+p2test.sh || exit 1
+
+p3tool -pendingexp || exit 1
+p3tool -pendingimfile || exit 1
+
+p3tool -addprocessedexp -exp_tag t10 -uri file://p3p -recip myrecipe -bg 1 -bg_stdev 2 -bg_mean_stdev 3 -sigma_ra 1 -sigma_dec 2 -nastro 42 -b1_uri file:///foo -b2_uri file://bar -zp_mean 1 -zp_stdev 2 || exit 1
+p3tool -addprocessedexp -exp_tag t11 -uri file://p3p -recip myrecipe -bg 1 -bg_stdev 2 -bg_mean_stdev 3 -sigma_ra 1 -sigma_dec 2 -nastro 42 -b1_uri file:///foo -b2_uri file://bar -zp_mean 1 -zp_stdev 2 || exit 1
Index: /branches/cache/ippTools/scripts/dettest.sh
===================================================================
--- /branches/cache/ippTools/scripts/dettest.sh	(revision 9459)
+++ /branches/cache/ippTools/scripts/dettest.sh	(revision 9459)
@@ -0,0 +1,58 @@
+#!//bin/sh
+
+set -o verbose
+
+det_id=1
+
+./p0test.sh -detrend || exit 1
+
+dettool -definebyquery -det_type flat || exit 1
+dettool -raw || exit 1
+
+for ID in `seq 0 3` ; do
+    dettool -addprocessedimfile -det_id $det_id -exp_tag t10 -class_id $ID -uri file://proc-$ID -recip myrecip -bg 1 -bg_stdev 1 -bg_mean_stdev 1 || exit 1
+done;
+
+for ID in `seq 0 3` ; do
+    dettool -addprocessedimfile -det_id $det_id -exp_tag t11 -class_id $ID -uri file://proc-$ID -recip myrecip -bg 1 -bg_stdev 1 -bg_mean_stdev 1 || exit 1
+done;
+
+dettool -tostack || exit 1
+
+for ID in `seq 0 3` ; do
+    dettool -addstacked -det_id $det_id -uri file://stacked-$ID -class_id $ID -recip myrecipe -bg 1 -bg_stdev 2 -bg_mean_stdev 3 || exit 1
+done;
+
+dettool -tonormalizedstat || exit 1
+for ID in `seq 0 3` ; do
+    dettool -addnormalizedstat -det_id $det_id -class_id $ID -norm 0.12345 || exit 1
+done;
+
+dettool -tonormalize || exit 1
+for ID in `seq 0 3` ; do
+    dettool -addnormalizedimfile -det_id $det_id -class_id $ID -uri file://normalized-$ID -bg 1 -bg_stdev 2 -bg_mean_stdev 3 -b1_uri banana1 -b2_uri banannnnnaaa2 || exit 1
+done;
+
+dettool -tonormalizedexp || exit 1
+dettool -addnormalizedexp -det_id $det_id -recip myrecipe -bg 1 -bg_stdev 2 -bg_mean_stdev 3 -b1_uri file://normalizedexp -b2_uri file://normlalizedexp|| exit 1
+
+dettool -toresid || exit 1
+
+for ID in `seq 0 3` ; do
+    dettool -addresidimfile -det_id $det_id -exp_tag t10 -class_id $ID -recip myrecip -bg 1 -bg_stdev 1 -bg_mean_stdev 1 -uri file://resid-$ID || exit 1
+done;
+for ID in `seq 0 3` ; do
+    dettool -addresidimfile -det_id $det_id -exp_tag t11 -class_id $ID -recip myrecip -bg 1 -bg_stdev 1 -bg_mean_stdev 1 -uri file://resid-$ID || exit 1
+done;
+
+dettool -toresidexp || exit 1
+dettool -addresidexp -det_id $det_id -exp_tag t10 -recip myrecipe -bg 1 -bg_stdev 2 -bg_mean_stdev 3 -b1_uri jpeg1 -b2_uri jpeg2  || exit 1
+dettool -addresidexp -det_id $det_id -exp_tag t11 -recip myrecipe -bg 1 -bg_stdev 2 -bg_mean_stdev 3 -b1_uri jpeg1 -b2_uri jpeg2  -reject || exit 1
+
+dettool -residdetrun || exit 1
+dettool -residexp || exit 1
+dettool -updateresidexp -det_id $det_id -iteration 0 -recip yourrecipe || exit 1
+dettool -updateresidexp -det_id $det_id -iteration 0 -exp_tag t10 -reject || exit 1
+dettool -updateresidexp -det_id $det_id -iteration 0 -exp_tag t11 || exit 1
+dettool -residexp || exit 1
+dettool -updatedetrun -det_id $det_id -again || exit 1
Index: /branches/cache/ippTools/scripts/regtest.sh
===================================================================
--- /branches/cache/ippTools/scripts/regtest.sh	(revision 9459)
+++ /branches/cache/ippTools/scripts/regtest.sh	(revision 9459)
@@ -0,0 +1,32 @@
+#!//bin/sh
+
+set -o verbose
+
+inject="pxinject"
+p0tool="p0tool"
+
+echo -e "YES\nipp\n\n" | pxadmin -recreate || exit 1
+
+$inject -newExp -exp_tag t10 -exp_id 10 -inst gpc -telescope ps1 -exp_type object -imfiles 4 || exit 1
+
+for ID in `seq 0 3`; do
+    $inject -newImfile -exp_tag t10 -class OTA -class_id $ID -uri file://$ID || exit 1
+done;
+
+$inject -newExp -exp_tag t11 -exp_id 11 -inst gpc -telescope ps1 -exp_type object -imfiles 4 || exit 1
+
+for ID in `seq 0 3`; do
+    $inject -newImfile -exp_tag t11 -class OTA -class_id $ID -uri file://$ID || exit 1
+done;
+
+for ID in `seq 0 3`; do
+    $p0tool -updateimfile -exp_tag t10 -exp_type object -class OTA -class_id $ID -filter r -airmass 10 -ra 1 -decl 2 -exp_time 0 -bg 1 -bg_stdev 1 -bg_mean_stdev 10 -alt 10 -az 10 -ccd_temp 10 -posang 10 -object dog || exit 1
+done;
+
+$p0tool -updateexp -exp_tag t10 -filter r -airmass 10 -ra 1 -decl 2 -exp_type bias -exp_time 0 -bg 10 -bg_stdev 1 -bg_mean_stdev 10 -alt 10 -az 10 -ccd_temp 45 -posang 10 -object dog $* || exit 1
+
+for ID in `seq 0 3`; do
+    $p0tool -updateimfile -exp_tag t11 -exp_type object -class OTA -class_id $ID -filter r -airmass 10 -ra 1 -decl 2 -exp_time 0 -bg 1 -bg_stdev 1 -bg_mean_stdev 10 -alt 10 -az 10 -ccd_temp 10 -posang 10 -object dog || exit 1
+done;
+
+$p0tool -updateexp -exp_tag t11 -filter r -airmass 11 -ra 1 -decl 2 -exp_type bias -exp_time 0 -bg 11 -bg_stdev 1 -bg_mean_stdev 11 -alt 11 -az 11 -ccd_temp 45 -posang 11 -object dog $* || exit 1
