Index: branches/czw_branch/20100427/ippScripts/scripts/automate_stacks.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/automate_stacks.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/automate_stacks.pl	(revision 28017)
@@ -56,5 +56,5 @@
 # Grab options
 my ( $date, $camera, $dbname, $logfile, $verbose, $manual);
-my ( $help, $isburning, $force_stack_count, $test_mode, $this_target_only, $this_filter_only);
+my ( $help, $isburning, $force_stack_count, $test_mode, $this_target_only, $this_filter_only, $check_mode);
 my ( $check_registration, $define_burntool, $queue_burntool, $check_chips, $queue_chips);
 my ( $check_stacks, $queue_stacks, $check_diffs, $queue_diffs, $clean_old);
@@ -70,4 +70,5 @@
     'isburning'            => \$isburning,
     'force_stack_count'    => \$force_stack_count,
+    'check'                => \$check_mode,
     'test_mode'            => \$test_mode,
     'this_target_only=s'   => \$this_target_only,
@@ -116,5 +117,5 @@
     defined $queue_chips or defined $queue_stacks or
     defined $check_chips or defined $check_stacks or
-    defined $test_mode or defined $clean_old;
+    defined $test_mode or defined $clean_old or defined $check_mode;
 
 # Configurable parameters from our config file.
@@ -127,6 +128,7 @@
 my %stackable_list = ();
 my %reduction_class = ();
-my $retention_time = 9000;
-
+my %clean_commands = ();
+my %clean_retention = ();
+my %noclean_list = ();
 # Grab the configuration data.
 my $conf_cmd = "$ppConfigDump -dump-recipe NIGHTLY_SCIENCE -";
@@ -141,7 +143,22 @@
 my $metadata = $mdcParser->parse(join "", @$stdout_buf);
 foreach my $entry (@{ $metadata }) {
-    if (${ $entry }{name} eq 'RETENTION_TIME') {
-        $retention_time = ${ $entry }{value};
-    }
+    if (@{ $entry }{name} eq 'CLEAN_MODES') {
+	my @mode_data = @{ ${ $entry }{value} };
+	my $this_mode = '';
+	foreach my $mentry (@mode_data) {
+	    if (${ $mentry }{name} eq 'MODE') {
+		$this_mode = ${ $mentry }{value};
+	    }
+	    elsif (${ $mentry }{name} eq 'COMMAND') {
+		$clean_commands{$this_mode} = ${ $mentry }{value};
+	    }
+	    elsif (${ $mentry }{name} eq 'RETENTION_TIME') {
+		$clean_retention{$this_mode} = ${ $mentry }{value};
+	    }
+	}
+    }
+#    if (${ $entry }{name} eq 'RETENTION_TIME') {
+#        $retention_time = ${ $entry }{value};
+#    }
     elsif (${ $entry }{name} eq 'FILTERS') {
         push @filter_list, ${ $entry }{value};
@@ -173,4 +190,7 @@
 		$reduction_class{$this_target} = ${ $tentry }{value};
 	    }
+	    elsif (${ $tentry }{name} eq 'NOCLEAN') {
+		$noclean_list{$this_target} = ${ $tentry }{value};
+	    }
         }
     }
@@ -218,11 +238,22 @@
 if (defined($test_mode)) {
     $debug = 1;
-}
-
-if (defined($check_registration) || defined($test_mode)) {
+    my $z;
+    foreach $z (@target_list) {
+	print "TARGET: $z $tessID_list{$z} $obsmode_list{$z} $object_list{$z} $comment_list{$z} $stackable_list{$z} $reduction_class{$z}\n";
+    }
+    foreach $z (@filter_list) {
+	print "FILTER: $z\n";
+    }
+    foreach $z (keys (%clean_commands)) {
+	print "CLEAN: $z $clean_commands{$z} $clean_retention{$z}\n";
+    }
+    
+}
+
+if (defined($check_registration) || defined($test_mode) || defined($check_mode)) {
     $metadata_out{nsState} = 'NEW';
     my ($Nsummit_exp,$Nfaults) = check_summit_copy($date);
     return_metadata($date);
-    unless (defined($test_mode)) { exit(0); }
+    unless (defined($test_mode) || defined($check_mode)) { exit(0); }
 }
 if (defined($define_burntool) || defined($test_mode)) {
@@ -237,5 +268,5 @@
     unless (defined($test_mode)) { exit(0); }
 }
-if (defined($check_chips) || defined($test_mode)) {
+if (defined($check_chips) || defined($test_mode) || defined($check_mode)) {
     $metadata_out{nsState} = 'QUEUECHIPS';
     &execute_chips($date,"pretend");
@@ -244,5 +275,5 @@
     }
     return_metadata($date);
-    unless (defined($test_mode)) { exit(0); }
+    unless (defined($test_mode) || defined($check_mode)) { exit(0); }
 }
 if (defined($queue_chips)) {
@@ -252,5 +283,5 @@
     exit(0);
 }
-if (defined($check_stacks) || defined($test_mode)) {
+if (defined($check_stacks) || defined($test_mode) || defined($check_mode)) {
     $metadata_out{nsState} = 'TOWARP';
     &execute_stacks($date,"pretend");
@@ -259,10 +290,10 @@
     }
     return_metadata($date);
-    unless (defined($test_mode)) { exit(0); }
+    unless (defined($test_mode) || defined($check_mode)) { exit(0); }
 }
 if (defined($queue_stacks)) {
     $metadata_out{nsState} = 'STACKING';
     &execute_stacks($date);
-    if ($metadata_out{nsState} == 'QUEUESTACKING') {
+    if ($metadata_out{nsState} eq 'QUEUESTACKING') {
 	$metadata_out{nsState} = 'STACKING_POSSIBLE_ERROR';
     }
@@ -424,8 +455,8 @@
     }
 
-    if ($#{ $stderr_buf } > -1) {
-        $metadata_out{nsState} = 'ERROR';
-        return(1);
-    }
+#    if ($#{ $stderr_buf } > -1) {
+#        $metadata_out{nsState} = 'ERROR';
+#        return(1);
+#    }
 
     my $N = 0;
@@ -433,6 +464,9 @@
     foreach my $row (@burntool_entries) {
         my ($trash,$start,$end);
-        ($trash,$trash,$start,$end) = (split /\s+/,$row);
-
+        (undef,$trash,$start,$end) = (split /\s+/,$row);
+	if ($trash ne 'burntool') {
+	    $metadata_out{nsState} = 'ERROR';
+	    return(1);
+	}
         for (my $class_counter = 0; $class_counter < 60; $class_counter++) {
             $metadata_out{"bt${N}Begin"} = $start;
@@ -731,4 +765,8 @@
     my $date = shift;
     my $target = shift;
+    my $mode = shift;
+
+    my $command = $clean_commands{$mode};
+    my $retention_time = $clean_retention{$mode};
 
     my ($year,$month,$day) = split /-/,$date;
@@ -740,6 +778,6 @@
 
     my ($label,$workdir,$obs_mode,$object,$comment,$tess_id,$dist_group,$data_group,$reduction) = get_tool_parameters($cleaning_date,$target);
-
-    my $args .= " -dbname gpc1 -updaterun -set_state goto_cleaned -state full -data_group $data_group ";
+    my $args = $command;
+    $args .= " -dbname gpc1 -updaterun -set_state goto_cleaned -state full -set_label goto_cleaned -label $label -data_group $data_group ";
     if ($debug == 1) {
         $args .= ' -pretend ';
@@ -752,29 +790,22 @@
     my $pretend = shift;
 
-    foreach my $target (@target_list) {
-        my ($cleaning_date,$args) = construct_cleantool_args($date,$target);
-
-        my $command = $chiptool . $args;
-        print STDERR "$command\n";
-        if (!(defined($pretend) || $debug == 1)) {
+    foreach my $mode (keys (%clean_commands)) {
+	foreach my $target (@target_list) {
+	    if (exists($noclean_list{$target})) {
+		next;
+	    }
+	    my ($cleaning_date,$command) = construct_cleantool_args($date,$target,$mode);
+
+	    print STDERR "$command\n";
+	    if (!(defined($pretend) || $debug == 1)) {
 #           print STDERR "BEAR IS DRIVING!?\n";
-            my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-                run ( command => $command, verbose => $verbose );
-            unless ($success) {
-                $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-                &my_die("Unable to perform stacktool: $error_code", 0,0,$date, $PS_EXIT_SYS_ERROR);
-            }
-        }
-        $command = $warptool . $args;
-        print STDERR "$command\n";
-        if (!(defined($pretend) || $debug == 1)) {
-#           print STDERR "BEAR IS DRIVING $pretend $debug!?\n";
-            my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-                run ( command => $command, verbose => $verbose );
-            unless ($success) {
-                $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-                &my_die("Unable to perform stacktool: $error_code", 0,0,$date, $PS_EXIT_SYS_ERROR);
-            }
-        }
+		my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+		    run ( command => $command, verbose => $verbose );
+		unless ($success) {
+		    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+		    &my_die("Unable to perform stacktool: $error_code", 0,0,$date, $PS_EXIT_SYS_ERROR);
+		}
+	    }
+	}
     }
     return(0);
Index: branches/czw_branch/20100427/ippScripts/scripts/camera_exp.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/camera_exp.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/camera_exp.pl	(revision 28017)
@@ -280,4 +280,5 @@
         unless ($success) {
             $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	    print STDERR (join "\n", @$stderr_buf);
             &my_die("Unable to perform psastro: $error_code", $cam_id, $error_code);
         }
Index: branches/czw_branch/20100427/ippScripts/scripts/diff_skycell.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/diff_skycell.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/diff_skycell.pl	(revision 28017)
@@ -399,8 +399,8 @@
             $command .= " -hostname $host" if defined $host;
             $command .= " -path_base $outroot" if defined $outroot;
-            $command .= " -dbname $dbname" if defined $dbname;
         } else {
             $command .= " -updatediffskyfile";
         }
+        $command .= " -dbname $dbname" if defined $dbname;
         run(command => $command, verbose => $verbose);
     }
Index: branches/czw_branch/20100427/ippScripts/scripts/ipp_cleanup.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/ipp_cleanup.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/ipp_cleanup.pl	(revision 28017)
@@ -192,5 +192,5 @@
             # Tell magicdstool that we've cleaned up this data, so it needs to do the same if it needs to do the same.
             my $magicdstool = can_run('magicdstool') or die "Can't find magicdstool";
-            $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned";
+            $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned -set_label goto_cleaned";
             $command .= " -dbname $dbname" if defined $dbname;
             ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
@@ -309,5 +309,5 @@
         # Tell magicdstool that we've cleaned up this data, so it needs to do the same if it needs to do the same.
         my $magicdstool = can_run('magicdstool') or die "Can't find magicdstool";
-        $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned";
+        $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned -set_label goto_cleaned";
         $command .= " -dbname $dbname" if defined $dbname;
         ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
@@ -447,5 +447,5 @@
             # Tell magicdstool that we've cleaned up this data, so it needs to do the same if it needs to do the same.
             my $magicdstool = can_run('magicdstool') or die "Can't find magicdstool";
-            $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned";
+            $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned -set_label goto_cleaned";
             $command .= " -dbname $dbname" if defined $dbname;
             ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
@@ -581,5 +581,5 @@
             # Tell magicdstool that we've cleaned up this data, so it needs to do the same if it needs to do the same.
             my $magicdstool = can_run('magicdstool') or die "Can't find magicdstool";
-            $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned";
+            $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned -set_label goto_cleaned";
             $command .= " -dbname $dbname" if defined $dbname;
             ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
@@ -731,5 +731,5 @@
             # Tell magicdstool that we've cleaned up this data, so it needs to do the same if it needs to do the same.
             my $magicdstool = can_run('magicdstool') or die "Can't find magicdstool";
-            $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned";
+            $command = "$magicdstool -stage $stage -stage_id $stage_id -updaterun -set_state goto_cleaned -set_label goto_cleaned";
             $command .= " -dbname $dbname" if defined $dbname;
             ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
Index: branches/czw_branch/20100427/ippScripts/scripts/magic_destreak.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/magic_destreak.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/magic_destreak.pl	(revision 28017)
@@ -42,5 +42,5 @@
 # Parse the command-line arguments
 my ($magic_ds_id, $camera, $streaks, $inv_streaks, $exp_id, $stage, $stage_id, $component, $uri, $path_base, $cam_path_base, $cam_reduction);
-my ($outroot, $recoveryroot);
+my ($outroot, $recoveryroot, $magicked);
 my ($replace, $release);
 my ($dbname, $save_temps, $verbose, $no_update, $no_op, $logfile);
@@ -62,4 +62,5 @@
            'recoveryroot=s' => \$recoveryroot,# "directory" for saving the images of excised pixels
            'replace=s'      => \$replace,    # replace the input images with the results.
+           'magicked=s'     => \$magicked,   # magicked state of the run
            'release'        => \$release,    # NAN masked pixels for release
            'save-temps'     => \$save_temps, # Save temporary files?
@@ -72,5 +73,5 @@
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
-pod2usage( -msg => "Required options: --magic_ds_id --camera --streaks --stage --stage_id --component --uri --path_base --outroot",
+pod2usage( -msg => "Required options: --magic_ds_id --camera --streaks --stage --stage_id --component --uri --path_base --outroot --magicked",
            -exitval => 3) unless
     defined $magic_ds_id and
@@ -83,5 +84,6 @@
     defined $uri and
     defined $path_base and
-    defined $outroot;
+    defined $outroot and
+    defined $magicked;
 
 my $ipprc = PS::IPP::Config->new( $camera ) or my_die( "Unable to set up", $magic_ds_id, $component, $PS_EXIT_CONFIG_ERROR ); # IPP configuration
@@ -210,5 +212,4 @@
                     &my_die("Unable to parse metadata list", $magic_ds_id, $component, $PS_EXIT_PROG_ERROR);
 
-            $temp_dir = tempdir( CLEANUP => !$save_temps);
             ($sfh, $skycell_list) = tempfile( "/tmp/skycell_list.XXXX", UNLINK => !$save_temps);
 
@@ -219,4 +220,7 @@
                 } else {
                     # diff run must have been cleaned up, need to create this skycell file on the fly
+                    if (!defined $temp_dir ) {
+                        $temp_dir = tempdir( CLEANUP => !$save_temps);
+                    }
                     my $skycell_id = $skycell->{skycell_id};
                     $skycell_uri = "$temp_dir/$skycell_id";
@@ -248,5 +252,6 @@
             my $command = "$ppConfigDump -camera $camera -recipe PSASTRO $recipe_psastro -dump-recipe PSASTRO -";
             my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-                run(command => $command, verbose => $verbose);
+                    # note verbose == 0 to avoid polluting log files with almost always useless information
+                run(command => $command, verbose => 0);
             unless ($success) {
                 $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
@@ -267,5 +272,7 @@
         $astrom = $ipprc->filename("PSASTRO.OUTPUT", $cam_path_base);
 
-        if ($dynamicMasks) {
+        # if magicked is non-zero we are updating a previously magicked component. In this case we don't
+        # touch the camera mask
+        if (!$magicked and $dynamicMasks) {
             $mask = $ipprc->filename("PSASTRO.OUTPUT.MASK", $cam_path_base, $class_id);
             $ch_mask = $ipprc->filename("PPIMAGE.CHIP.MASK", $path_base, $class_id);
Index: branches/czw_branch/20100427/ippScripts/scripts/magic_destreak_cleanup.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/magic_destreak_cleanup.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/magic_destreak_cleanup.pl	(revision 28017)
@@ -63,13 +63,4 @@
 $ipprc->redirect_output($logfile) or my_die( "Unable to redirect output", $magic_ds_id, $PS_EXIT_SYS_ERROR ) if $logfile;
 
-if (0) {
-my $nebulousServer = metadataLookupStr( $ipprc->{_siteConfig}, 'NEB_SERVER' );
-&my_die("cannot find NEB_SERVER in site configuration", $magic_ds_id, $PS_EXIT_CONFIG_ERROR) if !$nebulousServer;
-
-my $nebulous = eval { Nebulous::Client->new( proxy => $nebulousServer ); };
-if ($@ or not defined $nebulous) {
-    &my_die ("Unable to create a Nebulous::Client object with proxy $nebulousServer", $magic_ds_id, $PS_EXIT_CONFIG_ERROR);
-}
-}
 
 $dbname = metadataLookupStr( $ipprc->{_siteConfig}, 'DBNAME' ) if !$dbname;
@@ -108,4 +99,7 @@
 
 
+&my_die("cleanup not supported for camera stage", $magic_ds_id, $PS_EXIT_PROG_ERROR) if $stage eq "camera";
+
+
 &my_die("unexpected run state found: $state", $magic_ds_id, $PS_EXIT_CONFIG_ERROR) if $state ne "goto_cleaned";
 &my_die("clean not allowed for raw stage, use goto_restore", $magic_ds_id, $PS_EXIT_CONFIG_ERROR) if $stage eq "raw";
@@ -130,4 +124,8 @@
 $dbh->disconnect() or warn $dbh->errstr;
 
+# We no longer clean up the camera stage mask files, but the code was left in place in case
+# we change our minds.
+my $cleanup_cam_mask = 0;
+
 my $dynamicMasks;               # Use dynamic masks?
 foreach my $comp (@components) {
@@ -140,5 +138,5 @@
         if ($stage eq "chip") {
             # Check to see if we're using dynamic masks
-            if (!defined $dynamicMasks) {
+            if ($cleanup_cam_mask && !defined $dynamicMasks) {
                 # Get the PSASTRO recipe
                 my $command = "$ppConfigDump -camera $camera -recipe PSASTRO $recipe_psastro -dump-recipe PSASTRO -";
Index: branches/czw_branch/20100427/ippScripts/scripts/magic_destreak_revert.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/magic_destreak_revert.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/magic_destreak_revert.pl	(revision 28017)
@@ -38,5 +38,5 @@
 
 # Parse the command-line arguments
-my ($magic_ds_id, $camera, $streaks, $stage, $stage_id, $component, $uri, $path_base, $bothways, $cam_path_base, $cam_reduction);
+my ($magic_ds_id, $camera, $streaks, $stage, $stage_id, $component, $uri, $path_base, $bothways, $cam_path_base, $cam_reduction, $magicked);
 my ($outroot, $recoveryroot, $replace, $release, $bytes, $md5sum);
 my ($dbname, $save_temps, $verbose, $no_update, $no_op, $logfile);
@@ -55,4 +55,5 @@
            'replace=s'      => \$replace,    # replace the input images with the results.
            'bothways=s'     => \$bothways,   # run has inverse files (bothways diff)
+           'magicked=s'     => \$magicked,   # magicked state of the run
            'save-temps'     => \$save_temps, # Save temporary files?
            'dbname=s'       => \$dbname,     # Database name
@@ -64,5 +65,5 @@
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
-pod2usage( -msg => "Required options: --magic_ds_id --camera --stage --stage_id --component --path_base --outroot",
+pod2usage( -msg => "Required options: --magic_ds_id --camera --stage --stage_id --component --path_base --outroot --magicked",
            -exitval => 3) unless
     defined $magic_ds_id and
@@ -72,4 +73,5 @@
     defined $component and
     defined $path_base and
+    defined $magicked and
     defined $outroot;
 
@@ -77,4 +79,6 @@
 
 &my_die("cam_path_base is required for chip stage", $magic_ds_id, $component, $PS_EXIT_CONFIG_ERROR) if ($stage eq 'chip' and !$cam_path_base);
+
+
 
 my $ipprc = PS::IPP::Config->new( $camera ) or my_die( "Unable to set up", $magic_ds_id, $component, $PS_EXIT_CONFIG_ERROR ); # IPP configuration
@@ -169,5 +173,6 @@
         my $command = "$ppConfigDump -camera $camera -recipe PSASTRO $recipe_psastro -dump-recipe PSASTRO -";
         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-            run(command => $command, verbose => $verbose);
+            # note verbose == 0 to keep from polluting log file with lots of usually useless information
+            run(command => $command, verbose => 0);
         unless ($success) {
             $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
@@ -182,10 +187,12 @@
     }
 
+    $image  = $ipprc->filename("PPIMAGE.CHIP", $path_base, $class_id);
+    $weight = $ipprc->filename("PPIMAGE.CHIP.VARIANCE", $path_base, $class_id);
+
     # we use the mask output from the camera stage for input and replace
     # the output of the chip stage with that mask as well.
-    $image  = $ipprc->filename("PPIMAGE.CHIP", $path_base, $class_id);
-    $weight = $ipprc->filename("PPIMAGE.CHIP.VARIANCE", $path_base, $class_id);
-
-    if ($dynamicMasks) {
+    # Note that when destreaking as part of an update $magicked is non-zero.
+    # In this case we do not touch the camera stage mask so there is no need to revert it
+    if (!$magicked and $dynamicMasks) {
         $mask = $ipprc->filename("PSASTRO.OUTPUT.MASK", $cam_path_base, $class_id);
         $ch_mask = $ipprc->filename("PPIMAGE.CHIP.MASK", $path_base, $class_id);
@@ -195,5 +202,5 @@
 
     $bimage  = $ipprc->filename("PPIMAGE.CHIP", $backup_path_base, $class_id);
-    # This is kludgey but correct
+    # This is somewhat kludgey but it works whether the mask is camera mask or chip mask
     $bmask   = dirname($backup_path_base) . "/SR_" . basename($mask);
     $bch_mask= $ipprc->filename("PPIMAGE.CHIP.MASK", $backup_path_base, $class_id);
Index: branches/czw_branch/20100427/ippScripts/scripts/magic_process.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/magic_process.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/magic_process.pl	(revision 28017)
@@ -99,13 +99,11 @@
     }
 
-    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+    $inputs = $mdcParser->parse_list(join "", @$stdout_buf) or
         &my_die("Unable to parse metadata config doc", $magic_id, $node, $PS_EXIT_PROG_ERROR);
-
-    $inputs = parse_md_list($metadata) or
-        &my_die("Unable to parse metadata list", $magic_id, $node, $PS_EXIT_PROG_ERROR);
 }
 
 
 my @outputs;
+my $inverse;                    # Using inverse diff?
 ### Do the heavy lifting
 {
@@ -263,4 +261,8 @@
                 cat_list_to_list($mfh, $in_path_base, "mask.list");
                 cat_list_to_list($wfh, $in_path_base, "weight.list");
+
+                if ($innode->{inverse}) {
+                    $inverse = 1;
+                }
             }
             close $in_fh;
@@ -330,4 +332,5 @@
     }
 }
+
 if ($node eq "root") {
     my $streaks_file = "$outroot.streaks";
@@ -348,21 +351,56 @@
     &run_verifystreaks($baseroot);
 
-    my $command = "$magictool -addmask";
-    $command   .= " -magic_id $magic_id";
-    $command   .= " -uri $streaks_file";
-    $command   .= " -streaks $num_streaks";
-    $command   .= " -dbname $dbname" if defined $dbname;
-
-    # Add the processed file to the database
-    unless ($no_update) {
+    my $exp_id;                 # Exposure identifier
+    my $cam_path;               # Camera stage path_base
+    {
+        my $command = "magictool -exposure -magic_id $magic_id";
+        $command .= " -inverse" if defined $inverse;
+        $command .= " -dbname $dbname" if defined $dbname;
         my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
             run(command => $command, verbose => $verbose);
-        unless ($success) {
-            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-            # This isn't going to work because our result was already entered.
-            &my_die("Unable to perform magictool -addmask: $error_code", $magic_id, $node, $error_code);
-        }
-    } else {
-        print "Skipping command: $command\n";
+        my $exposures = $mdcParser->parse_list(join "", @$stdout_buf);
+        my $exp = $$exposures[0]; # Exposure of interest (should only be one)
+
+        $exp_id = $exp->{exp_id};
+        $cam_path = $exp->{path_base};
+    }
+
+    {
+        my $astrom = $ipprc->filename("PSASTRO.OUTPUT", $cam_path); # Astrometry file
+        my $streaks = "$outroot.streaks";                           # Streaks file
+        my $clusters = "$baseroot.verify/${exp_id}_clusterPos.txt"; # Clusters file
+
+        my $command = "ppCoord -astrom $astrom -streaks $streaks";
+        if ($ipprc->file_exists($clusters)) {
+            $command .= " -clusters $clusters";
+        }
+
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        open my $coords, "> $outroot.coords";
+        print $coords join("", @$stdout_buf);
+        close $coords;
+    }
+
+
+    {
+        my $command = "$magictool -addmask";
+        $command   .= " -magic_id $magic_id";
+        $command   .= " -uri $streaks_file";
+        $command   .= " -streaks $num_streaks";
+        $command   .= " -dbname $dbname" if defined $dbname;
+
+        # Add the processed file to the database
+        unless ($no_update) {
+            my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+                run(command => $command, verbose => $verbose);
+            unless ($success) {
+                $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+                # This isn't going to work because our result was already entered.
+                &my_die("Unable to perform magictool -addmask: $error_code", $magic_id, $node, $error_code);
+            }
+        } else {
+            print "Skipping command: $command\n";
+        }
     }
 }
Index: branches/czw_branch/20100427/ippScripts/scripts/make_burntool_pcontrol.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/make_burntool_pcontrol.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/make_burntool_pcontrol.pl	(revision 28017)
@@ -1,8 +1,12 @@
-#!/usr/bin/perl -w
+#!/usr/bin/env perl 
 # script to generate a pcontrol.pro file to run burntool on a set of data.
 
 use DBI;
+use warnings;
 use DateTime;
 use Getopt::Std;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use PS::IPP::Config 1.01 qw( :standard );
+use IPC::Cmd 0.36 qw( can_run run);
 
 use constant DB_SOCKET => '/var/run/mysqld/mysqld.sock';
@@ -35,7 +39,11 @@
 		   ) or die "Unable to connect to database $DBI::errstr\n";
 
+my $ppConfigDump = can_run('ppConfigDump') or (warn "Can't find ppConfigDump" and $missing_tools = 1);
+if ($missing_tools) {
+    die "Cannot find required tools.";
+}
 # Determine what the value of "BURNTOOL.STATE.GOOD" currently is:
 $burntoolStateGood = 999;
-open(LAZY,"ppConfigDump -camera GPC1 -dump-camera - |") || die "Can't run ppConfigDump\n";
+open(LAZY,"$ppConfigDump -camera GPC1 -dump-camera - |") || die "Can't run ppConfigDump\n";
 while(<LAZY>) {
     chomp;
@@ -46,14 +54,54 @@
 }
 close(LAZY);
-#unless( $burntoolStateGood == 999) {
-#    print STDERR "GOOD == $burntoolStateGood\n";
-#}
-
-
-# List of which obs_modes are "science" and which are something else.
-%science = ('MD' => 1, '3PI' => 1, 'STS' => 1, 'CAL' => 1, 'M31' => 1, 'SS' => 1,
-	    'ENGINEERING' => 0, 'NULL' => 0, 'Unknown' => 1, ' ' => 0);
+
+# Read the nightly science config file and use that to determine which data is science
+my $verbose = 0;
+my $conf_cmd = "$ppConfigDump -dump-recipe NIGHTLY_SCIENCE -";
+my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+    run(command => $conf_cmd, verbose => $verbose);
+unless ($success) {
+    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+    &my_die("Unable to perform ppConfigDUmp: $error_code", $date, $PS_EXIT_SYS_ERROR);
+}
+
+my @target_list;
+my %object_list;
+my $comment_list;
+
+my $mdcParser = PS::IPP::Metadata::Config->new;
+my $metadata = $mdcParser->parse(join "", @$stdout_buf);
+foreach my $entry (@{ $metadata }) {
+    if (${ $entry }{name} eq 'TARGETS') {
+        my @target_data = @{ ${ $entry }{value} };
+        my $this_target = '';
+	
+        foreach my $tentry (@target_data) {
+            if (${ $tentry }{name} eq 'NAME') {
+                $this_target = ${ $tentry }{value};
+                push @target_list, $this_target;
+		$obsmode_list{$this_target} = '.*';
+		$object_list{$this_target} = '.*';
+		$comment_list{$this_target} = '.*';
+            }
+            elsif (${ $tentry }{name} eq 'OBSMODE') {
+                $obsmode_list{$this_target} = ${ $tentry }{value};
+		$obsmode_list{$this_target} =~ s/%//;
+            }
+            elsif (${ $tentry }{name} eq 'OBJECT') {
+                $object_list{$this_target} = ${ $tentry }{value};
+		$object_list{$this_target} =~ s/%//;
+            }
+            elsif (${ $tentry }{name} eq 'COMMENT') {
+                $comment_list{$this_target} = ${ $tentry }{value};
+		$comment_list{$this_target} =~ s/%//;
+            }
+	}
+    }
+}
 if (exists($opt{P})) {
-    $science{Unknown} = 1;
+    push @target_list, 'PR';
+    $obsmode_list{'PR'} = 'Unknown';
+    $object_list{'PR'} = '.*';
+    $comment_list{'PR'} = '.*';
 }
 
@@ -119,5 +167,5 @@
     
     # Find _ALL_ observations within the date range we care about
-    $sth = "SELECT exp_id,dateobs,pon_time,exp_type,obs_mode,comment FROM rawExp WHERE " .
+    $sth = "SELECT exp_id,dateobs,pon_time,exp_type,obs_mode,comment,object FROM rawExp WHERE " .
 	"dateobs >= '${date_min}' AND dateobs <= '${date_max}' order by dateobs";
 
@@ -133,9 +181,12 @@
     foreach $row_ref (@{ $data_ref }) {
 
-	($exp_id,$dateobs,$pontime,$exp_type,$obs_mode,$comment) = @{ $row_ref };
+	($exp_id,$dateobs,$pontime,$exp_type,$obs_mode,$comment,$object) = @{ $row_ref };
 	# Fix nulls in the database
 	if (!defined($obs_mode)) {
 	    $obs_mode = ' ';
 	}
+	if (!defined($object)) {
+	    $object = ' ';
+	}
 	if (!defined($comment)) {
 	    $comment = ' ';
@@ -144,5 +195,5 @@
 	($date,$time) = split / /, $dateobs;
 	($year,$month,$day) = split /-/, $date;
-	($hour,$minute,$second) = split /:/, $time;
+	($hour,$minute,$second) = split /:/, $time; # / # This stops emacs run-on syntax highlights.
 	
 	$dt = DateTime->new( year   => $year, month  => $month, day    => $day,
@@ -155,16 +206,5 @@
 	$et = $dt->epoch();
 
-
-	if (!exists($science{$obs_mode})) {
-	    $science{$obs_mode} = 0;
-	}
-	if ((($science{$obs_mode} == 1)&&($comment !~ /Daytime/))||
-	    (($science{$obs_mode} == 0)&&(
-					  ($comment =~ /MD/)||($comment =~ /ThreePi/)||
-					  ($comment =~ /STS/i)||($comment =~ /M31/)||($comment =~ /Stellar Transit/)||
-					  ($comment =~ /CAL/i)||($comment =~ /SS/)||($comment =~ /SVS/)||
-					  ($comment =~ /Sweetspot/)||($comment =~ /virgo/i)||($comment =~ /kepler/)||
-					  ($comment =~ /sdss/))))					  
-	{
+	if (is_science($exp_type,$obs_mode,$object,$comment)) {
 	    if ($start_s[-1] == 0) {
 		$start_s[-1] = $et - 1800;
@@ -194,5 +234,5 @@
     # Scan again and count how many exposures are between windows
     foreach $row_ref (@{ $data_ref }) {
-	($exp_id,$dateobs,$pontime,$exp_type,$obs_mode,$comment) = @{ $row_ref };
+	($exp_id,$dateobs,$pontime,$exp_type,$obs_mode,$comment,$object) = @{ $row_ref };
 	if (!defined($obs_mode)) {
 	    $obs_mode = ' ';
@@ -204,5 +244,5 @@
 	($date,$time) = split / /, $dateobs;
 	($year,$month,$day) = split /-/, $date;
-	($hour,$minute,$second) = split /:/, $time;
+	($hour,$minute,$second) = split /:/, $time; # / # another emacs syntax highlight bug.
 	
 	$dt = DateTime->new( year   => $year, month  => $month, day    => $day,
@@ -215,10 +255,6 @@
 	$et = $dt->epoch();
 
-	if (!exists($science{$obs_mode})) {
-	    die "No mode >>$obs_mode<<\n";
-	}
-	
 	for ($i = 0; $i <= $#start_s; $i++) {
-	    if (($et < $start_s[$i])&&($science{$obs_mode} == 0)) {
+	    if (($et < $start_s[$i])&&(is_science($exp_type,$obs_mode,$object,$comment) == 0)) {
 		if ($i == 0) {
 		    $skips[$i]++;
@@ -278,4 +314,30 @@
 unless(exists($opt{b}) || ($N_ranges == 0)) {
     print_epilogue();
+}
+
+
+# Subroutine to use the configuration file data and the exposure data to determine whether or not something is "science"
+sub is_science {
+#    if (is_science($exp_type,$obs_mode,$object,$comment)) {
+    my ($exp_type,$obs_mode,$object,$comment) = @_;
+    my $return_value = 0;
+    unless($object) {
+	$object = '';
+    }
+    if ($exp_type eq 'OBJECT') {
+	foreach my $target (@target_list) {
+#	    print STDERR "$target $obsmode_list{$target} $exp_type $obs_mode $object $comment\n";
+	    if (($obs_mode =~ /$obsmode_list{$target}/)&&
+		($object   =~ /$object_list{$target}/)&&
+		($comment  =~ /$comment_list{$target}/)) {
+		$return_value = 1;
+	    }
+#	    print ">$return_value $exp_type $obs_mode $object $comment $target $obsmode_list{$target} $object_list{$target} $comment_list{$target}\n";
+	    if ($return_value) {
+		return($return_value);
+	    }
+	}
+    }
+    return(0);
 }
 
Index: branches/czw_branch/20100427/ippScripts/scripts/receive_advance.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/receive_advance.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/receive_advance.pl	(revision 28017)
@@ -60,7 +60,6 @@
     &my_die( "Unable to set up", $fileset_id, $PS_EXIT_CONFIG_ERROR ); # IPP configuration
 
-# update the fileset entry
-
-if ($dbinfo_uri and ($dbinfo_uri ne "NULL")) {
+my $import_run_to_db = 0;
+if ($import_run_to_db and $dbinfo_uri and ($dbinfo_uri ne "NULL")) {
     my $filename = basename($dbinfo_uri);
     my ($stage) = $filename =~ m|^dbinfo\.(\S+)\.\d+\.mdc$|; # Stage of interest
@@ -102,4 +101,5 @@
 }
 
+# update the fileset entry
 # All done
 {
Index: branches/czw_branch/20100427/ippScripts/scripts/register_exp.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/register_exp.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/register_exp.pl	(revision 28017)
@@ -127,4 +127,5 @@
 $command .= " -end_stage $end_stage" if defined $end_stage;
 $command .= " -tess_id   $tess_id"   if defined $tess_id;
+$command .= " -state full";
 $command .= " $cmdflags";
 
Index: branches/czw_branch/20100427/ippScripts/scripts/register_imfile.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/register_imfile.pl	(revision 27784)
+++ branches/czw_branch/20100427/ippScripts/scripts/register_imfile.pl	(revision 28017)
@@ -174,4 +174,5 @@
 $command .= " -hostname $host" if defined $host;
 $command .= " -dbname $dbname" if defined $dbname;
+$command .= " -data_state full";
 $command .= " $cmdflags";
 
Index: branches/czw_branch/20100427/ippScripts/scripts/staticsky.pl
===================================================================
--- branches/czw_branch/20100427/ippScripts/scripts/staticsky.pl	(revision 28017)
+++ branches/czw_branch/20100427/ippScripts/scripts/staticsky.pl	(revision 28017)
@@ -0,0 +1,324 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+## report the program and machine
+use Sys::Hostname;
+my $host = hostname();
+my $date = `date`;
+print "\n\n";
+print "Starting script $0 on $host at $date\n\n";
+
+use DateTime;
+my $mjd_start = DateTime->now->mjd;   # MJD of starting script
+
+use vars qw( $VERSION );
+$VERSION = '0.01';
+
+use IPC::Cmd 0.36 qw( can_run run );
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
+use Data::Dumper;
+use PS::IPP::Config 1.01 qw( :standard );
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+
+# Look for programs we need
+my $missing_tools;
+my $staticskytool = can_run('staticskytool') or (warn "Can't find staticskytool" and $missing_tools = 1);
+my $ppSub = can_run('ppSub') or (warn "Can't find ppSub" and $missing_tools = 1);
+my $ppStatsFromMetadata = can_run('ppStatsFromMetadata') or (warn "Can't find ppStatsFromMetadata" and $missing_tools = 1);
+if ($missing_tools) {
+    warn("Can't find required tools.");
+    exit($PS_EXIT_CONFIG_ERROR);
+}
+
+my ($sky_id, $dbname, $threads, $outroot, $reduction, $inverse, $run_state, $verbose, $no_update, $no_op, $redirect, $save_temps);
+GetOptions(
+    'sky_id=s'          => \$sky_id, # Diff identifier
+    'dbname|d=s'        => \$dbname, # Database name
+    'threads=s'         => \$threads,   # Number of threads to use
+    'run-state=s'       => \$run_state,   # state for run: 'new' or 'update'
+    'outroot=s'         => \$outroot, # Output root name
+    'reduction=s'       => \$reduction, # Reduction class
+    'verbose'           => \$verbose,   # Print to stdout
+    'no-update'         => \$no_update, # Don't update the database?
+    'no-op'             => \$no_op, # Don't do any operations?
+    'redirect-output'   => \$redirect,
+    'save-temps'        => \$save_temps, # Save temporary files?
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --sky_id --outroot",
+    -exitval => 3,
+          ) unless 
+    defined $sky_id and
+    defined $outroot;
+
+my $ipprc = PS::IPP::Config->new() or my_die( "Unable to set up", $sky_id, $PS_EXIT_CONFIG_ERROR ); # IPP configuration
+
+# XXX camera is not known here; cannot use filerules...
+# my $logDest = $ipprc->filename("LOG.EXP", $outroot);
+my $logDest = "$outroot.log";
+$logDest .= ".update" if $run_state eq "update";
+$ipprc->redirect_output($logDest) or my_die( "Unable to redirect output", $sky_id, $PS_EXIT_SYS_ERROR ) if $redirect;
+
+my $source_id = $ipprc->source_id($dbname, $PS_TABLE_ID_DIFF);
+
+my $outbase = basename($outroot);
+my ($listFile, $listName) = tempfile("/tmp/$outbase.list.XXXX", UNLINK => !$save_temps );
+
+# Get list of input images to stack photometry
+my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
+my $files;
+{
+    my $command = "$staticskytool -inputs -sky_id $sky_id";
+    $command .= " -dbname $dbname" if defined $dbname;
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        &my_die("Unable to perform difftool -inputskyfile: $error_code", $sky_id, $error_code);
+    }
+
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", $sky_id, $PS_EXIT_PROG_ERROR);
+    $files = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", $sky_id, $PS_EXIT_PROG_ERROR);
+}
+
+# XXX do we NEED to define the camera?
+# &my_die("Unable to identify camera", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless defined $camera;
+# $ipprc->define_camera($camera);
+
+# generate the input 
+print $listFile "INPUT   MULTI\n";
+
+foreach my $file (@$files) {
+    print $listFile "INPUT   METADATA\n";
+
+    $path_base = $file->{path_base};
+    my $imageCnv  = $ipprc->filename("PPSTACK.OUTPUT", $file->{path_base} ); # Mask name
+    my $maskCnv   = $ipprc->filename("PPSTACK.OUTPUT.MASK", $file->{path_base} ); # Mask name
+    my $weightCnv = $ipprc->filename("PPSTACK.OUTPUT.VARIANCE", $file->{path_base} ); # Weight name
+    my $psfCnv    = $ipprc->filename("PSPHOT.PSF.SKY.SAVE", $file->{path_base} ); # PSF name
+
+    my $imageRaw  = $ipprc->filename("PPSTACK.UNCONV", $file->{path_base} ); # Mask name
+    my $maskRaw   = $ipprc->filename("PPSTACK.UNCONV.MASK", $file->{path_base} ); # Mask name
+    my $weightRaw = $ipprc->filename("PPSTACK.UNCONV.VARIANCE", $file->{path_base} ); # Weight name
+
+    my $sources   = $ipprc->filename("PSPHOT.OUT.CMF.MEF", $file->{path_base}); # Sources name
+
+    &my_die("Image $image does not exist", $stack_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $image );
+    &my_die("Mask $mask does not exist", $stack_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $mask );
+    &my_die("Weight $weight does not exist", $stack_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $weight );
+    &my_die("PSF $psf does not exist", $stack_id, $PS_EXIT_SYS_ERROR) if ($convolve and not $ipprc->file_exists( $psf ));
+    &my_die("Sources $sources does not exist", $stack_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $sources );
+
+    print $listFile "  RAW:IMAGE     STR  " . $imageRaw  . "\n";
+    print $listFile "  RAW:MASK      STR  " . $maskRaw   . "\n";
+    print $listFile "  RAW:VARIANCE  STR  " . $weightRaw . "\n";
+
+    print $listFile "  CNV:IMAGE     STR  " . $imageCnv  . "\n";
+    print $listFile "  CNV:MASK      STR  " . $maskCnv   . "\n";
+    print $listFile "  CNV:VARIANCE  STR  " . $weightCnv . "\n";
+    print $listFile "  CNV:PSF       STR  " . $psfCnv    . "\n";
+
+    print $listFile "  SOURCES       STR  " . $sources   . "\n";
+
+    print $listFile "END\n\n";
+
+    &my_die("Couldn't find input: $imageRaw",  $sky_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists("$imageRaw");
+    &my_die("Couldn't find input: $maskRaw",   $sky_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists("$maskRaw");
+    &my_die("Couldn't find input: $weightRaw", $sky_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists("$weightRaw");
+    &my_die("Couldn't find input: $imageCnv",  $sky_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists("$imageCnv");
+    &my_die("Couldn't find input: $maskCnv",   $sky_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists("$maskCnv");
+    &my_die("Couldn't find input: $weightCnv", $sky_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists("$weightCnv");
+    &my_die("Couldn't find input: $psfCnv",    $sky_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists("$psfCnv");
+    &my_die("Couldn't find input: $sources",   $sky_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists("$sources");
+}
+
+# Recipes to use based on reduction class
+$reduction = 'DEFAULT' unless defined $reduction;
+my $recipe_psphot  = $ipprc->reduction($reduction, 'STACKPHOT'); # Recipe to use for psphot
+unless ($recipe_psphot) {
+    &my_die("Couldn't find selected reduction for STACKPHOT: $reduction\n", $sky_id, $PS_EXIT_CONFIG_ERROR);
+}
+
+print "reduction: $reduction\n";
+print "recipe_psphot: $recipe_psphot\n";
+
+# Get the output filenames
+my $outputName = $ipprc->filename("PPSUB.OUTPUT", $outroot);
+my $outputMask = $ipprc->filename("PPSUB.OUTPUT.MASK", $outroot);
+my $outputVariance = $ipprc->filename("PPSUB.OUTPUT.VARIANCE", $outroot);
+my $outputSources = $ipprc->filename("PPSUB.OUTPUT.SOURCES", $outroot);
+my $jpeg1Name = $ipprc->filename("PPSUB.OUTPUT.JPEG1", $outroot);
+my $jpeg2Name = $ipprc->filename("PPSUB.OUTPUT.JPEG2", $outroot);
+my $configuration = $ipprc->filename("PPSUB.CONFIG", $outroot);
+my $outputStats = $ipprc->filename("SKYCELL.STATS", $outroot);
+my $traceDest = $ipprc->filename("TRACE.EXP", $outroot);
+
+if ($run_state eq 'update') {
+    $traceDest .= '.update';
+    $outputStats .= '.update';
+}
+
+my ($inverseName, $inverseMask, $inverseVariance, $inverseSources);
+if ($inverse) {
+    $inverseName = $ipprc->filename("PPSUB.INVERSE", $outroot);
+    $inverseMask = $ipprc->filename("PPSUB.INVERSE.MASK", $outroot);
+    $inverseVariance = $ipprc->filename("PPSUB.INVERSE.VARIANCE", $outroot);
+    $inverseSources = $ipprc->filename("PPSUB.INVERSE.SOURCES", $outroot);
+}
+
+my $cmdflags;
+
+# Perform subtraction
+{
+    my $command = "$ppSub $outroot";
+    $command .= " -inimage $input";
+    $command .= " -refimage $template";
+    $command .= " -inmask $inputMask";
+    $command .= " -refmask $templateMask";
+    $command .= " -invariance $inputVariance";
+    $command .= " -refvariance $templateVariance";
+    $command .= " -insources $inputSources";
+    $command .= " -refsources $templateSources";
+    $command .= " -stats $outputStats";
+    $command .= " -threads $threads" if defined $threads;
+    if ($run_state eq "new") {
+        $command .= " -dumpconfig $configuration";
+    } else {
+        my $configurationReal = $ipprc->file_resolve($configuration) or &my_die("Couldn't resolve configuration file: $configuration", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR);
+        $command .= " -ipprc $configurationReal";
+    }
+    $command .= " -save-inconv" if defined $saveInConv;
+    $command .= " -save-refconv" if defined $saveRefConv;
+    $command .= " -recipe PPSUB $recipe_ppSub";
+    $command .= " -recipe PSPHOT $recipe_psphot";
+    $command .= " -recipe PPSTATS WARPSTATS";
+    $command .= " -F PSPHOT.PSF.SAVE PSPHOT.PSF.SKY.SAVE";
+    $command .= " -F PSPHOT.OUTPUT PSPHOT.OUT.CMF.MEF";
+    $command .= " -F PSPHOT.BACKMDL PSPHOT.BACKMDL.MEF";
+    if ($run_state eq "new") {
+        $command .= " -photometry";
+    }
+    $command .= " -inverse" if $inverse;
+    $command .= " -tracedest $traceDest -log $logDest";
+    $command .= " -dbname $dbname" if defined $dbname;
+    $command .= " -image_id $diff_skyfile_id" if defined $diff_skyfile_id;
+    $command .= " -source_id $source_id" if defined $source_id;
+
+    unless ($no_op) {
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform ppSub: $error_code", $sky_id, $skycell_id, $error_code);
+        }
+
+        my $outputStatsReal = $ipprc->file_resolve($outputStats);
+        &my_die("Couldn't find expected output file: $outputStats", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($outputStatsReal);
+
+        # measure chip stats
+        $command = "$ppStatsFromMetadata $outputStatsReal - DIFF_SKYCELL";
+        ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform ppStatsFromMetadata: $error_code", $sky_id, $skycell_id, $error_code);
+        }
+        foreach my $line (@$stdout_buf) {
+            $cmdflags .= " $line";
+        }
+        chomp $cmdflags;
+
+        my ($quality) = $cmdflags =~ /-quality (\d+)/; # Quality flag
+
+        if (!$quality) {
+            &my_die("Couldn't find expected output file: $outputName", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($outputName);
+            &my_die("Couldn't find expected output file: $outputMask", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($outputMask);
+            &my_die("Couldn't find expected output file: $outputVariance", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($outputVariance);
+            &my_die("Couldn't find expected output file: $outputSources", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($outputSources);
+            &my_die("Couldn't find expected output file: $jpeg1Name",    $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($jpeg1Name);
+            &my_die("Couldn't find expected output file: $jpeg2Name",    $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($jpeg2Name);
+            if ($inverse) {
+                &my_die("Couldn't find expected output file: $inverseName", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($inverseName);
+                &my_die("Couldn't find expected output file: $inverseMask", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($inverseMask);
+                &my_die("Couldn't find expected output file: $inverseVariance", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($inverseVariance);
+                &my_die("Couldn't find expected output file: $inverseSources", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($inverseSources);
+                if ($run_state eq 'new') {
+                    &my_die("Couldn't find expected output file: $configuration", $sky_id, $skycell_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($configuration);
+                }
+            }
+        }
+    } else {
+        print "Not executing: $command\n";
+    }
+}
+
+unless ($no_update) {
+
+    # Add the subtraction result
+    {
+        my $command = "$difftool -sky_id $sky_id -skycell_id $skycell_id";
+        $command .= " -magicked $magicked" if $magicked;
+        if ($run_state eq 'new') {
+            $command .= " -adddiffskyfile -path_base $outroot";
+            $command .= " $cmdflags";
+            $command .= (" -dtime_script " . ((DateTime->now->mjd - $mjd_start) * 86400));
+            $command .= " -hostname $host" if defined $host;
+        } else {
+            $command .= " -tofullskyfile";
+        }
+        $command .= " -dbname $dbname" if defined $dbname;
+
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            my $err_message = $run_state eq "update" ?
+                "Unable to perform difftool -adddiffskyfile" :
+                "Unable to perform difftool -tofullskyfile";
+            &my_die("$err_message: $error_code", $sky_id, $skycell_id, $error_code);
+        }
+    }
+}
+
+
+sub my_die
+{
+    my $msg = shift;            # Warning message on die
+    my $sky_id = shift;        # Diff identifier
+    my $exit_code = shift;      # Exit code to add
+
+    $exit_code = $PS_EXIT_PROG_ERROR unless defined $exit_code;
+
+    warn($msg);
+    if (defined $sky_id and defined $skycell_id and not $no_update) {
+        my $command = "$difftool -sky_id $sky_id -skycell_id $skycell_id -fault $exit_code";
+        if ($run_state eq 'new') {
+            $command .= " -adddiffskyfile";
+            $command .= (" -dtime_script " . ((DateTime->now->mjd - $mjd_start) * 86400));
+            $command .= " -hostname $host" if defined $host;
+            $command .= " -path_base $outroot" if defined $outroot;
+            $command .= " -dbname $dbname" if defined $dbname;
+        } else {
+            $command .= " -updatediffskyfile";
+        }
+        run(command => $command, verbose => $verbose);
+    }
+    exit $exit_code;
+}
+
+END {
+    my $exit = $?;
+    system("sync") == 0 or die "failed to execute sync: $!";
+    $? = $exit;
+}
+
+__END__
