Index: branches/eam_branches/20090820/DataStore/Build.PL
===================================================================
--- branches/eam_branches/20090820/DataStore/Build.PL	(revision 25206)
+++ branches/eam_branches/20090820/DataStore/Build.PL	(revision 25766)
@@ -33,4 +33,5 @@
     script_files        => [qw(
         scripts/dsget
+        scripts/dsgetfileset
         scripts/dsproductls
         scripts/dsleech
Index: branches/eam_branches/20090820/DataStore/lib/DataStore/Utils.pm
===================================================================
--- branches/eam_branches/20090820/DataStore/lib/DataStore/Utils.pm	(revision 25206)
+++ branches/eam_branches/20090820/DataStore/lib/DataStore/Utils.pm	(revision 25766)
@@ -42,7 +42,7 @@
 $BYTE_FIELD = qr/^\d+$/;
 $MD5_FIELD = qr/^[0-9a-f]{32}$/;
-%KNOWN_FILE_TYPES = map { $_ => 1 } qw( chip psrequest psresults pstamp chipproc warp stack diff ipp-mops table text xml tgz);
-%KNOWN_FILESET_TYPES = map { $_ => 1 } qw( OBJECT BIAS DARK SKYFLAT DOMEFLAT OOF SHACKHARTMANN PSREQUEST PSRESULTS IPP-MOPS XRAY FOCUS MOPS_DETECTABILITY_QUERY MOPS_DETECTABILITY_RESPONSE MOPS_TRANSIENT_DETECTIONS LED notset IPP_PSPS);
-%KNOWN_PRODUCT_TYPES = map { $_ => 1 } qw( image dump psrequest psresults table );
+%KNOWN_FILE_TYPES = map { $_ => 1 } qw( chip psrequest psresults pstamp chipproc warp stack diff ipp-mops table text xml tgz fits );
+%KNOWN_FILESET_TYPES = map { $_ => 1 } qw( OBJECT BIAS DARK SKYFLAT DOMEFLAT OOF SHACKHARTMANN PSREQUEST PSRESULTS IPP-MOPS XRAY FOCUS MOPS_DETECTABILITY_QUERY MOPS_DETECTABILITY_RESPONSE MOPS_TRANSIENT_DETECTIONS LED notset IPP_PSPS IPP-DIST);
+%KNOWN_PRODUCT_TYPES = map { $_ => 1 } qw( image dump psrequest psresults table ipp-dist ipp-misc);
 
 =pod
Index: branches/eam_branches/20090820/DataStore/scripts/dsget
===================================================================
--- branches/eam_branches/20090820/DataStore/scripts/dsget	(revision 25206)
+++ branches/eam_branches/20090820/DataStore/scripts/dsget	(revision 25766)
@@ -69,5 +69,5 @@
         undef $copies;
     }
-    if ($copies < 1) {
+    elsif ($copies < 1) {
         die "--copies must be >= 1";
     }
@@ -207,5 +207,5 @@
     if (defined $copies and $copies > 1) {
         foreach (1 .. ($copies - 1)) {
-            $neb->replicate($filename, 'any')
+            $neb->replicate($filename)
                 or die "failed to replicate $filename failed: $!";
         }
@@ -214,4 +214,7 @@
     $tmp->flush or die "can't flush filehandle: $!";
     $tmp->sync or die "can't sync filehandle: $!";
+    # set read and write permissions based on umask (ignore other bits)
+    my $umask = umask;
+    chmod 0666 ^ $umask, $tmpfilename or die "failed to chmod $tmpfilename";
     rename $tmpfilename, $filename
         or die "renaming $tmpfilename to $filename failed: $!";
Index: branches/eam_branches/20090820/DataStore/scripts/dsgetfileset
===================================================================
--- branches/eam_branches/20090820/DataStore/scripts/dsgetfileset	(revision 25766)
+++ branches/eam_branches/20090820/DataStore/scripts/dsgetfileset	(revision 25766)
@@ -0,0 +1,157 @@
+#!/usr/bin/env perl
+
+# Copyright (C) 2006-2009  Institute for Astromony University of Hawaii
+#
+# dsgetfileset
+
+use strict;
+use warnings FATAL => qw( all );
+
+use vars qw( $VERSION );
+$VERSION = '0.02';
+
+use DataStore;
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+use File::Basename qw( basename );
+
+my ($uri, $outdir, $timeout, $verbose);
+
+GetOptions(
+    'uri|u=s'           => \$uri,
+    'outdir|o=s'        => \$outdir,
+    'timeout|t=s'       => \$timeout,
+    'verbose|v'         => \$verbose,
+) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+    -msg => "Required options: --uri --outdir",
+    -exitval => 3,
+) unless defined $uri and defined $outdir;
+
+# default http request timeout is 30s
+$timeout ||= 30;
+
+my $response = DataStore::FileSet->new( uri => $uri )->request(
+        ua_args  => { timeout => $timeout },
+    );
+
+unless (defined $response and $response->is_success) {
+    warn "request failed: ", $response->status_line;
+    exit($response->code - 300);
+}
+
+# file retreival succeed
+
+my $data = $response->data;
+
+unless ($data) {
+    warn "no files found";
+    exit(0);
+}
+
+print "# uri fileid bytes md5sum type \n";
+foreach my $fs (@$data) {
+    if ($verbose) {
+        print 
+            $fs->uri, " ",
+            $fs->fileid, " ",
+            $fs->bytes, " ",
+            $fs->md5sum || 0, " ",
+            $fs->type;
+        print " ", join(" ", @{$fs->extra}) if defined $fs->extra;   
+        print "\n";
+    }
+
+    my $uri = $fs->uri;
+    my $base = basename($uri);
+    my $outfile = "$outdir/$base";
+    my $md5 = $fs->md5sum;
+    my $bytes = $fs->bytes;
+
+    my $command = "dsget --uri $uri --filename $outfile --md5 $md5 --bytes $bytes --timeout $timeout";
+    print "$command\n" if $verbose;
+    my $rc = system $command;
+    if ($rc) {
+        my $status = $rc >> 8;
+        print STDERR "dsget failed: rc: $rc status: $status\n";
+        exit $status;
+    }
+}
+
+__END__
+
+=pod
+
+=head1 NAME
+
+dsgetfilset - download all the Files under a FileSet from a DataStore server
+
+=head1 SYNOPSIS
+
+    dsgetfileset --uri <uri>  --outdir <output_directory>
+
+=head1 DESCRIPTION
+
+Download the contents of the Data Store Fileset at the supplied uri to a local directory.
+
+=head1 OPTIONS
+
+=over 4
+
+=item * --uri|-u <uri>
+
+The URI of the file to be retrieved.
+
+=item * --outdir|-o <uri>
+
+The output destination directory.
+
+=item * --timeout|-t
+
+The amount of time (in seconds) to wait for a response from the DataStore
+after making an HTTP request.  The default is 30s.
+
+Optional.
+
+=back
+
+=head1 CREDITS
+
+Based on the DataStore modules and scripts by Joshua Hoblitt
+
+=head1 SUPPORT
+
+None.
+
+=head1 AUTHOR
+
+The IPP Team
+
+=head1 COPYRIGHT
+
+Copyright (C) 2006-2009  Institute for Astromony University of Hawaii
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; either version 2 of the License, or (at your option) any later
+version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place - Suite 330, Boston, MA  02111-1307, USA.
+
+The full text of the license can be found in the L<perlgpl> Pod as supplied
+with Perl 5.8.1 and later.
+
+=head1 SEE ALSO
+
+L<dsget>, L<dsleech>, L<dsrootls>, L<dsproductls>, L<dsfilesetls>, L<DataStore>
+
+=cut
Index: branches/eam_branches/20090820/DataStoreServer/scripts/dsfsindex
===================================================================
--- branches/eam_branches/20090820/DataStoreServer/scripts/dsfsindex	(revision 25206)
+++ branches/eam_branches/20090820/DataStoreServer/scripts/dsfsindex	(revision 25766)
@@ -60,5 +60,5 @@
 my $header = "# fileID          |bytes   |md5sum                          |type        |";
 
-$stmt = $dbh->prepare("SELECT * from dsFile WHERE fileset_id = $fs_id");
+$stmt = $dbh->prepare("SELECT * from dsFile WHERE fileset_id = $fs_id ORDER BY file_id");
 $stmt->execute();
 
Index: branches/eam_branches/20090820/DataStoreServer/scripts/dsprodtool
===================================================================
--- branches/eam_branches/20090820/DataStoreServer/scripts/dsprodtool	(revision 25206)
+++ branches/eam_branches/20090820/DataStoreServer/scripts/dsprodtool	(revision 25766)
@@ -12,4 +12,6 @@
 use PS::IPP::Metadata::Config;
 use File::Copy;
+
+use Term::ReadKey;
 
 use PS::IPP::Config qw($PS_EXIT_SUCCESS
@@ -36,4 +38,5 @@
 my $dsroot;
 my $dbname;
+my $dbpass;
 
 my $add;
@@ -78,4 +81,23 @@
 } else {
     $product = $del;
+    if (! -t STDIN) {
+        die "cannot delete product from script\n";
+    }
+    print "*** Delete the Data Store Product $product? ***\n";
+    print "*** to delete $product answer YES, and give password ***\n";
+    print "*** WARNING this action is permanant *** \n";
+    print "Delete? (YES/[n]): ";
+
+    my $line = ReadLine(0);
+    chomp $line;
+    exit 1 if !$line or ($line ne "YES");
+
+    print "password: ";
+    ReadMode('noecho');
+    $line = ReadLine(0);
+    ReadMode('normal');
+    print "\n";
+    chomp $line;
+    $dbpass = $line;
 }
 
@@ -93,5 +115,5 @@
 }
 
-my $root_index_script = "$dsroot/index.txt";
+my $root_index_script = "$dsroot/index.txt.template";
 if (!stat($root_index_script)) {
     $err .= "Data Store not found at '$dsroot'.\n"
@@ -106,11 +128,8 @@
     unless defined $dbname;
 my $dbuser   = metadataLookupStr($siteConfig, 'DS_DBUSER');
-my $dbpass   = metadataLookupStr($siteConfig, 'DS_DBPASSWORD');
+$dbpass   = metadataLookupStr($siteConfig, 'DS_DBPASSWORD') if !$dbpass;
 exit ($PS_EXIT_CONFIG_ERROR) unless defined $dbserver and $dbname and $dbuser and $dbpass;
 
 my $dsn = "DBI:mysql:host=$dbserver;database=$dbname";
-
-my $dbh = DBI->connect($dsn, $dbuser, $dbpass) or die "Cannot connect to server\n";
-
 
 my $product_dir = "$dsroot/$product";
@@ -118,4 +137,5 @@
 
 if ($del) {
+    my $dbh = DBI->connect($dsn, $dbuser, $dbpass) or die "Cannot connect to server\n";
     #
     # delete product
@@ -129,14 +149,4 @@
     }
     my $prod_id = $prod_row->{prod_id};
-
-    # if requested, remove the product directory
-    if ($remove) {
-        if (system "rm -r $product_dir") {
-            die("failed to remove $product_dir");
-        }
-    } else  {
-        # otherwise just zap the index script
-        unlink("$index_script_name");
-    }
 
 
@@ -152,4 +162,17 @@
     $dbh->do("DELETE from dsProduct where prod_id = $prod_id");
 
+    print "Product $product deleted.\n";
+
+    # if requested, remove the product directory
+    if ($remove) {
+        print "Removing files from $product.\n";
+        if (system "rm -r $product_dir") {
+            die("failed to remove $product_dir");
+        }
+    } else  {
+        # otherwise just zap the index script
+        unlink("$index_script_name");
+    }
+
     exit 0;
 
@@ -158,4 +181,6 @@
     # add a new product
     #
+    my $dbh = DBI->connect($dsn, $dbuser, $dbpass) or die "Cannot connect to server\n";
+
     my $stmt = $dbh->prepare("SELECT prod_id FROM dsProduct WHERE prod_name = \'$product\'");
     $stmt->execute();
@@ -167,4 +192,10 @@
 
     # set up the product directory
+    # if there is an old index file delete it
+    if (-e $index_script_name ) {
+        if (!unlink($index_script_name)) {
+            die("failed trying to remove old $index_script_name");
+        }
+    }
     if (! -e $product_dir) {
         $we_created_dir = 1;
@@ -172,10 +203,10 @@
             die("failed trying to make product directory $product_dir");
         }
-    }
-    if (-e $index_script_name ) {
-        if (!unlink($index_script_name)) {
-            die("failed trying to remove old $index_script_name");
-        }
-    }
+    } else {
+        # directory alrady exists make sure that it's empty
+        my @dirlist = glob("$product_dir/*");
+        die ("existing product directory $product_dir is not empty") if scalar @dirlist;
+    }
+
     if (!copy($root_index_script, $index_script_name)) {
         print STDERR "failed trying to copy($root_index_script, $index_script_name)";
Index: branches/eam_branches/20090820/DataStoreServer/scripts/dsreg
===================================================================
--- branches/eam_branches/20090820/DataStoreServer/scripts/dsreg	(revision 25206)
+++ branches/eam_branches/20090820/DataStoreServer/scripts/dsreg	(revision 25766)
@@ -203,8 +203,8 @@
                 $new_last_fs = $new_newest->{fileset_name};
             } else {
-                $new_last_fs = "none";
+                $new_last_fs = undef;
             }
             $stmt->finish();
-            $dbh->do("UPDATE dsProduct SET last_fs = \'$new_last_fs\' WHERE prod_id = $prod_id");
+            $dbh->do("UPDATE dsProduct SET last_fs = ? WHERE prod_id = $prod_id", undef, ($new_last_fs));
         }
         $dbh->commit();
Index: branches/eam_branches/20090820/DataStoreServer/scripts/installscripts
===================================================================
--- branches/eam_branches/20090820/DataStoreServer/scripts/installscripts	(revision 25206)
+++ branches/eam_branches/20090820/DataStoreServer/scripts/installscripts	(revision 25766)
@@ -56,5 +56,5 @@
 # index.txt file for the root of the data store.
 my @dsroot_list = qw(
-index.txt
+index.txt.template
 );
 
Index: branches/eam_branches/20090820/DataStoreServer/scripts/tabledefs.sql
===================================================================
--- branches/eam_branches/20090820/DataStoreServer/scripts/tabledefs.sql	(revision 25206)
+++ branches/eam_branches/20090820/DataStoreServer/scripts/tabledefs.sql	(revision 25766)
@@ -75,4 +75,7 @@
 # type specific column for type chip
 INSERT INTO dsFileType (type, type_col_0) VALUES('chip', 'chipname');
+INSERT INTO dsFileType (type, type_col_0) VALUES('dbinfo', 'component');
+INSERT INTO dsFileType (type, type_col_0) VALUES('text', 'component');
+INSERT INTO dsFileType (type, type_col_0) VALUES('tgz', 'component');
 
 # none of these types have any type specific columns
Index: branches/eam_branches/20090820/DataStoreServer/web/cgi/dsgetindex
===================================================================
--- branches/eam_branches/20090820/DataStoreServer/web/cgi/dsgetindex	(revision 25206)
+++ branches/eam_branches/20090820/DataStoreServer/web/cgi/dsgetindex	(revision 25766)
@@ -140,7 +140,9 @@
             # 'text/plain' format
             print header('text/plain', '404 ERROR');
-            #print header('text/plain', '200 OK');
+#           print header('text/plain', '410 GONE');
+#            print header('text/plain', '200 OK');
             print @$stderr_buf;
             print STDERR @$stderr_buf;
+#            exit 410;
         }
     }
@@ -172,17 +174,26 @@
 #
 
-sub print_free_space {
-    use Filesys::Df;
-	# get free space
-	my $ref = df($DS_ROOT);
-	printf '<p>Free space: %.2f G (%.1f%%)</p>',
-		$ref->{bfree}/(1024*1024),
-		100.0*$ref->{bfree}/$ref->{blocks};
-        print "\n";
-}
+#sub print_free_space {
+#    use Filesys::Df;
+#	# get free space
+#	my $ref = df($DS_ROOT);
+#	printf '<p>Free space: %.2f G (%.1f%%)</p>',
+#		$ref->{bfree}/(1024*1024),
+#		100.0*$ref->{bfree}/$ref->{blocks};
+#        print "\n";
+#}
 sub pprint_pre {
 
     print header('text/html', '200 OK');
-    print start_html('Data Store');
+    my $name;
+    # note $fileset is not so we look at the name of the index script to determine the level
+    if ($program eq "dsfsindex") {
+        $name = $fileset;
+    } elsif ($program eq "dsprodindex") {
+        $name = "$product";
+    } else {
+        $name = "";
+    }
+    print start_html("IPP Data Store $name");
 
 
@@ -208,5 +219,5 @@
     print p();
 
-    print_free_space();
+#    print_free_space();
     print end_html();
 }
@@ -241,8 +252,10 @@
             # if this is a file request, use a download cgi
             if ($wpath =~ /\.fits\s*$/) {
-                    $wpath = '/ds-cgi/dsfits.cgi?'.substr($wpath, 4); # strip' /ds/'
+                # This doesn't work through the proxy
+                # The /ds-cgi gets tried on alala
+                #    $wpath = '/ds-cgi/dsfits.cgi?'.substr($wpath, 4); # strip' /ds/'
             }
 
-        print a({-href=>$wpath}, $toks[0]);
+        print a({-href=>$wpath, -type=>'image/x-fits'}, $toks[0]);
     }
 
Index: branches/eam_branches/20090820/DataStoreServer/web/cgi/index.txt
===================================================================
--- branches/eam_branches/20090820/DataStoreServer/web/cgi/index.txt	(revision 25206)
+++ 	(revision )
@@ -1,1 +1,0 @@
-<!--#include virtual="/ds-cgi/dstxtindex.cgi" -->
Index: branches/eam_branches/20090820/DataStoreServer/web/cgi/index.txt.template
===================================================================
--- branches/eam_branches/20090820/DataStoreServer/web/cgi/index.txt.template	(revision 25766)
+++ branches/eam_branches/20090820/DataStoreServer/web/cgi/index.txt.template	(revision 25766)
@@ -0,0 +1,1 @@
+<!--#include virtual="/ds-cgi/dstxtindex.cgi" -->
Index: branches/eam_branches/20090820/Ohana/src/addstar/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/addstar/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/addstar/src/ConfigInit.c	(revision 25766)
@@ -180,5 +180,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/addstar/src/ConfigInit_skycells.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/addstar/src/ConfigInit_skycells.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/addstar/src/ConfigInit_skycells.c	(revision 25766)
@@ -55,5 +55,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/addstar/src/addstar.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/addstar/src/addstar.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/addstar/src/addstar.c	(revision 25766)
@@ -25,5 +25,5 @@
   options = args (argc, argv, options);
 
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   if (sky == NULL) {
       fprintf (stderr, "ERROR: unable to load sky table data\n");
Index: branches/eam_branches/20090820/Ohana/src/addstar/src/addstard.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/addstar/src/addstard.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/addstar/src/addstard.c	(revision 25766)
@@ -12,5 +12,5 @@
 
   /* store the sky table in a global for internal use */
-  ServerSky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  ServerSky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (ServerSky, CATDIR, "cpt");
 
Index: branches/eam_branches/20090820/Ohana/src/addstar/src/addstart.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/addstar/src/addstart.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/addstar/src/addstart.c	(revision 25766)
@@ -12,5 +12,5 @@
 
   /* store the sky table in a global for internal use */
-  ServerSky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  ServerSky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (ServerSky, CATDIR, "cpt");
 
Index: branches/eam_branches/20090820/Ohana/src/addstar/src/load2mass.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/addstar/src/load2mass.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/addstar/src/load2mass.c	(revision 25766)
@@ -16,5 +16,5 @@
 
   // load the full sky description table:
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   
Index: branches/eam_branches/20090820/Ohana/src/addstar/src/sedstar.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/addstar/src/sedstar.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/addstar/src/sedstar.c	(revision 25766)
@@ -15,5 +15,5 @@
   options = args_sedstar (argc, argv, options);
 
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   
Index: branches/eam_branches/20090820/Ohana/src/delstar/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/delstar/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/delstar/src/ConfigInit.c	(revision 25766)
@@ -45,5 +45,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/delstar/src/delete_imagefile.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/delstar/src/delete_imagefile.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/delstar/src/delete_imagefile.c	(revision 25766)
@@ -12,5 +12,5 @@
 
   /* load sky from correct table */
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
 
Index: branches/eam_branches/20090820/Ohana/src/delstar/src/delete_imagename.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/delstar/src/delete_imagename.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/delstar/src/delete_imagename.c	(revision 25766)
@@ -15,5 +15,5 @@
 
   /* load sky from correct table */
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
 
Index: branches/eam_branches/20090820/Ohana/src/delstar/src/delete_times.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/delstar/src/delete_times.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/delstar/src/delete_times.c	(revision 25766)
@@ -15,5 +15,5 @@
 
   /* load sky from correct table */
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
 
Index: branches/eam_branches/20090820/Ohana/src/dvomerge/src/dvomerge.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/dvomerge/src/dvomerge.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/dvomerge/src/dvomerge.c	(revision 25766)
@@ -24,5 +24,5 @@
   // the first input define the photcode table & db layout
   sprintf (filename, "%s/Photcodes.dat", input1);
-  if (!LoadPhotcodes (filename, NULL)) {
+  if (!LoadPhotcodes (filename, NULL, FALSE)) {
     fprintf (stderr, "error loading photcode table %s\n", filename);
     exit (1);
@@ -30,5 +30,5 @@
   // save the photcodes in the output catdir
   sprintf (filename, "%s/Photcodes.dat", output);
-  if (!check_file_access (filename, TRUE, TRUE)) {
+  if (!check_file_access (filename, TRUE, TRUE, TRUE)) {
     fprintf (stderr, "error creating output catdir %s\n", output);
     exit (1);
@@ -40,12 +40,12 @@
 
   // load the sky table for the existing database
-  insky1 = SkyTableLoadOptimal (input1, NULL, NULL, SKY_DEPTH_HST, VERBOSE);
+  insky1 = SkyTableLoadOptimal (input1, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
   SkyTableSetFilenames (insky1, input1, "cpt");
 
-  insky2 = SkyTableLoadOptimal (input2, NULL, NULL, SKY_DEPTH_HST, VERBOSE);
+  insky2 = SkyTableLoadOptimal (input2, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
   SkyTableSetFilenames (insky2, input2, "cpt");
 
   // generate an output table populated at the desired depth
-  outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, SKY_DEPTH, VERBOSE);
+  outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (outsky, output, "cpt");
 
@@ -117,5 +117,5 @@
   // save the output sky table copy
   sprintf (filename, "%s/SkyTable.fits", output);
-  check_file_access (filename, TRUE, VERBOSE);
+  check_file_access (filename, TRUE, TRUE, VERBOSE);
   if (!SkyTableSave (outsky, filename)) {
     fprintf (stderr, "ERROR: failed to save sky table for %s\n", output);
Index: branches/eam_branches/20090820/Ohana/src/dvosplit/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/dvosplit/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/dvosplit/src/ConfigInit.c	(revision 25766)
@@ -33,5 +33,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/dvosplit/src/dvosplit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/dvosplit/src/dvosplit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/dvosplit/src/dvosplit.c	(revision 25766)
@@ -18,5 +18,5 @@
 
   // load the sky table for the existing database
-  sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, SKY_DEPTH_HST, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, NULL, NULL, TRUE, SKY_DEPTH_HST, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
 
@@ -79,5 +79,5 @@
   // save sky table copy
   sprintf (filename, "%s/SkyTable.fits", CATDIR);
-  check_file_access (filename, TRUE, VERBOSE);
+  check_file_access (filename, TRUE, TRUE, VERBOSE);
   if (!SkyTableSave (sky, filename)) {
     fprintf (stderr, "ERROR: failed to save sky table for %s\n", CATDIR);
Index: branches/eam_branches/20090820/Ohana/src/gastro/src/getptolemy.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/gastro/src/getptolemy.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/gastro/src/getptolemy.c	(revision 25766)
@@ -19,5 +19,5 @@
 
   /* load regions from GSC table, restrict to patch */
-  sky = SkyTableLoadOptimal (CATDIR, NULL, GSCFILE, SKY_DEPTH_HST, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, NULL, GSCFILE, FALSE, SKY_DEPTH_HST, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   skylist = SkyListByPatch (sky, -1, &patch);
Index: branches/eam_branches/20090820/Ohana/src/gastro2/src/getptolemy.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/gastro2/src/getptolemy.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/gastro2/src/getptolemy.c	(revision 25766)
@@ -21,5 +21,5 @@
 
   /* load regions from GSC table, restrict to patch */
-  sky = SkyTableLoadOptimal (CATDIR, NULL, GSCFILE, SKY_DEPTH_HST, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, NULL, GSCFILE, FALSE, SKY_DEPTH_HST, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   skylist = SkyListByPatch (sky, -1, &patch);
Index: branches/eam_branches/20090820/Ohana/src/getstar/include/dvoImagesAtCoords.h
===================================================================
--- branches/eam_branches/20090820/Ohana/src/getstar/include/dvoImagesAtCoords.h	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/getstar/include/dvoImagesAtCoords.h	(revision 25766)
@@ -18,4 +18,13 @@
 Coords *MOSAIC;         // carries the mosaic into ReadImageHeader
 
+typedef struct {
+    int     id;
+    double  ra;
+    double  dec;
+    int     Nmatches;
+    int     *matches;
+    int     arrayLength;
+} Point;
+
 int WITH_PHU;
 int SOLO_PHU;
@@ -33,7 +42,5 @@
 Image *ReadImageFiles (char *filename, int *Nimages);
 int ReadImageHeader (Header *header, Image *image);
-int *MatchCoords(Image *, int, double, double, int *);
+int MatchCoords(Image *, int, Point *, int);
 
 int GetFileMode (Header *header);
-// int edge_check (double *x1, double *y1, double *x2, double *y2);
-// double opening_angle (double x1, double y1, double x2, double y2, double x3, double y3);
Index: branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit.c	(revision 25766)
@@ -34,5 +34,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_coords.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_coords.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_coords.c	(revision 25766)
@@ -35,5 +35,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_extract.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_extract.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_extract.c	(revision 25766)
@@ -35,5 +35,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_overlaps.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_overlaps.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/getstar/src/ConfigInit_overlaps.c	(revision 25766)
@@ -35,5 +35,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, FALSE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/getstar/src/MatchCoords.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/getstar/src/MatchCoords.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/getstar/src/MatchCoords.c	(revision 25766)
@@ -5,8 +5,8 @@
 
 /* given coordinate, find images in list that contain the point */
-int *MatchCoords (Image *dbImages, int NdbImages, double ra, double dec, int *Nmatch) {
+int MatchCoords (Image *dbImages, int NdbImages, Point *points, int Npoints) {
   
-  int i, j, N, addtolist, status;
-  int NMATCH, nmatch, *match;
+  int i, j, N;
+  int totalMatches = 0;
   Coords tcoords;
   double r, d;
@@ -15,10 +15,4 @@
   double xmin, xmax, ymin, ymax;
 
-  *Nmatch = 0;
-
-  /* match represents the subset of overlapping images */
-  nmatch = 0;
-  NMATCH = 20;
-  ALLOCATE (match, int, NMATCH);
 
   /* setup links for mosaic WRP and DIS entries */
@@ -49,28 +43,32 @@
     }
 
-    // transform input point to image coords
-    double x, y;
-    int status = RD_to_XY(&x, &y, ra, dec, &dbImages[i].coords);
+    for (j = 0; j < Npoints; j++) {
+        Point *pt = points + j;
 
-    if (!status) {
-        // avoid matching antipodal skycells
-        continue;
-    }
+        // transform input point to image coords
+        double x, y;
+        int status = RD_to_XY(&x, &y, pt->ra, pt->dec, &dbImages[i].coords);
 
-    if ((x >= xmin && x <= xmax) && (y >= ymin && y <= ymax)) {
+        if (!status) {
+            // avoid matching antipodal skycells
+            continue;
+        }
 
-        match[nmatch] = i;
-        nmatch ++;
-        if (nmatch == NMATCH) {
-          NMATCH += 20;
-          REALLOCATE (match, int, NMATCH);
+        if ((x >= xmin && x <= xmax) && (y >= ymin && y <= ymax)) {
+            totalMatches++;
+
+            pt->matches[pt->Nmatches] = i;
+            pt->Nmatches ++;
+
+            if (pt->Nmatches == pt->arrayLength) {
+                pt->arrayLength += 20;
+                REALLOCATE (pt->matches, int, pt->arrayLength);
+            }
         }
     }
-      
-  }
-  if (VERBOSE) fprintf (stderr, "found %d overlapping images\n", nmatch);
+ }
+ if (VERBOSE) fprintf (stderr, "found %d overlapping images\n", totalMatches);
   
-  *Nmatch = nmatch;
-  return (match);
+ return (totalMatches);
 }
   
Index: branches/eam_branches/20090820/Ohana/src/getstar/src/dvoImagesAtCoords.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/getstar/src/dvoImagesAtCoords.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/getstar/src/dvoImagesAtCoords.c	(revision 25766)
@@ -1,12 +1,11 @@
 # include "dvoImagesAtCoords.h"
 
-typedef struct {
-    int     id;
-    double  ra;
-    double  dec;
-} Point;
+// We'd like to do this but since pstamp gets built later this won't work
+// so just redefine the macro
+// # include "pstamp.h"
+#define PSTAMP_NO_OVERLAP 28
 
 static int readPoints(char *filename, Point **pointsOut);
-static int ListImagesAtCoords (Image *dbImages, int id, double ra, double dec, int *matches, int Nmatches);
+static int ListImagesAtCoords (Image *dbImages, Point *points, int Npoints);
 
 int main (int argc, char **argv) {
@@ -25,10 +24,10 @@
   Npoints = readPoints(argv[1], &points);
   if (!Npoints) {
-    exit(0);
+    exit(1);
   }
 
   if (astromFile) {
       dbImages = ReadImageFiles(astromFile, &NdbImages);
-    } else {
+  } else {
     /*** update the image table ***/
     /* setup image table format and lock */
@@ -53,11 +52,10 @@
   }
   
-  Point *pt;
-  for (i = 0, pt = points; i < Npoints; i++, pt++) {
-    matches = MatchCoords (dbImages, NdbImages, pt->ra, pt->dec, &Nmatches);
-    ListImagesAtCoords(dbImages, pt->id, pt->ra, pt->dec, matches, Nmatches);
+  if (MatchCoords (dbImages, NdbImages, points, Npoints)) {
+    ListImagesAtCoords(dbImages, points, Npoints);
+    exit(0);
+  } else {
+    exit(PSTAMP_NO_OVERLAP);
   }
-
-  exit (0);
 }
 
@@ -83,6 +81,9 @@
 
     while ((Nread = fscanf(f, "%d %lf %lf\n", &pts[Npoints].id, &pts[Npoints].ra, &pts[Npoints].dec)) == 3) {
-        Npoints++;
-        if (Npoints >= LEN) {
+        pts[Npoints].Nmatches = 0;
+        ALLOCATE(pts[Npoints].matches, int, 20);
+        pts[Npoints].arrayLength = 20;
+
+        if (++Npoints >= LEN) {
             LEN += 20;
             REALLOCATE(pts, Point, LEN);
@@ -99,24 +100,33 @@
 }
 
-static int ListImagesAtCoords (Image *dbImages, int id, double ra, double dec, int *matches, int Nmatches)
+static int ListImagesAtCoords (Image *dbImages, Point *points, int Npoints) 
 {
+  int j;
   int i;
-  for (i = 0; i < Nmatches; i++) {
-    int N = matches[i];
+  for (j = 0; j < Npoints; j++) {
+      Point *pt = points + j;
+      for (i = 0; i < pt->Nmatches; i++) {
+        int N = pt->matches[i];
 
-    char *name;
-    // output of lookup is filename[class_id.hdr] for astrometry files
-    char *left_bracket = rindex(dbImages[N].name, '[');
-    if (left_bracket) {
-        name = strdup(left_bracket + 1);
-        // zap the .hdr]
-        char *dot = index(name, '.');
-        if (dot) {
-            *dot = 0;
+        char *name;
+        char *copy = NULL;
+        // output of lookup is filename[class_id.hdr] for astrometry files
+        char *left_bracket = rindex(dbImages[N].name, '[');
+        if (left_bracket) {
+            copy = strdup(left_bracket + 1);
+            name = copy;
+            // zap the .hdr]
+            char *dot = index(name, '.');
+            if (dot) {
+                *dot = 0;
+            }
+        } else {
+            name = dbImages[N].name;
         }
-    } else {
-        name = dbImages[N].name;
+        fprintf (stdout, "%d %lf %lf %s\n", pt->id, pt->ra, pt->dec, name);
+        if  (copy) {
+            free(copy);
+        }
     }
-    fprintf (stdout, "%d %lf %lf %s\n", id, ra, dec, name);
   }
   
Index: branches/eam_branches/20090820/Ohana/src/getstar/src/getstar.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/getstar/src/getstar.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/getstar/src/getstar.c	(revision 25766)
@@ -13,5 +13,5 @@
   set_db (&db);
 
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   if (!sky) exit (1);
     
Index: branches/eam_branches/20090820/Ohana/src/imregister/base/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/imregister/base/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/imregister/base/ConfigInit.c	(revision 25766)
@@ -105,5 +105,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", catdir);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/imregister/imphot/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/imregister/imphot/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/imregister/imphot/ConfigInit.c	(revision 25766)
@@ -101,5 +101,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/kapa2/Makefile
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/Makefile	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/Makefile	(revision 25766)
@@ -48,7 +48,8 @@
 $(SRC)/Layout.$(ARCH).o		  	  $(SRC)/Sections.$(ARCH).o	      \
 $(SRC)/Graphs.$(ARCH).o                   $(SRC)/SetGraphSize.$(ARCH).o       \
-$(SRC)/Resize.$(ARCH).o                   $(SRC)/ErasePlots.$(ARCH).o         \
-$(SRC)/EraseImage.$(ARCH).o         	  $(SRC)/SetToolbox.$(ARCH).o         \
+$(SRC)/Resize.$(ARCH).o                   $(SRC)/Relocate.$(ARCH).o           \
+$(SRC)/ErasePlots.$(ARCH).o               $(SRC)/EraseImage.$(ARCH).o         \
 $(SRC)/EraseCurrentPlot.$(ARCH).o         $(SRC)/EraseSections.$(ARCH).o      \
+$(SRC)/SetToolbox.$(ARCH).o                                                   \
 $(SRC)/SetSection.$(ARCH).o		  $(SRC)/DefineSection.$(ARCH).o      \
 $(SRC)/SetLimits.$(ARCH).o                $(SRC)/SetFont.$(ARCH).o            \
@@ -79,7 +80,4 @@
 $(SRC)/ColorHistogram.$(ARCH).o           $(SRC)/CreateWide.$(ARCH).o
 
-#$(SRC)/CreateZoom8.$(ARCH).o              $(SRC)/CreateZoom16.$(ARCH).o       \
-#$(SRC)/CreateZoom24.$(ARCH).o             $(SRC)/CreateZoom32.$(ARCH).o       \
-
 OBJ  =  $(KAPA)
 
Index: branches/eam_branches/20090820/Ohana/src/kapa2/include/constants.h
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/include/constants.h	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/include/constants.h	(revision 25766)
@@ -11,5 +11,5 @@
 
 # define NCHANNELS 3
-# define NPIXELS_DYNAMIC 128
+# define NPIXELS_DYNAMIC 4600
 
 // XXX for the moment, this is set to match the values in SetColorScale3D_CC
Index: branches/eam_branches/20090820/Ohana/src/kapa2/include/prototypes.h
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/include/prototypes.h	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/include/prototypes.h	(revision 25766)
@@ -55,4 +55,5 @@
 int           LoadTextlines       PROTO((int sock));
 int           Resize              PROTO((int sock));
+int           Relocate            PROTO((int sock));
 int           GetLimits           PROTO((int sock));
 int           SetLimits           PROTO((int sock));
@@ -178,6 +179,6 @@
 void          Image_to_Picture    PROTO((double *x1, double *y1, double x2, double y2, Picture *picture));
 void          Image_to_Screen     PROTO((double *x1, double *y1, double x2, double y2, Picture *picture));
-void          Picture_Lower 	  PROTO((int *i_start, int *j_start, Matrix *matrix, Picture *picture));
-void          Picture_Upper 	  PROTO((int *i_end, int *j_end, Matrix *matrix, Picture *picture));
+void          Picture_Lower 	  PROTO((int *i_start, int *j_start, int *I_start, int *J_start, Matrix *matrix, Picture *picture));
+void          Picture_Upper 	  PROTO((int *i_end, int *j_end, int i_start, int j_start, Matrix *matrix, Picture *picture));
 
 void          DragColorbar        PROTO((Graphic *graphic, KapaImageWidget *image, XButtonEvent *mouse_event));
Index: branches/eam_branches/20090820/Ohana/src/kapa2/include/structures.h
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/include/structures.h	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/include/structures.h	(revision 25766)
@@ -21,5 +21,5 @@
   Window         window;
   Visual        *visual;
-  int            visualclass; // is visual dynamic? (XXX change name?)
+  int            dynamicColors; // is visual dynamic?
   int            Nbits;	      // pixel depth in bits (8, 16, 24, 32)
   GC             gc;
@@ -94,5 +94,5 @@
   int      DX, DY;	      // size of displayed picture (must be updated with new images...)
   int      expand;	      // zoomscale
-  double   X,  Y;	      // center of image in picture
+  double   Xc,  Yc;	      // center of image in picture
   char     flipx, flipy;      // parity (0 = +; 1 = -)
   XImage  *pix;
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/ButtonFunctions.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/ButtonFunctions.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/ButtonFunctions.c	(revision 25766)
@@ -44,6 +44,6 @@
 int Recenter (Graphic *graphic, KapaImageWidget *image) {
 
-  image[0].picture.X = 0.5*image[0].image[0].matrix.Naxis[0];
-  image[0].picture.Y = 0.5*image[0].image[0].matrix.Naxis[1];
+  image[0].picture.Xc = 0.5*image[0].image[0].matrix.Naxis[0];
+  image[0].picture.Yc = 0.5*image[0].image[0].matrix.Naxis[1];
  
   Remap (graphic, image);
@@ -56,4 +56,5 @@
 
   image[0].picture.expand = 1;
+  image[0].zoom.expand = 5;
   Remap (graphic, image);
   Refresh ();
@@ -64,7 +65,8 @@
 int RecenterRescale (Graphic *graphic, KapaImageWidget *image) {
 
-  image[0].picture.X = 0.5*image[0].image[0].matrix.Naxis[0];
-  image[0].picture.Y = 0.5*image[0].image[0].matrix.Naxis[1];
+  image[0].picture.Xc = 0.5*image[0].image[0].matrix.Naxis[0];
+  image[0].picture.Yc = 0.5*image[0].image[0].matrix.Naxis[1];
   image[0].picture.expand = 1;
+  image[0].zoom.expand = 5;
  
   Remap (graphic, image);
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/Center.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/Center.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/Center.c	(revision 25766)
@@ -16,8 +16,10 @@
   if (image == NULL) return (TRUE);
 
-  image[0].picture.X = X;
-  image[0].picture.Y = Y;
+  // enforce integer center here?
+  image[0].picture.Xc = X;
+  image[0].picture.Yc = Y;
   if ((zoom != 0) && (zoom != -1)) {
     image[0].picture.expand = zoom;
+    image[0].zoom.expand = MIN(image[0].zoom.dx / 5.5, MAX(5, 2*zoom));
   }
 
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckPipe.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckPipe.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckPipe.c	(revision 25766)
@@ -131,4 +131,10 @@
   }
 
+  if (!strcmp (word, "MOVE")) {
+    status = Relocate (sock);
+    KiiSendCommand (sock, 4, "DONE");
+    FINISHED (status);
+  }
+
   if (!strcmp (word, "GLIM")) {
     GetLimits (sock);
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckVisual.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckVisual.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckVisual.c	(revision 25766)
@@ -10,5 +10,5 @@
 
   int i, Nfound, N;
-  int isColor, isDefault, isDynamic;
+  int isColor, isDefault;
   XVisualInfo *visual_list, visual_temp;
   unsigned long planes[3];
@@ -34,29 +34,8 @@
   }
   
-// skip the default and the PseudoColor visuals, go for TrueColor first
-# if (0)
-  /* check default visual first */ 
-  for (i = 0; (i < Nfound) && (graphic[0].visual != visual_list[i].visual); i++);
-  if (i == Nfound) {
-    fprintf (stderr, "default visual not found??\n");
-    exit (0);
-  }
-# endif
-
   // set these based on selected visual
-  isColor = isDefault = isDynamic = FALSE;
-
-# if (0)
-  // attempt to select the most desirable type of visual: Default as PseudoColor (XXX is it still true?)
-  if (DEBUG) fprintf (stderr, "default visual class is %d\n", visual_list[i].class);
-  if (visual_list[i].class == PseudoColor) {
-    isColor = isDefault = isDynamic = TRUE;
-    graphic[0].visual = visual_list[i].visual;
-    graphic[0].visualclass = TRUE;
-    goto test_pixels;
-  }
-# endif
-
-  // attempt to select the most desirable type of visual: TrueColor (XXX is it still true?)
+  isColor = isDefault = FALSE;
+
+  // attempt to select the most desirable type of visual: TrueColor
   for (i = 0; (i < Nfound) && (visual_list[i].class != TrueColor); i++);
   if (i != Nfound) {
@@ -65,5 +44,18 @@
     isDefault = (graphic[0].visual == visual_list[i].visual);
     graphic[0].visual = visual_list[i].visual;
-    graphic[0].visualclass = FALSE;
+    graphic[0].dynamicColors = FALSE;
+    if (DEBUG) fprintf (stderr, "got TrueColor visual\n");
+    goto test_pixels;
+  }
+
+  // attempt to select the most desirable type of visual: DirectColor
+  for (i = 0; (i < Nfound) && (visual_list[i].class != DirectColor); i++);
+  if (i != Nfound) {
+    isColor = TRUE;
+    if (DEBUG) fprintf (stderr, "visual class is %d\n", visual_list[i].class);
+    isDefault = (graphic[0].visual == visual_list[i].visual);
+    graphic[0].visual = visual_list[i].visual;
+    graphic[0].dynamicColors = TRUE;
+    if (DEBUG) fprintf (stderr, "got DirectColor visual\n");
     goto test_pixels;
   }
@@ -72,9 +64,10 @@
   for (i = 0; (i < Nfound) && (visual_list[i].class != PseudoColor); i++);
   if (i != Nfound) {
-    isColor = isDynamic = TRUE;
+    isColor = TRUE;
     if (DEBUG) fprintf (stderr, "selected visual class is %d\n", visual_list[i].class);
     isDefault = (graphic[0].visual == visual_list[i].visual);
     graphic[0].visual = visual_list[i].visual;
-    graphic[0].visualclass = TRUE;
+    graphic[0].dynamicColors = TRUE;
+    if (DEBUG) fprintf (stderr, "got PseudoColor visual\n");
     goto test_pixels;
   }
@@ -83,9 +76,9 @@
   for (i = 0; (i < Nfound) && (visual_list[i].class != GrayScale); i++);
   if (i != Nfound) {
-    isDynamic = TRUE;
     if (DEBUG) fprintf (stderr, "selected visual class is %d\n", visual_list[i].class);
     isDefault = (graphic[0].visual == visual_list[i].visual);
     graphic[0].visual = visual_list[i].visual;
-    graphic[0].visualclass = TRUE;
+    graphic[0].dynamicColors = TRUE;
+    if (DEBUG) fprintf (stderr, "got GrayScale visual\n");
     goto test_pixels;
   }
@@ -97,5 +90,6 @@
     isDefault = (graphic[0].visual == visual_list[i].visual);
     graphic[0].visual = visual_list[i].visual;
-    graphic[0].visualclass = FALSE;
+    graphic[0].dynamicColors = FALSE;
+    if (DEBUG) fprintf (stderr, "got StaticColor visual\n");
     goto test_pixels;
   }
@@ -107,5 +101,6 @@
     isDefault = (graphic[0].visual == visual_list[i].visual);
     graphic[0].visual = visual_list[i].visual;
-    graphic[0].visualclass = FALSE;
+    graphic[0].dynamicColors = FALSE;
+    if (DEBUG) fprintf (stderr, "got StaticGray visual\n");
     goto test_pixels;
   }
@@ -115,4 +110,5 @@
   /* need to make a colormap if 
      1) the selected visual is not the default 
+        XXX not sure if I need to / am allowed to alloc a colormap if I've grabbed the default.
      2) there are not enough colors available */
 
@@ -125,11 +121,15 @@
   } 
 
-  // allocate a private colormap, if needed
+  // dynamic visual classes can accept AllocAll and can use XAllocColorCells while AllocNone must use XAllocColor
+  // int allocMode = graphic[0].dynamicColors ? AllocAll : AllocNone;
+  int allocMode = AllocNone;
+
+  // allocate a private colormap, if desired or needed
   if (!isDefault) {
     if (DEBUG) fprintf (stderr, "allocated private colormap\n");
-    graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, AllocNone);
-  }
-
-  if (isDynamic) {
+    graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, allocMode);
+  }
+
+  if (graphic[0].dynamicColors) {
     Npixels = NPIXELS_DYNAMIC;
     if ((N = get_argument (*argc, argv, "-ncolors"))) {
@@ -144,6 +144,9 @@
     for (graphic[0].Npixels = Npixels; graphic[0].Npixels >= 16; graphic[0].Npixels -= 4) {
       if (DEBUG) fprintf (stderr, "trying %d colors\n", (int) graphic[0].Npixels);
-      if (XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 1, graphic[0].pixels, graphic[0].Npixels)) {
+      if (XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 0, graphic[0].pixels, graphic[0].Npixels)) {
 	break;
+      }
+      for (i = 0; i < graphic[0].Npixels; i++) {
+	graphic[0].cmap[i].pixel = graphic[0].pixels[i];
       }
     }
@@ -152,9 +155,10 @@
     if (graphic[0].Npixels < 16) {
       if (!isDefault) {
+	// We've already tried to allocate a colormap above...
 	fprintf (stderr, "can't allocate enough cells in private colormap\n");
 	exit (0);
       }
       if (DEBUG) fprintf (stderr, "can't allocate enough cells, using private colormap\n");
-      graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, AllocNone);
+      graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, allocMode);
 
       for (graphic[0].Npixels = NPIXELS_DYNAMIC; graphic[0].Npixels >= 16; graphic[0].Npixels -= 4) {
@@ -163,6 +167,8 @@
 	  break;
 	}
-      }
-
+	for (i = 0; i < graphic[0].Npixels; i++) {
+	  graphic[0].cmap[i].pixel = graphic[0].pixels[i];
+	}
+      }
       if ((N = get_argument (*argc, argv, "-colorcount"))) {
 	fprintf (stderr, "kapa can grab %d colors\n", graphic[0].Npixels);
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckVisual.test.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckVisual.test.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/CheckVisual.test.c	(revision 25766)
@@ -0,0 +1,174 @@
+# include "Ximage.h"
+
+/* DirectColor doesn't seem to work, even though it is available:
+   I cannot use XAllocColorCells to get pixels under DirectColor
+*/
+
+/* static int try_visual[] = {5, 3, 1, 4, 2, 0}; */
+
+int TryVisualType (int *isColor, int *isDefault, Graphic *graphic, int Nvisual, XVisualInfo *visual_list, int VisualType, char *name) {
+
+    int i;
+
+    for (i = 0; i < Nvisual; i++) {
+	if (visual_list[i].class != VisualType) continue;
+
+	*isColor = FALSE;
+	if (VisualType == DirectColor) *isColor = TRUE;
+	if (VisualType == PseudoColor) *isColor = TRUE;
+	if (VisualType == TrueColor)   *isColor = TRUE;
+
+	if (DEBUG) fprintf (stderr, "visual class is %d\n", visual_list[i].class);
+	*isDefault = (graphic[0].visual == visual_list[i].visual);
+
+	graphic[0].dynamicColors = FALSE;
+	if (VisualType == DirectColor) graphic[0].dynamicColors = TRUE;
+	if (VisualType == PseudoColor) graphic[0].dynamicColors = TRUE;
+	if (VisualType == GrayScale) graphic[0].dynamicColors = TRUE;
+
+	if (DEBUG) fprintf (stderr, "got %s visual\n", name);
+	return (TRUE);
+    }
+    return (FALSE);
+}
+
+void CheckVisual (Graphic *graphic, int *argc, char **argv) {
+
+  int i, Nvisual, N;
+  int isColor, isDefault;
+  XVisualInfo *visual_list, visual_temp;
+  unsigned long planes[3];
+  XPixmapFormatValues *pixmaps;
+  int Npixmaps, Npixels;
+
+  if (DEBUG) {
+    fprintf (stderr, "DirectColor: %d\n", DirectColor);
+    fprintf (stderr, "PseudoColor: %d\n", PseudoColor);
+    fprintf (stderr, "TrueColor:   %d\n", TrueColor);
+    fprintf (stderr, "GrayScale:   %d\n", GrayScale);
+    fprintf (stderr, "StaticColor: %d\n", StaticColor);
+    fprintf (stderr, "StaticGray:  %d\n", StaticGray);
+  }
+
+  visual_temp.screen = graphic[0].screen;
+  
+  /* find available visuals */
+  visual_list = XGetVisualInfo (graphic[0].display, VisualScreenMask, &visual_temp, &Nvisual);
+  if (Nvisual == 0) {
+    fprintf (stderr, "error finding useful visual\n");
+    exit (2);
+  }
+  
+  // set these based on selected visual
+  isColor = isDefault = FALSE;
+
+  if (TryVisualType (&isColor, &isDefault, graphic, Nvisual, visual_list, TrueColor,   "TrueColor"))   goto test_pixels;
+  if (TryVisualType (&isColor, &isDefault, graphic, Nvisual, visual_list, DirectColor, "DirectColor")) goto test_pixels;
+  if (TryVisualType (&isColor, &isDefault, graphic, Nvisual, visual_list, PseudoColor, "PseudoColor")) goto test_pixels;
+  if (TryVisualType (&isColor, &isDefault, graphic, Nvisual, visual_list, GrayScale,   "GrayScale"))   goto test_pixels;
+  if (TryVisualType (&isColor, &isDefault, graphic, Nvisual, visual_list, StaticColor, "StaticColor")) goto test_pixels;
+  if (TryVisualType (&isColor, &isDefault, graphic, Nvisual, visual_list, StaticGray,  "StaticGray"))  goto test_pixels;
+
+  fprintf (stderr, "error finding valid visual\n");
+  exit (2);
+
+  test_pixels:
+
+  /* need to make a colormap if 
+     1) the selected visual is not the default 
+        XXX not sure if I need to / am allowed to alloc a colormap if I've grabbed the default.
+     2) there are not enough colors available */
+
+  /* NEED TO ADD A COUPLE LINES DEFINING THE VARIOUS HARD COLORS (BLACK, WHITE, AND THE OVERLAYS) */
+
+  // allow user to force a private colormap
+  if ((N = get_argument (*argc, argv, "-private"))) {
+    remove_argument(N, argc, argv);
+    isDefault = FALSE;
+  } 
+
+  // dynamic visual classes can accept AllocAll and can use XAllocColorCells while AllocNone must use XAllocColor
+  // int allocMode = graphic[0].dynamicColors ? AllocAll : AllocNone;
+  int allocMode = AllocNone;
+
+  // allocate a private colormap, if desired or needed
+  if (!isDefault) {
+    if (DEBUG) fprintf (stderr, "allocated private colormap\n");
+    graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, allocMode);
+  }
+
+  if (graphic[0].dynamicColors) {
+    Npixels = NPIXELS_DYNAMIC;
+    if ((N = get_argument (*argc, argv, "-ncolors"))) {
+      remove_argument(N, argc, argv);
+      Npixels = atoi (argv[N]);
+      remove_argument(N, argc, argv);
+    } 
+
+    /* allocate color cells */
+    ALLOCATE (graphic[0].pixels, unsigned long, Npixels);
+    ALLOCATE (graphic[0].cmap,   XColor,        Npixels);
+    for (graphic[0].Npixels = Npixels; graphic[0].Npixels >= 16; graphic[0].Npixels -= 4) {
+      if (DEBUG) fprintf (stderr, "trying %d colors\n", (int) graphic[0].Npixels);
+      if (XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 0, graphic[0].pixels, graphic[0].Npixels)) {
+	break;
+      }
+      for (i = 0; i < graphic[0].Npixels; i++) {
+	graphic[0].cmap[i].pixel = graphic[0].pixels[i];
+      }
+    }
+
+    /* insufficient cells, can we make a private colormap? */
+    if (graphic[0].Npixels < 16) {
+      if (!isDefault) {
+	// We've already tried to allocate a colormap above...
+	fprintf (stderr, "can't allocate enough cells in private colormap\n");
+	exit (0);
+      }
+      if (DEBUG) fprintf (stderr, "can't allocate enough cells, using private colormap\n");
+      graphic[0].colormap = XCreateColormap (graphic[0].display, RootWindow (graphic[0].display, graphic[0].screen), graphic[0].visual, allocMode);
+
+      for (graphic[0].Npixels = NPIXELS_DYNAMIC; graphic[0].Npixels >= 16; graphic[0].Npixels -= 4) {
+	if (DEBUG) fprintf (stderr, "trying %d colors\n", (int) graphic[0].Npixels);
+	if (XAllocColorCells (graphic[0].display, graphic[0].colormap, FALSE, planes, 1, graphic[0].pixels, graphic[0].Npixels)) {
+	  break;
+	}
+	for (i = 0; i < graphic[0].Npixels; i++) {
+	  graphic[0].cmap[i].pixel = graphic[0].pixels[i];
+	}
+      }
+      if ((N = get_argument (*argc, argv, "-colorcount"))) {
+	fprintf (stderr, "kapa can grab %d colors\n", graphic[0].Npixels);
+	exit (0);
+      } 
+      if (graphic[0].Npixels < 16) {
+	fprintf (stderr, "can't even allocate enough cells in private colormap\n");
+	exit (0);
+      }
+    }
+  } else {
+    Npixels = NPIXELS_STATIC;
+    if ((N = get_argument (*argc, argv, "-ncolors"))) {
+      remove_argument(N, argc, argv);
+      Npixels = atoi (argv[N]);
+      remove_argument(N, argc, argv);
+    } 
+
+    // XXX allocate the unsigned long *pixels here and above
+    ALLOCATE (graphic[0].pixels, unsigned long, Npixels);
+    ALLOCATE (graphic[0].cmap,   XColor,        Npixels);
+    graphic[0].Npixels = Npixels;
+  }
+
+  if ((N = get_argument (*argc, argv, "-colorcount"))) {
+    fprintf (stderr, "kii can grab %d colors\n", graphic[0].Npixels);
+    exit (0);
+  } 
+  
+  pixmaps = XListPixmapFormats (graphic[0].display, &Npixmaps);
+  for (i = 0; i < Npixmaps; i++) {
+    if (pixmaps[i].depth == graphic[0].depth) {
+      graphic[0].Nbits = pixmaps[i].bits_per_pixel;
+    }
+  }
+}
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/CreateZoom16.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/CreateZoom16.c	(revision 25206)
+++ 	(revision )
@@ -1,144 +1,0 @@
-# include "Ximage.h"
-
-void CreateZoom16 (KapaImageWidget *image, Graphic *graphic, double x, double y) {
-
-# if (0)
-  int i, j, ii, jj;
-  int i_start, i_end, j_start, j_end;
-  int dropback;  /* this is a bit of a kludge... */
-  int dx, dy, DX, DY, pixelN;
-  double expand, zoomscale, Rx, Ry;
-  int expand_in, expand_out;
-  unsigned char *out_pix, *out_pix2, *data;
-  float *imdata, *in_pix,  *in_pix2;
-  unsigned char pixel1[256], pixel2[256];
-  unsigned char pixvalue1, pixvalue2;
-  unsigned long back;
-  unsigned char back1, back2;
-
-  dx = image[0].zoom.dx;
-  dy = image[0].zoom.dy;
-
-  if (image[0].image[0].matrix.size == 0) {  /* create a test pattern */
-    REALLOCATE (image[0].zoom.data, char, 2*dy*dx);
-    bzero (image[0].zoom.data, image[0].zoom.dx*image[0].zoom.dy);
-    image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
-				       image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 16, 0);
-    return;
-  }
-
-  for (i = 0; i < 256; i++) { /* set up pixel array */
-    pixel1[i] = 0x0000ff &  graphic[0].cmap[i].pixel;
-    pixel2[i] = 0x0000ff & (graphic[0].cmap[i].pixel >> 8);
-  }
-  back = graphic[0].back;
-  back1 = 0x0000ff & back;
-  back2 = 0x0000ff & (back >> 8);
-  // define the color transform parameters
-  MaxValue = graphic[0].Npixels - 1;
-  if (image[0].image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].image[0].range;
-    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
-  } else {
-    slope = 1.0;
-    start = image[0].image[0].zero;
-  }
-
-  zoomscale = MAX (5, image[0].expand + 5);
-  expand = 1 / zoomscale;
-  expand_out = (int) zoomscale;
-  expand_in  = 1;
-
-  DX = image[0].image[0].matrix.Naxis[0];
-  DY = image[0].image[0].matrix.Naxis[1];
-  Rx = x - expand*(int)(0.5*(dx + 1)) + 1;
-  Ry = y - expand*(int)(0.5*(dy + 1)) + 1;
-
-  i_start = MIN (MAX (-Rx / expand, (1 - FRAC(Rx)) / expand), dx - expand_out + 1);
-  j_start = MIN (MAX (-Ry / expand, (1 - FRAC(Ry)) / expand), dy - expand_out + 1);
-  i_end   = MAX (MIN ((DX-Rx) / expand, dx - expand_out + 1), 0);
-  j_end   = MAX (MIN ((DY-Ry) / expand, dy - expand_out + 1), 0);
-  dropback = expand_out - (i_end - i_start) % expand_out;
-  if ((i_end - i_start) % expand_out == 0) dropback = 0;
-
-  data = out_pix = (unsigned char *) image[0].zoom.data;
-  imdata  = (float *) image[0].image[0].matrix.buffer;
-  in_pix  = &imdata[DX*(int)MAX(Ry,0) + (int)MAX(Rx,0)];
-
-  /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
-
-  if ((i_end < i_start) || (j_end < j_start)) {
-    for (j = 0; j < dx*dy; j++, out_pix++) 
-      *out_pix = back;
-    return;
-  } 
-  
-  /**** fill in bottom area ****/
-  for (j = 0; j < j_start; j++) {
-    for (i = 0; i < dx; i++, out_pix+=2) {
-      out_pix[0] = back1;
-      out_pix[1] = back2;
-    }
-  }
-
-  for (j = j_start; j < j_end; j+= expand_out, in_pix += expand_in*DX) {
-    out_pix = &data[2*j*dx];
-
-    /**** fill in area to the left of the picture ****/
-    for (jj = 0; jj < expand_out; jj++) { 
-      out_pix2 = out_pix + 2*jj*dx;
-      for (i = 0; i < i_start; i++, out_pix2+=2) {
-	out_pix2[0] = back1;
-	out_pix2[1] = back2;
-      }
-    }
-    out_pix += 2*i_start;
-    
-    /*** fill in the picture region ***/
-    in_pix2 = in_pix;
-    if (expand_out == 1) {
-      for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix+=2) {
-	pixelN = PixelLookup(*in_pix2);
-	out_pix[0] = pixel1[pixelN];
-	out_pix[1] = pixel2[pixelN];
-      }
-    } else {
-      for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= 2*expand_out) { 
-	pixelN = PixelLookup(*in_pix2);
-	pixvalue1 = pixel1[pixelN];
-	pixvalue2 = pixel2[pixelN];
-	out_pix2 = out_pix;
-	for (jj = 0; jj < expand_out; jj++, out_pix2+=2*(dx-expand_out)) {
-	  for (ii = 0; ii < expand_out; ii++, out_pix2+=2) {
-	    out_pix2[0] = pixvalue1; 
-	    out_pix2[1] = pixvalue2; 
-	  }
-	}
-      }
-    }
-    out_pix -= 2*dropback;
-    
-    /**** fill in area to the right of the picture ****/
-    for (jj = 0; jj < expand_out; jj++) {
-      out_pix2 = out_pix + 2*jj*dx;
-      for (i = i_end; i < dx; i++, out_pix2+=2) {
-	out_pix2[0] = back1;
-	out_pix2[1] = back2;
-      }
-    }
-  } 
-  
-  out_pix = &data[2*j_end*dx];
-  /**** fill in top area ****/
-  for (j = 0; j < (dy - j_end); j++) {
-    for (i = 0; i < dx; i++, out_pix+=2) { 
-      out_pix[0] = back1;
-      out_pix[1] = back2;
-    }
-  }
-
-  image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
-					image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 16, 0);
-  
-# endif
-}
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/CreateZoom24.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/CreateZoom24.c	(revision 25206)
+++ 	(revision )
@@ -1,178 +1,0 @@
-# include "Ximage.h"
-
-void CreateZoom24 (KapaImageWidget *image, Graphic *graphic, double x, double y) {
-
-# if (0)
-  int i, j, ii, jj, extra;
-  int i_start, i_end, j_start, j_end;
-  int dropback;  /* this is a bit of a kludge... */
-  int dx, dy, DX, DY, pixelN;
-  double expand, zoomscale, Rx, Ry;
-  int expand_in, expand_out;
-  unsigned char *out_pix, *out_pix2, *data;
-  float *imdata, *in_pix, *in_pix2;
-  unsigned char pixel1[256], pixel2[256], pixel3[256];
-  unsigned char pixvalue1, pixvalue2, pixvalue3;
-  unsigned long back;
-  unsigned char back1, back2, back3;
-
-  dx = image[0].zoom.dx;
-  dy = image[0].zoom.dy;
-  extra = 4 - (dx * 3) % 4;
-
-  if (image[0].image[0].matrix.size == 0) {  /* create a test pattern */
-    REALLOCATE (image[0].zoom.data, char, dy*(3*dx+extra));
-    bzero (image[0].zoom.data, image[0].zoom.dx*image[0].zoom.dy);
-    image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
-				       image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 32, 0);
-    return;
-  }
-
-  for (i = 0; i < 256; i++) { /* set up pixel array */
-    pixel1[i] = 0x0000ff &  graphic[0].cmap[i].pixel;
-    pixel2[i] = 0x0000ff & (graphic[0].cmap[i].pixel >> 8);
-    pixel3[i] = 0x0000ff & (graphic[0].cmap[i].pixel >> 16);
-  }
-  back = graphic[0].back;
-  back1 = 0x0000ff & back;
-  back2 = 0x0000ff & (back >> 8);
-  back3 = 0x0000ff & (back >> 16);
-
-  // define the color transform parameters
-  MaxValue = graphic[0].Npixels - 1;
-  if (image[0].image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].image[0].range;
-    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
-  } else {
-    slope = 1.0;
-    start = image[0].image[0].zero;
-  }
-
-  zoomscale = MAX (5, image[0].expand + 5);
-  expand = 1 / zoomscale;
-  expand_out = (int) zoomscale;
-  expand_in  = 1;
-
-  DX = image[0].image[0].matrix.Naxis[0];
-  DY = image[0].image[0].matrix.Naxis[1];
-  Rx = x - expand*(int)(0.5*(dx + 1)) + 1;
-  Ry = y - expand*(int)(0.5*(dy + 1)) + 1;
-
-  i_start = MIN (MAX (-Rx / expand, (1 - FRAC(Rx)) / expand), dx - expand_out + 1);
-  j_start = MIN (MAX (-Ry / expand, (1 - FRAC(Ry)) / expand), dy - expand_out + 1);
-  i_end   = MAX (MIN ((DX-Rx) / expand, dx - expand_out + 1), 0);
-  j_end   = MAX (MIN ((DY-Ry) / expand, dy - expand_out + 1), 0);
-  dropback = expand_out - (i_end - i_start) % expand_out;
-  if ((i_end - i_start) % expand_out == 0) dropback = 0;
-
-  data = out_pix = (unsigned char *) image[0].zoom.data;
-  imdata  = (float *) image[0].image[0].matrix.buffer;
-  in_pix  = &imdata[DX*(int)MAX(Ry,0) + (int)MAX(Rx,0)];
-
-  /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
-
-  if ((i_end < i_start) || (j_end < j_start)) {
-    for (j = 0; j < dx*dy; j++, out_pix++) 
-      *out_pix = back;
-    return;
-  } 
-  
-  /**** fill in bottom area ****/
-  for (j = 0; j < j_start; j++) {
-    for (i = 0; i < dx; i++, out_pix+=3) {
-      out_pix[0] = back1;
-      out_pix[1] = back2;
-      out_pix[2] = back3;
-    }
-    out_pix += extra;
-  }
-
-  for (j = j_start; j < j_end; j+= expand_out, in_pix += expand_in*DX) {
-    out_pix = &data[j*(3*dx+extra)];
-
-    /**** fill in area to the left of the picture ****/
-    for (jj = 0; jj < expand_out; jj++) { 
-      out_pix2 = out_pix + jj*(3*dx + extra);
-      for (i = 0; i < i_start; i++, out_pix2+=3) {
-	out_pix2[0] = back1;
-	out_pix2[1] = back2;
-	out_pix2[2] = back3;
-      }
-    }
-    out_pix += 3*i_start;
-    
-    /*** fill in the picture region ***/
-    in_pix2 = in_pix;
-    if (expand_out == 1) {
-      for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix+=3) {
-	pixelN = PixelLookup(*in_pix2);
-	out_pix[0] = pixel1[pixelN];
-	out_pix[1] = pixel2[pixelN];
-	out_pix[2] = pixel3[pixelN];
-      }
-    } else {
-      for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= 3*expand_out) { 
-	pixelN   = PixelLookup(*in_pix2);
-	pixvalue1 = pixel1[pixelN];
-	pixvalue2 = pixel2[pixelN];
-	pixvalue3 = pixel3[pixelN];
-	out_pix2 = out_pix;
-	for (jj = 0; jj < expand_out; jj++, out_pix2+=3*(dx-expand_out)+extra) {
-	  for (ii = 0; ii < expand_out; ii++, out_pix2+=3) {
-	    out_pix2[0] = pixvalue1; 
-	    out_pix2[1] = pixvalue2; 
-	    out_pix2[2] = pixvalue3; 
-	  }
-	}
-      }
-    }
-    out_pix -= 3*dropback;
-    
-    /**** fill in area to the right of the picture ****/
-    for (jj = 0; jj < expand_out; jj++) {
-      out_pix2 = out_pix + jj*(3*dx+extra);
-      for (i = i_end; i < dx; i++, out_pix2+=3) {
-	out_pix2[0] = back1;
-	out_pix2[1] = back2;
-	out_pix2[2] = back3;
-      }
-    }
-  } 
-  
-  /*
-  if ((j_end - j_start) % expand_out > 0)
-    out_pix -= (expand_out - (j_end - j_start) % expand_out);
-  */
-
-  out_pix = &data[j_end*(3*dx+extra)];
-  /**** fill in top area ****/
-  for (j = 0; j < (dy - j_end); j++) {
-    for (i = 0; i < dx; i++, out_pix+=3) { 
-      out_pix[0] = back1;
-      out_pix[1] = back2;
-      out_pix[2] = back3;
-    }
-    out_pix+=extra;
-  }
-
-  /*
-  out_pix = (unsigned char *) image[0].zoom.data;
-  for (i = 0; i < dx*dy; i++) {
-    out_pix[3*i + 0] = back1;
-    out_pix[3*i + 1] = back2;
-    out_pix[3*i + 2] = back3;
-  }
-  for (j = 0; j < dy/2; j++) {
-    for (i = 0; i < dx; i++) {
-      out_pix[j*(extra + 3*dx) + 3*i + 0] = pixel1[10];
-      out_pix[j*(extra + 3*dx) + 3*i + 1] = pixel2[10];
-      out_pix[j*(extra + 3*dx) + 3*i + 2] = pixel3[10];
-    }
-
-  }
-  */
-  image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, 24, ZPixmap, 0, 
-					image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 32, 0);
-  
-# endif
-}
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/CreateZoom32.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/CreateZoom32.c	(revision 25206)
+++ 	(revision )
@@ -1,138 +1,0 @@
-# include "Ximage.h"
-
-void CreateZoom32 (KapaImageWidget *image, Graphic *graphic, double x, double y) {
-
-  int i, j, ii, jj;
-  int i_start, i_end, j_start, j_end;
-  int dropback;  /* this is a bit of a kludge... */
-  int dx, dy, DX, DY;
-  double expand, Ix, Iy;
-  int expand_in, expand_out;
-  unsigned int *out_pix, *out_pix2;
-  unsigned short *in_pix, *in_pix2;
-  unsigned long *pixel, pixvalue;
-  unsigned long back;
-
-  if (image[0].image[0].matrix.size == 0) {  /* create a test pattern */
-    REALLOCATE (image[0].zoom.data, char, 4*image[0].zoom.dx*image[0].zoom.dy);
-    image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
-				       image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 32, 0);
-    return;
-  }
-
-  ALLOCATE (pixel, unsigned long, graphic[0].Npixels);
-
-  // local array for pixel values
-  for (i = 0; i < graphic[0].Npixels; i++) { 
-    pixel[i] = graphic[0].cmap[i].pixel;
-  }
-  back = graphic[0].back;
-
-  // set up expansions
-  assert ((image[0].zoom.expand >= 1) || (image[0].zoom.expand <= -2));
-  expand = expand_in = expand_out = 1.0;
-  if (image[0].zoom.expand > 0) {
-    expand = 1 / (1.0*image[0].zoom.expand);
-    expand_out = image[0].zoom.expand;
-    expand_in  = 1;
-  }
-  if (image[0].zoom.expand < 0) {
-    expand = fabs((double)image[0].zoom.expand);
-    expand_out = 1;
-    expand_in  = -image[0].zoom.expand;
-  }
-
-  // define the image sizes
-  dx = image[0].zoom.dx;
-  dy = image[0].zoom.dy;
-  DX = image[0].image[0].matrix.Naxis[0];
-  DY = image[0].image[0].matrix.Naxis[1];
-  
-  // x, y are the closest lit screen pixel to 0,0
-  Picture_Lower (&i_start, &j_start, &image[0].image[0].matrix, &image[0].zoom);
-
-  // x, y are the closest lit screen pixel to dx, dy
-  Picture_Upper (&i_end, &j_end, &image[0].image[0].matrix, &image[0].zoom);
-
-  // Ix,Iy are the first displayed image pixel
-  Picture_to_Image (&Ix, &Iy, i_start, j_start, &image[0].zoom);
-
-  dropback = expand_out - (i_end - i_start) % expand_out;
-  if ((i_end - i_start) % expand_out == 0) dropback = 0;
-
-  out_pix = (unsigned int *) image[0].zoom.data;
-  in_pix  = &image[0].pixmap[DX*(int)MAX(Iy,0) + (int)MAX(Ix,0)];
-
-  /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
-
-  // XXX can we just drop this?
-  if ((i_end < i_start) || (j_end < j_start)) {
-    for (j = 0; j < dx*dy; j++, out_pix++) 
-      *out_pix = back;
-    return;
-  } 
-
-  /**** fill in bottom area ****/
-  for (j = 0; j < dx*j_start; j++, out_pix++) {
-    *out_pix = back;
-  }
-
-  for (j = j_start; j < j_end; j+= expand_out, out_pix+=(expand_out-1)*dx, in_pix += expand_in*DX) {
-
-    /**** fill in area to the left of the picture ****/
-    for (jj = 0; (i_start > 0) && (jj < expand_out); jj++) { 
-      out_pix2 = out_pix + jj*dx;
-      for (i = 0; i < i_start; i++, out_pix2++) {
-	*out_pix2 = back;
-      }
-    }
-    out_pix += i_start;
-    
-    /*** fill in the picture region ***/
-    in_pix2 = in_pix;
-    if (expand_out == 1) {
-      for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix++) {
-	*out_pix = pixel[*in_pix2];
-      }
-    } else {
-      // equiv to : out_pix += (i_end - i_start) + [expand_out - (i_end - i_start) % expand_out]
-      for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= expand_out) { 
-	pixvalue = pixel[*in_pix2];
-	out_pix2 = out_pix;
-	for (jj = 0; jj < expand_out; jj++, out_pix2+=(dx-expand_out)) {
-	  for (ii = 0; ii < expand_out; ii++, out_pix2++) {
-	    *out_pix2 = pixvalue; 
-	  }
-	}
-      }
-    }
-    out_pix -= dropback;
-    
-    /**** fill in area to the right of the picture ****/
-    for (jj = 0; jj < expand_out; jj++) {
-      out_pix2 = out_pix + jj*dx;
-      for (i = i_end; i < dx; i++, out_pix2++) {
-	*out_pix2 = back;
-      }
-    }
-    out_pix += (dx - i_end);
-    assert (out_pix - (unsigned int *)image[0].zoom.data <= dx*dy);
-  } 
-  assert (out_pix - (unsigned int *)image[0].zoom.data <= dx*dy);
-  
-  if ((j_end - j_start) % expand_out > 0)
-    out_pix -= (expand_out - (j_end - j_start) % expand_out);
-  
-  assert (out_pix - (unsigned int *)image[0].zoom.data <= dx*dy);
-
-  /**** fill in top area ****/
-  for (j = 0; (j < dx*(dy - j_end)) && (out_pix - (unsigned int *)image[0].zoom.data < dx*dy); j++, out_pix++) { 
-    *out_pix = back;
-  }
-  assert (out_pix - (unsigned int *)image[0].zoom.data <= dx*dy);
-
-  image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
-					image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 32, 0);
-  
-  free (pixel);
-}
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/CreateZoom8.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/CreateZoom8.c	(revision 25206)
+++ 	(revision )
@@ -1,130 +1,0 @@
-# include "Ximage.h"
-
-void CreateZoom8 (KapaImageWidget *image, Graphic *graphic, double x, double y) {
-
-# if (0)
-  int i, j, ii, jj;
-  int i_start, i_end, j_start, j_end;
-  int dropback;  /* this is a bit of a kludge... */
-  int dx, dy, DX, DY, pixelN;
-  double expand, zoomscale, Rx, Ry;
-  int expand_in, expand_out;
-  unsigned char *out_pix, *out_pix2;
-  float *imdata, *in_pix, *in_pix2;
-  unsigned long pixel[256], pixvalue;
-  unsigned long back;
-
-  if (image[0].image[0].matrix.size == 0) {  /* create a test pattern */
-    REALLOCATE (image[0].zoom.data, char, image[0].zoom.dx*image[0].zoom.dy);
-    bzero (image[0].zoom.data, image[0].zoom.dx*image[0].zoom.dy);
-    image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
-				       image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 8, 0);
-    return;
-  }
-
-  for (i = 0; i < 256; i++) { /* set up pixel array */
-    pixel[i] = graphic[0].cmap[i].pixel;
-  }
-  back = graphic[0].back;
-
-  // define the color transform parameters
-  MaxValue = graphic[0].Npixels - 1;
-  if (image[0].image[0].range != 0.0) {
-    slope = graphic[0].Npixels / image[0].image[0].range;
-    start = graphic[0].Npixels * image[0].image[0].zero / image[0].image[0].range;
-  } else {
-    slope = 1.0;
-    start = image[0].image[0].zero;
-  }
-
-  zoomscale = MAX (5, image[0].expand + 5);
-  expand = 1 / zoomscale;
-  expand_out = (int) zoomscale;
-  expand_in  = 1;
-
-  dx = image[0].zoom.dx;
-  dy = image[0].zoom.dy;
-  DX = image[0].image[0].matrix.Naxis[0];
-  DY = image[0].image[0].matrix.Naxis[1];
-  Rx = x - expand*(int)(0.5*(dx + 1)) + 1;
-  Ry = y - expand*(int)(0.5*(dy + 1)) + 1;
-
-  i_start = MIN (MAX (-Rx / expand, (1 - FRAC(Rx)) / expand), dx - expand_out + 1);
-  j_start = MIN (MAX (-Ry / expand, (1 - FRAC(Ry)) / expand), dy - expand_out + 1);
-  i_end   = MAX (MIN ((DX-Rx) / expand, dx - expand_out + 1), 0);
-  j_end   = MAX (MIN ((DY-Ry) / expand, dy - expand_out + 1), 0);
-  dropback = expand_out - (i_end - i_start) % expand_out;
-  if ((i_end - i_start) % expand_out == 0) dropback = 0;
-
-  out_pix = (unsigned char *) image[0].zoom.data;
-  imdata  = (float *) image[0].image[0].matrix.buffer;
-  in_pix  = &imdata[DX*(int)MAX(Ry,0) + (int)MAX(Rx,0)];
-
-  /********** below we do the mapping from buffer pixels (in) to picture pixels (out) **********/
-
-  if ((i_end < i_start) || (j_end < j_start)) {
-    for (j = 0; j < dx*dy; j++, out_pix++) 
-      *out_pix = back;
-    return;
-  } 
-  
-  /**** fill in bottom area ****/
-  for (j = 0; j < dx*j_start; j++, out_pix++) 
-    *out_pix = back;
-  
-  for (j = j_start; j < j_end; j+= expand_out, out_pix+=(expand_out-1)*dx, in_pix += expand_in*DX) {
-
-    /**** fill in area to the left of the picture ****/
-    for (jj = 0; jj < expand_out; jj++) { 
-      out_pix2 = out_pix + jj*dx;
-      for (i = 0; i < i_start; i++, out_pix2++) {
-	*out_pix2 = back;
-      }
-    }
-    out_pix += i_start;
-    
-    /*** fill in the picture region ***/
-    in_pix2 = in_pix;
-    if (expand_out == 1) {
-      for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix++) {
-	pixelN = PixelLookup(*in_pix2);
-	*out_pix = pixel[pixelN];
-      }
-    } else {
-      for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= expand_out) { 
-	pixelN   = PixelLookup(*in_pix2);
-	pixvalue = pixel[pixelN];
-	out_pix2 = out_pix;
-	for (jj = 0; jj < expand_out; jj++, out_pix2+=(dx-expand_out)) {
-	  for (ii = 0; ii < expand_out; ii++, out_pix2++) {
-	    *out_pix2 = pixvalue;
-	  }
-	}
-      }
-    }
-    out_pix -= dropback;
-    
-    /**** fill in area to the right of the picture ****/
-    for (jj = 0; jj < expand_out; jj++) {
-      out_pix2 = out_pix + jj*dx;
-      for (i = i_end; i < dx; i++, out_pix2++) {
-	*out_pix2 = back;
-      }
-    }
-    out_pix += (dx - i_end);
-    
-  } 
-  
-  if ((j_end - j_start) % expand_out > 0)
-    out_pix -= expand_out - (j_end - j_start) % expand_out;
-  
-  /**** fill in top area ****/
-  for (j = 0; (j < dx*(dy - j_end)) && (out_pix - (unsigned char *) image[0].zoom.data < dx*dy); j++, out_pix++) { 
-    *out_pix = back;
-  }
-
-  image[0].zoom.pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
-					image[0].zoom.data, image[0].zoom.dx, image[0].zoom.dy, 8, 0);
-  
-# endif
-}
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/CursorOps.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/CursorOps.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/CursorOps.c	(revision 25766)
@@ -2,4 +2,5 @@
 
 // input coordinates are relative to the picture bounding box
+// XXX pre-calculate fexpand, Xc, Yc when expand is set?
 void Picture_to_Image (double *x1, double *y1, double x2, double y2, Picture *picture) {
 
@@ -14,10 +15,14 @@
   
   // pixel coordinates in picture frame
-  dx = expand*(x2 - 0.5*picture[0].dx);
-  dy = expand*(y2 - 0.5*picture[0].dy);
+  dx = expand*(x2 - (int)(0.5*picture[0].dx));
+  dy = expand*(y2 - (int)(0.5*picture[0].dy));
+
+  // set the true center (image and screen pixel boundaries must be aligned)
+  // Xc = (int)(picture[0].Xc / expand) * expand;
+  // Yc = (int)(picture[0].Yc / expand) * expand;
 
   // picture[0].X,Y is the image coordinate in the center of the picture
-  *x1 = picture[0].flipx ? picture[0].X - dx : picture[0].X + dx;
-  *y1 = picture[0].flipy ? picture[0].Y - dy : picture[0].Y + dy;
+  *x1 = picture[0].flipx ? picture[0].Xc - dx : picture[0].Xc + dx;
+  *y1 = picture[0].flipy ? picture[0].Yc - dy : picture[0].Yc + dy;
 }
 
@@ -46,10 +51,14 @@
   }
   
+  // set the true center (image and screen pixel boundaries must be aligned)
+  // Xc = ((int)(picture[0].Xc * expand)) / expand;
+  // Yc = ((int)(picture[0].Yc * expand)) / expand;
+
   // pixel coordinates in picture frame
-  dx = picture[0].flipx ? picture[0].X - x2 : x2 - picture[0].X;
-  dy = picture[0].flipy ? picture[0].Y - y2 : y2 - picture[0].Y;
+  dx = picture[0].flipx ? picture[0].Xc - x2 : x2 - picture[0].Xc;
+  dy = picture[0].flipy ? picture[0].Yc - y2 : y2 - picture[0].Yc;
     
-  *x1 = expand*dx + 0.5*picture[0].dx;
-  *y1 = expand*dy + 0.5*picture[0].dy;
+  *x1 = expand*dx + (int)(0.5*picture[0].dx);
+  *y1 = expand*dy + (int)(0.5*picture[0].dy);
 }
 
@@ -66,5 +75,5 @@
 
 // input coordinates are relative to the picture bounding box
-void Picture_Lower (int *i_start, int *j_start, Matrix *matrix, Picture *picture) {
+void Picture_Lower (int *i_start, int *j_start, int *I_start, int *J_start, Matrix *matrix, Picture *picture) {
 
   double Ix, Iy, Sx, Sy;
@@ -72,8 +81,4 @@
   // Ix, Iy are the image coordinates of the specified screen pixel
   Picture_to_Image (&Ix, &Iy, 0.0, 0.0, picture);
-
-  // Ix, Iy are now limited to valid image coordinates
-  Ix = MIN (MAX (Ix, 0), matrix[0].Naxis[0]);
-  Iy = MIN (MAX (Iy, 0), matrix[0].Naxis[1]);
 
   // round up (down) to nearest pixel boundary
@@ -84,4 +89,12 @@
     Iy = picture[0].flipy ? (int)(Iy) : (int)(Iy) + 1;
   }
+
+  // Ix, Iy are now limited to valid image coordinates
+  Ix = MIN (MAX (Ix, 0), matrix[0].Naxis[0]);
+  Iy = MIN (MAX (Iy, 0), matrix[0].Naxis[1]);
+
+  // I_start, J_start are the first displayed image pixel 
+  *I_start = Ix;
+  *J_start = Iy;
 
   // Sx, Sy are the screen coordinates of the Ix,Iy pixel
@@ -94,6 +107,7 @@
   
 // input coordinates are relative to the picture bounding box
-void Picture_Upper (int *i_end, int *j_end, Matrix *matrix, Picture *picture) {
+void Picture_Upper (int *i_end, int *j_end, int i_start, int j_start, Matrix *matrix, Picture *picture) {
 
+  int nExtra;
   double Ix, Iy, Sx, Sy;
 
@@ -101,15 +115,19 @@
   Picture_to_Image (&Ix, &Iy, picture[0].dx, picture[0].dy, picture);
 
+  // round down (up) to nearest pixel boundary
+  if (Ix > (int)(Ix)) {
+    Ix = picture[0].flipx ? (int)(Ix) + 1: (int)(Ix);
+  }
+  if (Iy > (int)(Iy)) {
+    Iy = picture[0].flipy ? (int)(Iy) + 1: (int)(Iy);
+  }
+
   // Ix, Iy are now limited to valid image coordinates
   Ix = MIN (MAX (Ix, 0), matrix[0].Naxis[0]);
   Iy = MIN (MAX (Iy, 0), matrix[0].Naxis[1]);
 
-  // round down (up) to nearest pixel boundary
-  if (Ix > (int)(Ix)) {
-    Ix = picture[0].flipx ? (int)(Ix) + 1 : (int)(Ix);
-  }
-  if (Iy > (int)(Iy)) {
-    Iy = picture[0].flipy ? (int)(Iy) + 1: (int)(Iy);
-  }
+  // I_end, J_end are the last displayed image pixel 
+  // *I_end = Ix;
+  // *J_end = Iy;
 
   // Sx, Sy are the screen coordinates of the Ix,Iy pixel
@@ -119,3 +137,11 @@
   *i_end = MIN (MAX (Sx, 0), picture[0].dx);
   *j_end = MIN (MAX (Sy, 0), picture[0].dy);
+
+  // round off error can leave us with a small number of extra pixels here.
+  if (picture[0].expand > 1) {
+    nExtra = (*i_end - i_start) % picture[0].expand;
+    *i_end -= nExtra;
+    nExtra = (*j_end - j_start) % picture[0].expand;
+    *j_end -= nExtra;
+  }
 }
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/DragColorbar.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/DragColorbar.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/DragColorbar.c	(revision 25766)
@@ -10,5 +10,5 @@
   int             xstatus, Npix, center;
 
-  if (!graphic[0].visualclass) return;
+  if (!graphic[0].dynamicColors) return;
 
   X = mouse_event[0].x;
@@ -79,5 +79,5 @@
   XColor cmap[256];
 
-  if (!graphic[0].visualclass) return;
+  if (!graphic[0].dynamicColors) return;
 
   for (i = 0; i < graphic[0].Npixels; i++) {
@@ -88,4 +88,5 @@
       cmap[i].blue = graphic[0].cmap[0].blue;
       cmap[i].green = graphic[0].cmap[0].green;
+      cmap[i].flags = DoRed | DoGreen | DoBlue;
     }
     else {
@@ -94,4 +95,5 @@
 	cmap[i].blue = graphic[0].cmap[graphic[0].Npixels-1].blue;
 	cmap[i].green = graphic[0].cmap[graphic[0].Npixels-1].green;
+	cmap[i].flags = DoRed | DoGreen | DoBlue;
       }
       else {
@@ -99,4 +101,5 @@
 	cmap[i].blue = graphic[0].cmap[j].blue;
 	cmap[i].green = graphic[0].cmap[j].green;
+	cmap[i].flags = DoRed | DoGreen | DoBlue;
       }
     }
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/Image.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/Image.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/Image.c	(revision 25766)
@@ -48,18 +48,18 @@
 
   // set the center and expansion for the pictures:
-  image[0].picture.X      = 0.0;
-  image[0].picture.Y      = 0.0;
+  image[0].picture.Xc     = 0.0;
+  image[0].picture.Yc     = 0.0;
   image[0].picture.expand = 1;
   image[0].picture.flipx  = FALSE;
   image[0].picture.flipy  = FALSE;
 
-  image[0].zoom.X      	  = 0.0;
-  image[0].zoom.Y      	  = 0.0;
-  image[0].zoom.expand 	  = +5;
+  image[0].zoom.Xc     	  = 0.0;
+  image[0].zoom.Yc     	  = 0.0;
+  image[0].zoom.expand 	  = 5;
   image[0].zoom.flipx  	  = FALSE;
   image[0].zoom.flipy  	  = FALSE;
 
-  image[0].wide.X      	  = 0.0;
-  image[0].wide.Y      	  = 0.0;
+  image[0].wide.Xc     	  = 0.0;
+  image[0].wide.Yc     	  = 0.0;
   image[0].wide.expand 	  = -5;
   image[0].wide.flipx  	  = FALSE;
@@ -144,8 +144,10 @@
 		  image[0].picture.dx+1, image[0].picture.dy+1);
   
-  XPutImage (graphic[0].display, graphic[0].window, graphic[0].gc,
-	     image[0].picture.pix, 0, 0, 
-	     image[0].picture.x + 1, image[0].picture.y + 1, 
-	     image[0].picture.dx, image[0].picture.dy);
+  if (image[0].picture.pix) {
+    XPutImage (graphic[0].display, graphic[0].window, graphic[0].gc,
+	       image[0].picture.pix, 0, 0, 
+	       image[0].picture.x + 1, image[0].picture.y + 1, 
+	       image[0].picture.dx, image[0].picture.dy);
+  }
 
   for (i = 0; i < NOVERLAYS; i++) {
@@ -156,13 +158,16 @@
 
   if (image[0].location) {
-    XPutImage (graphic[0].display, graphic[0].window, graphic[0].gc,
-	       image[0].cmapbar.pix, 0, 0, 
-	       image[0].cmapbar.x, image[0].cmapbar.y, 
-	       image[0].cmapbar.dx, image[0].cmapbar.dy);
-
-    XPutImage (graphic[0].display, graphic[0].window, graphic[0].gc,
-	       image[0].wide.pix, 0, 0, 
-	       image[0].wide.x, image[0].wide.y, 
-	       image[0].wide.dx, image[0].wide.dy);
+    if (image[0].cmapbar.pix) {
+      XPutImage (graphic[0].display, graphic[0].window, graphic[0].gc,
+		 image[0].cmapbar.pix, 0, 0, 
+		 image[0].cmapbar.x, image[0].cmapbar.y, 
+		 image[0].cmapbar.dx, image[0].cmapbar.dy);
+    }
+    if (image[0].wide.pix) {
+	XPutImage (graphic[0].display, graphic[0].window, graphic[0].gc,
+		   image[0].wide.pix, 0, 0, 
+		   image[0].wide.x, image[0].wide.y, 
+		   image[0].wide.dx, image[0].wide.dy);
+    }
 
     CrossHairs (graphic, &image[0].zoom);
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/InterpretKeys.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/InterpretKeys.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/InterpretKeys.c	(revision 25766)
@@ -93,5 +93,5 @@
       SetColorScale (graphic, image);
       Remap (graphic, image);
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y, 0);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc, 0);
       break;
 
@@ -100,5 +100,5 @@
       SetColorScale (graphic, image);
       Remap (graphic, image);
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y, 0);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc, 0);
       break;
 
@@ -107,5 +107,5 @@
       SetColorScale (graphic, image);
       Remap (graphic, image);
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y, 0);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc, 0);
       break;
 
@@ -113,9 +113,11 @@
     case XK_Home:
       image[0].picture.expand = 1;
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y, 0);
+      image[0].zoom.expand = 5;
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc, 0);
       break;
     case XK_KP_End:
     case XK_End:
       image[0].picture.expand = 1;
+      image[0].zoom.expand = 5;
       Reorient (graphic, image, 0.5*image[0].image[0].matrix.Naxis[0], 0.5*image[0].image[0].matrix.Naxis[1], 0);
       break;
@@ -128,25 +130,25 @@
     case XK_Prior:
     case XK_KP_Prior:
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y, +1);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc, +1);
       break;
     case XK_Next:
     case XK_KP_Next:
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y, -1);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc, -1);
       break;
     case XK_Up:
     case XK_KP_Up:
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y + offset, 0);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc + offset, 0);
       break;
     case XK_Down:
     case XK_KP_Down:
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y - offset, 0);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc - offset, 0);
       break;
     case XK_Left:
     case XK_KP_Left:
-      Reorient (graphic, image, image[0].picture.X + offset, image[0].picture.Y, 0);
+      Reorient (graphic, image, image[0].picture.Xc + offset, image[0].picture.Yc, 0);
       break;
     case XK_Right:
     case XK_KP_Right:
-      Reorient (graphic, image, image[0].picture.X - offset, image[0].picture.Y, 0);
+      Reorient (graphic, image, image[0].picture.Xc - offset, image[0].picture.Yc, 0);
       break;
 
@@ -160,5 +162,5 @@
       SetColorScale (graphic, image);
       Remap (graphic, image);
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y, 0);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc, 0);
       break;
     case XK_KP_Subtract:
@@ -171,5 +173,5 @@
       SetColorScale (graphic, image);
       Remap (graphic, image);
-      Reorient (graphic, image, image[0].picture.X, image[0].picture.Y, 0);
+      Reorient (graphic, image, image[0].picture.Xc, image[0].picture.Yc, 0);
       break;
 
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/JPEGit24.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/JPEGit24.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/JPEGit24.c	(revision 25766)
@@ -22,4 +22,5 @@
   int ii, i, j;
   int i_start, i_end, j_start, j_end;
+  int I_start, J_start;
   int dropback;  /* this is a bit of a kludge... */
   int dx, dy, DX, DY, inDX, inDY;
@@ -95,17 +96,17 @@
   DY = image[0].image[0].matrix.Naxis[1];
 
-  // x, y are the closest lit screen pixel to 0,0
-  Picture_Lower (&i_start, &j_start, &image[0].image[0].matrix, &image[0].picture);
-
-  // x, y are the closest lit screen pixel to dx, dy
-  Picture_Upper (&i_end, &j_end, &image[0].image[0].matrix, &image[0].picture);
-
-  if (i_end < i_start) MY_SWAP_INT (i_start, i_end);
-  if (j_end < j_start) MY_SWAP_INT (j_start, j_end);
-
-  // Ix,Iy are the first displayed image pixel
-  Picture_to_Image (&Ix, &Iy, i_start, j_start, &image[0].picture);
-  Ix = MIN (MAX (0, Ix), DX - 1);
-  Iy = MIN (MAX (0, Iy), DY - 1);
+  // i_start, j_start are the closest lit screen pixel to 0,0
+  // I_start, J_start are the image pixel corresponding to i_start, j_start
+  Picture_Lower (&i_start, &j_start, &I_start, &J_start, &image[0].image[0].matrix, &image[0].picture);
+
+  // i_end, j_end are the closest lit screen pixel to dx, dy
+  // I_end, J_end are the image pixel corresponding to i_end, j_end
+  Picture_Upper (&i_end, &j_end, i_start, j_start, &image[0].image[0].matrix, &image[0].picture);
+
+  assert (i_start <= i_end);
+  assert (j_start <= j_end);
+
+  Ix = image[0].picture.flipx ? I_start - 1 : I_start;
+  Iy = image[0].picture.flipy ? J_start - 1 : J_start;
 
   inDX = image[0].picture.flipx ? -1 : +1;
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/LoadPicture.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/LoadPicture.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/LoadPicture.c	(revision 25766)
@@ -25,6 +25,7 @@
   Yoffset = 0.0;
   if (image[0].image[0].matrix.size) {
-    Xoffset = image[0].picture.X - 0.5*image[0].image[0].matrix.Naxis[0];
-    Yoffset = image[0].picture.Y - 0.5*image[0].image[0].matrix.Naxis[1];
+    // XXX enforce int center here?
+    Xoffset = image[0].picture.Xc - 0.5*image[0].image[0].matrix.Naxis[0];
+    Yoffset = image[0].picture.Yc - 0.5*image[0].image[0].matrix.Naxis[1];
   }
 
@@ -49,6 +50,6 @@
 
   // reference point for image is the center pixel
-  image[0].picture.X = 0.5*header.Naxis[0] + Xoffset;
-  image[0].picture.Y = 0.5*header.Naxis[1] + Yoffset;
+  image[0].picture.Xc = 0.5*header.Naxis[0] + Xoffset;
+  image[0].picture.Yc = 0.5*header.Naxis[1] + Yoffset;
 
   // choose expand for wide to guarantee we fit:
@@ -59,6 +60,6 @@
     image[0].wide.expand = 1.0 / wx;
   }    
-  image[0].wide.X = 0.5*header.Naxis[0];
-  image[0].wide.Y = 0.5*header.Naxis[1];
+  image[0].wide.Xc = 0.5*header.Naxis[0];
+  image[0].wide.Yc = 0.5*header.Naxis[1];
 
   fcntl (sock, F_SETFL, O_NONBLOCK);  
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/MakeColormap.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/MakeColormap.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/MakeColormap.c	(revision 25766)
@@ -2,4 +2,5 @@
 
 static char default_cmap[] = "grayscale";
+// static char default_cmap[] = "heat";
 
 void MakeColormap (int argc, char **argv) {
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/PSOverlay.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/PSOverlay.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/PSOverlay.c	(revision 25766)
@@ -80,11 +80,11 @@
 	  double sn = sin(angle);
 	  x0 = X + pX*dX*cs;
-	  y0 = Y + pY*dX*sn;
+	  y0 = Y - pY*dX*sn;
 	  // XXX dt should be based on the size of the ellipse...
 	  // 0.10 -> 60 segments on the ellipse
 	  # define DT 0.1
 	  for (t = DT; t < 2*M_PI + DT; t+=DT) {
-	    x1 = X + pX*dX*cos(t)*cs - pX*dY*sin(t)*sn;
-	    y1 = Y + pY*dX*cos(t)*sn + pY*dY*sin(t)*cs;
+	    x1 = X + pX*dX*cos(t)*cs + pX*dY*sin(t)*sn;
+	    y1 = Y - pY*dX*cos(t)*sn + pY*dY*sin(t)*cs;
 	    fprintf (f, " %6.1f %6.1f %6.1f %6.1f L\n", x0 + extra, y0 + extra, x1 + extra, y1 + extra);
 	    x0 = x1;
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/PaintOverlay.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/PaintOverlay.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/PaintOverlay.c	(revision 25766)
@@ -9,5 +9,5 @@
  
   XSetForeground (graphic[0].display, graphic[0].gc, image[0].overlay[N].color);
-  XSetLineAttributes (graphic->display, graphic->gc, 2, LineSolid, CapNotLast, JoinMiter);
+  XSetLineAttributes (graphic->display, graphic->gc, 1, LineSolid, CapNotLast, JoinMiter);
   
   expand = 1.0;
@@ -72,11 +72,11 @@
 	  double sn = sin(angle);
 	  x0 = X + pX*dx*cs;
-	  y0 = Y - pY*dx*sn;
+	  y0 = Y + pY*dx*sn;
 	  // XXX dt should be based on the size of the ellipse...
 	  // 0.10 -> 60 segments on the ellipse
 	  # define DT 0.1
 	  for (t = DT; t < 2*M_PI + DT; t+=DT) {
-	    x1 = X + pX*dx*cos(t)*cs + pX*dy*sin(t)*sn;
-	    y1 = Y - pY*dx*cos(t)*sn + pY*dy*sin(t)*cs;
+	    x1 = X + pX*dx*cos(t)*cs - pX*dy*sin(t)*sn;
+	    y1 = Y + pY*dx*cos(t)*sn + pY*dy*sin(t)*cs;
 	    XDrawLine (graphic[0].display, graphic[0].window, graphic[0].gc, x0, y0, x1, y1);
 	    x0 = x1;
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/Relocate.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/Relocate.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/Relocate.c	(revision 25766)
@@ -0,0 +1,30 @@
+# include "Ximage.h"
+
+// XXX Should there be a base command + KiiMessage command?
+int Relocate (int sock) {
+ 
+  int i, Nsection;
+  int x, y, dX, dY;
+  Graphic *graphic;
+  Section *section;
+
+  graphic = GetGraphic();
+
+  KiiScanMessage (sock, "%d %d", &x, &y);
+
+  if (!USE_XWINDOW) return (TRUE);
+
+  dX = DisplayWidth  (graphic->display, graphic->screen);
+  dY = DisplayHeight (graphic->display, graphic->screen);
+
+  // let's not lose the window
+  x = MAX(0, MIN(x, dX - 10)); 
+  y = MAX(0, MIN(y, dY - 10)); 
+
+  XMoveWindow (graphic->display, graphic->window, x, y);
+
+  // if (USE_XWINDOW) XClearWindow (graphic->display, graphic->window);
+  // Refresh ();
+
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap16.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap16.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap16.c	(revision 25766)
@@ -1,3 +1,4 @@
 # include "Ximage.h"
+# define OUT_TYPE unsigned short
 
 # define MY_SWAP_BYTE(W) { \
@@ -10,15 +11,21 @@
   int i, j, ii, jj;
   int i_start, i_end, j_start, j_end;
-  int dropback;
+  int I_start, J_start;
+  int dropback, inDX, inDY;
   int dx, dy, DX, DY;
   double expand, Ix, Iy;
   int expand_in, expand_out;
-  unsigned short *out_pix, *out_pix2, *data;
+  OUT_TYPE *out_pix, *out_pix2, *data;
   unsigned short *in_pix, *in_pix2;
-  unsigned short *pixel, pixvalue;
-  unsigned short back;
+  OUT_TYPE *pixel, pixvalue;
+  OUT_TYPE back;
   int swap_client, swap_server, swap_bytes;
 
-  ALLOCATE (pixel, unsigned short, graphic[0].Npixels);
+  // just skip if there is no data
+  if (matrix[0].Naxes == 0) return;
+  if (matrix[0].Naxis[0] == 0) return;
+  if (matrix[0].Naxis[1] == 0) return;
+
+  ALLOCATE (pixel, OUT_TYPE, graphic[0].Npixels);
 
 # ifdef BYTE_SWAP
@@ -38,5 +45,4 @@
   back = 0xffff & graphic[0].back;
   if (swap_bytes) MY_SWAP_BYTE (back);
-  // XXX not certain this is the correct solution...
 
   // set up expansions
@@ -60,17 +66,25 @@
   DY = matrix[0].Naxis[1];
 
-  // x, y are the closest lit screen pixel to 0,0
-  Picture_Lower (&i_start, &j_start, matrix, picture);
+  // i_start, j_start are the closest lit screen pixel to 0,0
+  // I_start, J_start are the image pixel corresponding to i_start, j_start
+  Picture_Lower (&i_start, &j_start, &I_start, &J_start, matrix, picture);
 
-  // x, y are the closest lit screen pixel to dx, dy
-  Picture_Upper (&i_end, &j_end, matrix, picture);
+  // i_end, j_end are the closest lit screen pixel to dx, dy
+  // I_end, J_end are the image pixel corresponding to i_end, j_end
+  Picture_Upper (&i_end, &j_end, i_start, j_start, matrix, picture);
 
-  // Ix,Iy are the first displayed image pixel
-  Picture_to_Image (&Ix, &Iy, i_start, j_start, picture);
+  assert (i_start <= i_end);
+  assert (j_start <= j_end);
+
+  Ix = picture[0].flipx ? I_start - 1 : I_start;
+  Iy = picture[0].flipy ? J_start - 1 : J_start;
+
+  inDX = picture[0].flipx ? -1 : +1;
+  inDY = picture[0].flipy ? -1 : +1;
 
   dropback = expand_out - (i_end - i_start) % expand_out;
   if ((i_end - i_start) % expand_out == 0) dropback = 0;
 
-  data = out_pix = (unsigned short *) picture[0].data;
+  out_pix = data = (OUT_TYPE *) picture[0].data;
   in_pix  = &image[0].pixmap[DX*(int)MAX(Iy,0) + (int)MAX(Ix,0)];
 
@@ -82,5 +96,5 @@
   }
   
-  for (j = j_start; j < j_end; j+= expand_out, in_pix += expand_in*DX) {
+  for (j = j_start; j < j_end; j+= expand_out, in_pix += inDY*expand_in*DX) {
     out_pix = &data[j*dx];
 
@@ -97,9 +111,9 @@
     in_pix2 = in_pix;
     if (expand_out == 1) {
-      for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix++) {
+      for (i = i_start; i < i_end; i++, in_pix2 += inDX*expand_in, out_pix++) {
 	*out_pix = pixel[*in_pix2];
       }
     } else {
-      for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= expand_out) { 
+      for (i = i_start; i < i_end; i+= expand_out, in_pix2 += inDX, out_pix+= expand_out) { 
 	pixvalue = pixel[*in_pix2];
 	out_pix2 = out_pix;
@@ -124,5 +138,5 @@
   /**** fill in top area ****/
   out_pix = &data[j_end*dx];
-  for (j = 0; j < (dy - j_end); j++) {
+  for (j = 0; j < dy - j_end; j++) {
     for (i = 0; i < dx; i++, out_pix++) { 
       *out_pix = back;
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap24.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap24.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap24.c	(revision 25766)
@@ -5,5 +5,6 @@
   int i, j, ii, jj;
   int i_start, i_end, j_start, j_end;
-  int dropback, extra;
+  int I_start, J_start;
+  int dropback, extra, inDX, inDY;
   int dx, dy, DX, DY;
   double expand, Ix, Iy;
@@ -53,12 +54,20 @@
   extra = 4 - (dx * 3) % 4;
 
-  // x, y are the closest lit screen pixel to 0,0
-  Picture_Lower (&i_start, &j_start, matrix, picture);
+  // i_start, j_start are the closest lit screen pixel to 0,0
+  // I_start, J_start are the image pixel corresponding to i_start, j_start
+  Picture_Lower (&i_start, &j_start, &I_start, &J_start, matrix, picture);
 
-  // x, y are the closest lit screen pixel to dx, dy
-  Picture_Upper (&i_end, &j_end, matrix, picture);
+  // i_end, j_end are the closest lit screen pixel to dx, dy
+  // I_end, J_end are the image pixel corresponding to i_end, j_end
+  Picture_Upper (&i_end, &j_end, i_start, j_start, matrix, picture);
 
-  // Ix,Iy are the first displayed image pixel
-  Picture_to_Image (&Ix, &Iy, i_start, j_start, picture);
+  assert (i_start <= i_end);
+  assert (j_start <= j_end);
+
+  Ix = picture[0].flipx ? I_start - 1 : I_start;
+  Iy = picture[0].flipy ? J_start - 1 : J_start;
+
+  inDX = picture[0].flipx ? -1 : +1;
+  inDY = picture[0].flipy ? -1 : +1;
 
   dropback = expand_out - (i_end - i_start) % expand_out;
@@ -80,5 +89,5 @@
   }
   
-  for (j = j_start; j < j_end; j+= expand_out, in_pix += expand_in*DX) {
+  for (j = j_start; j < j_end; j+= expand_out, in_pix += inDY*expand_in*DX) {
     out_pix = &data[j*(3*dx+extra)];
 
@@ -97,5 +106,5 @@
     in_pix2 = in_pix;
     if (expand_out == 1) {
-      for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix+=3) {
+      for (i = i_start; i < i_end; i++, in_pix2+= inDX*expand_in, out_pix+=3) {
 	out_pix[0] = pixel1[*in_pix2];
 	out_pix[1] = pixel2[*in_pix2];
@@ -103,5 +112,5 @@
       }
     } else {
-      for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= 3*expand_out) { 
+      for (i = i_start; i < i_end; i+= expand_out, in_pix2 += inDX, out_pix+= 3*expand_out) { 
 	pixvalue1 = pixel1[*in_pix2];
 	pixvalue2 = pixel2[*in_pix2];
@@ -121,5 +130,4 @@
     /**** fill in area to the right of the picture ****/
     for (jj = 0; (jj < expand_out) && (j + jj < dy); jj++) {
-      //    for (jj = 0; jj < expand_out; jj++) {
       out_pix2 = out_pix + jj*(3*dx+extra);
       for (i = i_end; i < dx; i++, out_pix2+=3) {
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap32.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap32.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap32.c	(revision 25766)
@@ -1,11 +1,12 @@
 # include "Ximage.h"
+# define OUT_TYPE unsigned int
 
 # define MY_SWAP_INT(A,B) { int tmp; tmp = A; A = B; B = tmp; }
 
-# define MY_SWAP_WORD(W) { \
-  char tmp, *X; \
-  X = (char *) &W; \
-  tmp = X[0]; X[0] = X[3]; X[3] = tmp; \
-  tmp = X[1]; X[1] = X[2]; X[2] = tmp; }
+# define MY_SWAP_WORD(W) {			\
+    char tmp, *X;				\
+    X = (char *) &W;				\
+    tmp = X[0]; X[0] = X[3]; X[3] = tmp;	\
+    tmp = X[1]; X[1] = X[2]; X[2] = tmp; }
 
 void Remap32 (Graphic *graphic, KapaImageWidget *image, Picture *picture, Matrix *matrix) {
@@ -13,15 +14,21 @@
   int i, j, ii, jj;
   int i_start, i_end, j_start, j_end;
+  int I_start, J_start;
   int dropback, inDX, inDY;
   int dx, dy, DX, DY;
   double expand, Ix, Iy;
   int expand_in, expand_out;
-  unsigned int *out_pix, *out_pix2;
+  OUT_TYPE *out_pix, *out_pix2, *data;
   unsigned short *in_pix, *in_pix2;
-  unsigned long *pixel, pixvalue;
-  unsigned long back;
+  OUT_TYPE *pixel, pixvalue;
+  OUT_TYPE back;
   int swap_client, swap_server, swap_bytes;
 
-  ALLOCATE (pixel, unsigned long, graphic[0].Npixels);
+  // just skip if there is no data
+  if (matrix[0].Naxes == 0) return;
+  if (matrix[0].Naxis[0] == 0) return;
+  if (matrix[0].Naxis[1] == 0) return;
+
+  ALLOCATE (pixel, OUT_TYPE, graphic[0].Npixels);
 
 # ifdef BYTE_SWAP
@@ -43,5 +50,5 @@
 
   // set up expansions
-  assert ((picture[0].expand >= 1) || (picture[0].expand <= -1));
+  assert ((picture[0].expand >= 1) || (picture[0].expand <= -2));
   expand = expand_in = expand_out = 1.0;
   if (picture[0].expand > 0) {
@@ -62,22 +69,17 @@
   DY = matrix[0].Naxis[1];
 
-  // x, y are the closest lit screen pixel to 0,0
-  Picture_Lower (&i_start, &j_start, matrix, picture);
+  // i_start, j_start are the closest lit screen pixel to 0,0
+  // I_start, J_start are the image pixel corresponding to i_start, j_start
+  Picture_Lower (&i_start, &j_start, &I_start, &J_start, matrix, picture);
 
-  // x, y are the closest lit screen pixel to dx, dy
-  Picture_Upper (&i_end, &j_end, matrix, picture);
+  // i_end, j_end are the closest lit screen pixel to dx, dy
+  // I_end, J_end are the image pixel corresponding to i_end, j_end
+  Picture_Upper (&i_end, &j_end, i_start, j_start, matrix, picture);
 
-  if (i_end < i_start) MY_SWAP_INT (i_start, i_end);
-  if (j_end < j_start) MY_SWAP_INT (j_start, j_end);
+  assert (i_start <= i_end);
+  assert (j_start <= j_end);
 
-  // Ix,Iy are the first displayed image pixel
-  Picture_to_Image (&Ix, &Iy, i_start, j_start, picture);
-  Ix = MIN (MAX (0, Ix), DX - 1);
-  Iy = MIN (MAX (0, Iy), DY - 1);
-  // XXX not completely consistent with the i_start, i_end range...
-
-  // we need to offset because i_start points to the bottom edge of Ix
-  // if (picture[0].flipx) Ix -= 1.0;
-  // if (picture[0].flipy) Iy -= 1.0;
+  Ix = picture[0].flipx ? I_start - 1 : I_start;
+  Iy = picture[0].flipy ? J_start - 1 : J_start;
 
   inDX = picture[0].flipx ? -1 : +1;
@@ -87,5 +89,5 @@
   if ((i_end - i_start) % expand_out == 0) dropback = 0;
 
-  out_pix = (unsigned int *) picture[0].data;
+  out_pix = data = (OUT_TYPE *) picture[0].data;
   in_pix  = &image[0].pixmap[DX*(int)MAX(Iy,0) + (int)MAX(Ix,0)];
 
@@ -97,5 +99,6 @@
   }
   
-  for (j = j_start; j < j_end; j+= expand_out, out_pix+=(expand_out-1)*dx, in_pix += inDY*expand_in*DX) {
+  for (j = j_start; j < j_end; j+= expand_out, in_pix += inDY*expand_in*DX) {
+    out_pix = &data[j*dx];
 
     /**** fill in area to the left of the picture ****/
@@ -126,9 +129,4 @@
     }
     out_pix -= dropback;
-    
-    // assert (in_pix2 - image[0].pixmap <= DX*DY);
-    // assert (in_pix2 - image[0].pixmap >= 0);
-    // assert (in_pix - image[0].pixmap <= DX*DY);
-    // assert (in_pix - image[0].pixmap >= 0);
 
     /**** fill in area to the right of the picture ****/
@@ -139,22 +137,16 @@
       }
     }
-    out_pix += (dx - i_end);
-    // assert (out_pix - (unsigned int *)picture[0].data <= dx*dy);
-    // assert (out_pix - (unsigned int *)picture[0].data >= 0);
   } 
-  
-  if ((j_end - j_start) % expand_out > 0)
-    out_pix -= expand_out - (j_end - j_start) % expand_out;
-  
-  // assert (out_pix - (unsigned int *)picture[0].data <= dx*dy);
-  // assert (out_pix - (unsigned int *)picture[0].data >= 0);
 
   /**** fill in top area ****/
-  for (j = 0; (j < dx*(dy - j_end)) && (out_pix - (unsigned int *)picture[0].data < dx*dy); j++, out_pix++) { 
-    *out_pix = back;
+  out_pix = &data[j_end*dx];
+  for (j = 0; j < dy - j_end; j++) {
+    for (i = 0; i < dx; i++, out_pix ++) {
+      *out_pix = back;
+    }
   }
 
   picture[0].pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
-					picture[0].data, picture[0].dx, picture[0].dy, 32, 0);
+				 picture[0].data, picture[0].dx, picture[0].dy, 32, 0);
 
   free (pixel);
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap8.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap8.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/Remap8.c	(revision 25766)
@@ -1,3 +1,4 @@
 # include "Ximage.h"
+# define OUT_TYPE unsigned char
 
 void Remap8 (Graphic *graphic, KapaImageWidget *image, Picture *picture, Matrix *matrix) {
@@ -5,14 +6,20 @@
   int i, j, ii, jj;
   int i_start, i_end, j_start, j_end;
-  int dropback;
+  int I_start, J_start;
+  int dropback, inDX, inDY;
   int dx, dy, DX, DY;
   double expand, Ix, Iy;
   int expand_in, expand_out;
-  unsigned char *out_pix, *out_pix2;
-  unsigned short *in_pix,  *in_pix2;
-  unsigned char *pixel, pixvalue;
-  unsigned char back;
+  OUT_TYPE *out_pix, *out_pix2, *data;
+  unsigned short *in_pix, *in_pix2;
+  OUT_TYPE *pixel, pixvalue;
+  OUT_TYPE back;
 
-  ALLOCATE (pixel, unsigned char, graphic[0].Npixels);
+  // just skip if there is no data
+  if (matrix[0].Naxes == 0) return;
+  if (matrix[0].Naxis[0] == 0) return;
+  if (matrix[0].Naxis[1] == 0) return;
+
+  ALLOCATE (pixel, OUT_TYPE, graphic[0].Npixels);
 
   // local array for pixel values
@@ -44,17 +51,25 @@
   DY = matrix[0].Naxis[1];
 
-  // x, y are the closest lit screen pixel to 0,0
-  Picture_Lower (&i_start, &j_start, matrix, picture);
+  // i_start, j_start are the closest lit screen pixel to 0,0
+  // I_start, J_start are the image pixel corresponding to i_start, j_start
+  Picture_Lower (&i_start, &j_start, &I_start, &J_start, matrix, picture);
 
-  // x, y are the closest lit screen pixel to dx, dy
-  Picture_Upper (&i_end, &j_end, matrix, picture);
+  // i_end, j_end are the closest lit screen pixel to dx, dy
+  // I_end, J_end are the image pixel corresponding to i_end, j_end
+  Picture_Upper (&i_end, &j_end, i_start, j_start, matrix, picture);
 
-  // Ix,Iy are the first displayed image pixel
-  Picture_to_Image (&Ix, &Iy, i_start, j_start, picture);
+  assert (i_start <= i_end);
+  assert (j_start <= j_end);
+
+  Ix = picture[0].flipx ? I_start - 1 : I_start;
+  Iy = picture[0].flipy ? J_start - 1 : J_start;
+
+  inDX = picture[0].flipx ? -1 : +1;
+  inDY = picture[0].flipy ? -1 : +1;
 
   dropback = expand_out - (i_end - i_start) % expand_out;
   if ((i_end - i_start) % expand_out == 0) dropback = 0;
 
-  out_pix = (unsigned char *) picture[0].data;
+  out_pix = data = (OUT_TYPE *) picture[0].data;
   in_pix  = &image[0].pixmap[DX*(int)MAX(Iy,0) + (int)MAX(Ix,0)];
 
@@ -66,5 +81,6 @@
   }
   
-  for (j = j_start; j < j_end; j+= expand_out, out_pix+=(expand_out-1)*dx, in_pix += expand_in*DX) {
+  for (j = j_start; j < j_end; j+= expand_out, in_pix += inDY*expand_in*DX) {
+    out_pix = &data[j*dx];
 
     /**** fill in area to the left of the picture ****/
@@ -80,12 +96,12 @@
     in_pix2 = in_pix;
     if (expand_out == 1) {
-      for (i = i_start; i < i_end; i++, in_pix2+= expand_in, out_pix++) {
+      for (i = i_start; i < i_end; i++, in_pix2 += inDX*expand_in, out_pix++) {
 	*out_pix = pixel[*in_pix2];
       }
     } else {
-      for (i = i_start; i < i_end; i+= expand_out, in_pix2++, out_pix+= expand_out) { 
+      for (i = i_start; i < i_end; i+= expand_out, in_pix2 += inDX, out_pix+= expand_out) { 
 	pixvalue = pixel[*in_pix2];
 	out_pix2 = out_pix;
-	for (jj = 0; (jj < expand_out) & (j + jj < dy); jj++, out_pix2+=(dx-expand_out)) {
+	for (jj = 0; (jj < expand_out) && (j + jj < dy); jj++, out_pix2+=(dx-expand_out)) {
 	  for (ii = 0; ii < expand_out; ii++, out_pix2++) {
 	    *out_pix2 = pixvalue;
@@ -103,14 +119,12 @@
       }
     }
-    out_pix += (dx - i_end);
-    
   } 
   
-  if ((j_end - j_start) % expand_out > 0)
-    out_pix -= expand_out - (j_end - j_start) % expand_out;
-  
   /**** fill in top area ****/
-  for (j = 0; (j < dx*(dy - j_end)) && (out_pix - (unsigned char *)picture[0].data < dx*dy); j++, out_pix++) { 
-    *out_pix = back;
+  out_pix = &data[j_end*dx];
+  for (j = 0; j < dy - j_end; j++) {
+    for (i = 0; i < dx; i++, out_pix++) {
+      *out_pix = back;
+    }
   }
   picture[0].pix = XCreateImage (graphic[0].display, graphic[0].visual, graphic[0].depth, ZPixmap, 0, 
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/Reorient.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/Reorient.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/Reorient.c	(revision 25766)
@@ -7,7 +7,10 @@
   picture = &image[0].picture;
 
-  if (picture[0].expand == 0) picture[0].expand = 1;
+  if (picture[0].expand == 0) {
+      picture[0].expand = 1;
+      image[0].zoom.expand = 5;
+  }
 
-  if ((picture[0].X == X) && (picture[0].Y == Y) && (mode == 0)) {
+  if ((picture[0].Xc == X) && (picture[0].Yc == Y) && (mode == 0)) {
     Refresh ();
     XFlush (graphic[0].display);
@@ -17,7 +20,7 @@
   switch (mode) {
   case 0:
-    if ((picture[0].X != X) || (picture[0].Y != Y)) {
-      picture[0].X = X;
-      picture[0].Y = Y;
+    if ((picture[0].Xc != X) || (picture[0].Yc != Y)) {
+      picture[0].Xc = X;
+      picture[0].Yc = Y;
     }
     break;
@@ -25,14 +28,15 @@
     picture[0].expand--;
     if ((picture[0].expand == 0) || (picture[0].expand == -1)) picture[0].expand = -2;
-    picture[0].X = X;
-    picture[0].Y = Y;
+    picture[0].Xc = X;
+    picture[0].Yc = Y;
     break;
   case +1:
     picture[0].expand++;
     if ((picture[0].expand == 0) || (picture[0].expand == -1)) picture[0].expand = 1;
-    picture[0].X = X;
-    picture[0].Y = Y;
+    picture[0].Xc = X;
+    picture[0].Yc = Y;
     break;
   }
+  image[0].zoom.expand = MIN(image[0].zoom.dx / 5.5, MAX(5, 2*picture[0].expand));
 
   Remap (graphic, image);
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/SetColorScale.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/SetColorScale.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/SetColorScale.c	(revision 25766)
@@ -218,5 +218,5 @@
   // store the colors
   if (USE_XWINDOW) {
-    if (graphic[0].visualclass) {
+    if (graphic[0].dynamicColors) {
       XStoreColors(graphic[0].display, graphic[0].colormap, graphic[0].cmap, Npixels);
     } else {
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/SetColormap.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/SetColormap.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/SetColormap.c	(revision 25766)
@@ -146,9 +146,11 @@
  store_colors:
   if (!USE_XWINDOW) return (TRUE);
-  if (graphic[0].visualclass) {
-    XStoreColors(graphic[0].display, graphic[0].colormap, graphic[0].cmap, graphic[0].Npixels);
+  if (graphic[0].dynamicColors) {
+    if (!XStoreColors(graphic[0].display, graphic[0].colormap, graphic[0].cmap, graphic[0].Npixels)) {
+	fprintf (stderr, "error storing colors\n");
+    }
   } else {
     for (i = 0; i < graphic[0].Npixels; i++) {
-      if (XAllocColor (graphic[0].display, graphic[0].colormap, &graphic[0].cmap[i]) == 0) {
+      if (!XAllocColor (graphic[0].display, graphic[0].colormap, &graphic[0].cmap[i])) {
 	fprintf (stderr, "error on %d\n", i);
       }
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/SetUpGraphic.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/SetUpGraphic.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/SetUpGraphic.c	(revision 25766)
@@ -60,4 +60,5 @@
   graphic->color = KapaX11colors (graphic->display, graphic->colormap, graphic->fore, &Ncolors);
   if (MAP_WINDOW) MapWindow (graphic);
+
   return;
 }
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/StatusBox.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/StatusBox.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/StatusBox.c	(revision 25766)
@@ -11,10 +11,10 @@
     y = 0.5*image[0].image[0].matrix.Naxis[1];
     // z = -1;
-    image[0].zoom.X = x;
-    image[0].zoom.Y = y;
+    image[0].zoom.Xc = x;
+    image[0].zoom.Yc = y;
     // image[0].z = z;
   } else {
-    x = image[0].zoom.X;
-    y = image[0].zoom.Y;
+    x = image[0].zoom.Xc;
+    y = image[0].zoom.Yc;
     // z = image[0].z;
   }
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/UpdatePointer.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/UpdatePointer.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/UpdatePointer.c	(revision 25766)
@@ -29,6 +29,6 @@
 
   skip:
-    image[0].zoom.X = x;
-    image[0].zoom.Y = y;
+    image[0].zoom.Xc = x;
+    image[0].zoom.Yc = y;
     
     UpdateStatusBox (graphic, image, x, y, z, 0);
@@ -36,8 +36,10 @@
       
     CreateZoom (graphic, image);  
-    XPutImage (graphic[0].display, graphic[0].window, graphic[0].gc,
-	       image[0].zoom.pix, 0, 0, 
-	       image[0].zoom.x, image[0].zoom.y, 
-	       image[0].zoom.dx, image[0].zoom.dy);
+    if (image[0].zoom.pix) {
+	XPutImage (graphic[0].display, graphic[0].window, graphic[0].gc,
+		   image[0].zoom.pix, 0, 0, 
+		   image[0].zoom.x, image[0].zoom.y, 
+		   image[0].zoom.dx, image[0].zoom.dy);
+    }
     CrossHairs (graphic, &image[0].zoom);
     XFlush (graphic[0].display);
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/UpdateStatusBox.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/UpdateStatusBox.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/UpdateStatusBox.c	(revision 25766)
@@ -48,5 +48,5 @@
   
   bzero (line, 100);
-  sprintf (line, "%10.1f %10.1f", x, y);
+  sprintf (line, "%10.2f %10.2f", x, y);
   XDrawString (graphic[0].display, graphic[0].window, graphic[0].gc, 
 	       image[0].text_x + PAD1, image[0].text_y + 2*textpad + 2*PAD1, line, strlen(line));
Index: branches/eam_branches/20090820/Ohana/src/kapa2/src/bDrawOverlay.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/src/bDrawOverlay.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/src/bDrawOverlay.c	(revision 25766)
@@ -81,11 +81,11 @@
 	  double sn = sin(angle);
 	  x0 = X + pX*dx*cs;
-	  y0 = Y - pY*dx*sn;
+	  y0 = Y + pY*dx*sn;
 	  // XXX dt should be based on the size of the ellipse...
 	  // 0.10 -> 60 segments on the ellipse
 	  # define DT 0.1
 	  for (t = DT; t < 2*M_PI + DT; t+=DT) {
-	    x1 = X + pX*dx*cos(t)*cs + pX*dy*sin(t)*sn;
-	    y1 = Y - pY*dx*cos(t)*sn + pY*dy*sin(t)*cs;
+	    x1 = X + pX*dx*cos(t)*cs - pX*dy*sin(t)*sn;
+	    y1 = Y + pY*dx*cos(t)*sn + pY*dy*sin(t)*cs;
 	    bDrawLine (x0, y0, x1, y1);
 	    x0 = x1;
Index: branches/eam_branches/20090820/Ohana/src/kapa2/test/overlay.sh
===================================================================
--- branches/eam_branches/20090820/Ohana/src/kapa2/test/overlay.sh	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/kapa2/test/overlay.sh	(revision 25766)
@@ -0,0 +1,10 @@
+
+macro checker
+  mcreate a 8 8
+  for ix 0 8
+    for iy 0 8
+      if (($ix + $iy) % 2) continue
+      a[$ix][$iy] = $ix + $iy
+    end
+  end
+end
Index: branches/eam_branches/20090820/Ohana/src/libdvo/doc/locking.txt
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libdvo/doc/locking.txt	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/libdvo/doc/locking.txt	(revision 25766)
@@ -0,0 +1,13 @@
+
+The DVO locking policy is a little bit broken.  DVO currently
+(2009.08.10) requires that users have write access to files because
+the code does not distinguish well cases where read-only (soft locks)
+are used vs cases of read/write (hard locks) are needed.
+
+locks set in DVO:
+
+dvo_catalog_lock -- on catalog open & catalog create (all files for
+		    split mode)
+
+gfits_db_lock -- on photcode table read/write and dvo_image_lock
+
Index: branches/eam_branches/20090820/Ohana/src/libdvo/include/dvo.h
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libdvo/include/dvo.h	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libdvo/include/dvo.h	(revision 25766)
@@ -325,5 +325,5 @@
 PhotCodeData *GetPhotcodeTable (void);
 
-int LoadPhotcodes (char *catdir_file, char *master_file);
+int LoadPhotcodes (char *catdir_file, char *master_file, int readwrite);
 int LoadPhotcodesText (char *filename);
 int LoadPhotcodesFITS (char *filename);
@@ -432,5 +432,5 @@
 SkyTable  *SkyTableLoad        	   PROTO((char *filename, int VERBOSE));
 SkyTable  *SkyTableFromGSC     	   PROTO((char *filename, int depth, int VERBOSE));
-SkyTable  *SkyTableLoadOptimal 	   PROTO((char *catdir, char *SKYFILE, char *GSCFILE, int depth, int VERBOSE));
+SkyTable  *SkyTableLoadOptimal 	   PROTO((char *catdir, char *SKYFILE, char *GSCFILE, int readwrite, int depth, int VERBOSE));
 int        SkyTableSetDepth    	   PROTO((SkyTable *sky, int depth));
 SkyList   *SkyRegionByPoint    	   PROTO((SkyTable *table, int depth, double ra, double dec));
Index: branches/eam_branches/20090820/Ohana/src/libdvo/src/LoadPhotcodes.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libdvo/src/LoadPhotcodes.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libdvo/src/LoadPhotcodes.c	(revision 25766)
@@ -1,15 +1,20 @@
 # include <dvo.h>
 
-int LoadPhotcodes (char *catdir_file, char *master_file) {
+int LoadPhotcodes (char *catdir_file, char *master_file, int readwrite) {
 
   /* first try to load the photcodes from the specified CATDIR location */
   if (LoadPhotcodesFITS (catdir_file)) return TRUE;
   
+  if (!readwrite) {
+    fprintf (stderr, "db is missing a photcode table & access is read-only -- create one with photcode-table -import\n");
+    return FALSE;
+  }
+
   /* next try to load the photcodes from the master text photcode file */
   /* automatically (or on demand?) save the text file to the FITS version */
   if (LoadPhotcodesText (master_file)) { 
-      if (!check_file_access (catdir_file, TRUE, TRUE)) return TRUE;
-      SavePhotcodesFITS (catdir_file);
-      return TRUE;
+    if (!check_file_access (catdir_file, TRUE, TRUE, TRUE)) return TRUE;
+    SavePhotcodesFITS (catdir_file);
+    return TRUE;
   }
 
Index: branches/eam_branches/20090820/Ohana/src/libdvo/src/coordops.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libdvo/src/coordops.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libdvo/src/coordops.c	(revision 25766)
@@ -163,4 +163,5 @@
 	return (FALSE);
     }
+    if (fabs(alpha) >= 180.0) return (FALSE);
     *ra  = alpha + coords[0].crval1;
     *dec = delta + coords[0].crval2;
Index: branches/eam_branches/20090820/Ohana/src/libdvo/src/dvo_catalog.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libdvo/src/dvo_catalog.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libdvo/src/dvo_catalog.c	(revision 25766)
@@ -180,4 +180,5 @@
 
   int Nsecfilt, mode;
+  int BACKUP, READWRITE;
 
   mode = DVO_OPEN_NONE;
@@ -192,9 +193,17 @@
   dvo_catalog_init (catalog, FALSE);
 
+  // default access control options:
   catalog[0].lockmode  = LCK_XCLD;
-  if (mode == DVO_OPEN_READ) catalog[0].lockmode  = LCK_SOFT;
+  BACKUP = TRUE;
+  READWRITE = TRUE;
+
+  // in read-only mode, do not backup or require write access
+  if (mode == DVO_OPEN_READ) {
+    catalog[0].lockmode  = LCK_SOFT;
+    BACKUP = FALSE;
+    READWRITE = FALSE;
+  }
   
-  // XXX make a backup?  always?
-  if (!check_file_access (catalog[0].filename, TRUE, VERBOSE)) {
+  if (!check_file_access (catalog[0].filename, BACKUP, READWRITE, VERBOSE)) {
     if (VERBOSE) fprintf (stderr, "no permission to access %s\n", catalog[0].filename);
     return (FALSE);
Index: branches/eam_branches/20090820/Ohana/src/libdvo/src/dvo_image.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libdvo/src/dvo_image.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libdvo/src/dvo_image.c	(revision 25766)
@@ -4,6 +4,16 @@
 int dvo_image_lock (FITS_DB *db, char *filename, double timeout, int lockstate) {
 
-  /* lock the image catalog */
-  if (!check_file_access (filename, FALSE, TRUE)) return (FALSE);
+  int READWRITE;
+
+  // default access control options:
+  READWRITE = TRUE;
+
+  // in read-only mode, do not backup or require write access
+  if (lockstate == LCK_SOFT) {
+    READWRITE = FALSE;
+  }
+
+  // do not perform a backup here
+  if (!check_file_access (filename, FALSE, READWRITE, TRUE)) return (FALSE);
 
   db[0].lockstate = lockstate;
Index: branches/eam_branches/20090820/Ohana/src/libdvo/src/skyregion_io.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libdvo/src/skyregion_io.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libdvo/src/skyregion_io.c	(revision 25766)
@@ -84,5 +84,5 @@
 }
 
-SkyTable *SkyTableLoadOptimal (char *catdir, char *skyfile, char *gscfile, int depth, int verbose) {
+SkyTable *SkyTableLoadOptimal (char *catdir, char *skyfile, char *gscfile, int readwrite, int depth, int verbose) {
 
   char filename[256];
@@ -93,5 +93,5 @@
   sprintf (filename, "%s/SkyTable.fits", catdir);
   if (stat (filename, &filestat)) goto SKYFILE;
-  if (!check_file_access (filename, FALSE, verbose)) goto SKYFILE;
+  if (!check_file_access (filename, FALSE, readwrite, verbose)) goto SKYFILE;
   sky = SkyTableLoad (filename, verbose);
   if (sky == NULL) {
@@ -106,5 +106,5 @@
   if (skyfile[0] != 0) goto GSCFILE;
   if (stat (skyfile, &filestat)) goto GSCFILE;
-  if (!check_file_access (skyfile, FALSE, verbose)) goto GSCFILE;
+  if (!check_file_access (skyfile, FALSE, readwrite, verbose)) goto GSCFILE;
   sky = SkyTableLoad (skyfile, verbose);
   if (sky == NULL) {
@@ -117,5 +117,5 @@
   /* create CATDIR copy */
   sprintf (filename, "%s/SkyTable.fits", catdir);
-  check_file_access (filename, FALSE, verbose);
+  check_file_access (filename, FALSE, readwrite, verbose);
   if (!SkyTableSave (sky, filename)) return NULL;
 
@@ -134,5 +134,5 @@
   /* create CATDIR copy */
   sprintf (filename, "%s/SkyTable.fits", catdir);
-  check_file_access (filename, FALSE, verbose);
+  check_file_access (filename, FALSE, readwrite, verbose);
   if (!SkyTableSave (sky, filename)) return NULL;
 
Index: branches/eam_branches/20090820/Ohana/src/libkapa/include/kapa.h
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libkapa/include/kapa.h	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libkapa/include/kapa.h	(revision 25766)
@@ -154,4 +154,5 @@
 /* KapaWindow.c */
 int KiiResize (int fd, int Nx, int Ny);
+int KiiRelocate (int fd, int x, int y);
 int KiiCenter (int fd, double x, double y, int zoom);
 int KiiParity (int fd, int xflip, int yflip);
Index: branches/eam_branches/20090820/Ohana/src/libkapa/src/KapaWindow.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libkapa/src/KapaWindow.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libkapa/src/KapaWindow.c	(revision 25766)
@@ -23,4 +23,12 @@
   KiiSendCommand (fd, 4, "RSIZ");
   KiiSendMessage (fd, "%d %d", Nx, Ny); 
+  KiiWaitAnswer (fd, "DONE");
+  return (TRUE);
+}
+
+int KiiRelocate (int fd, int x, int y) {
+
+  KiiSendCommand (fd, 4, "MOVE");
+  KiiSendMessage (fd, "%d %d", x, y); 
   KiiWaitAnswer (fd, "DONE");
   return (TRUE);
Index: branches/eam_branches/20090820/Ohana/src/libohana/include/ohana.h
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libohana/include/ohana.h	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libohana/include/ohana.h	(revision 25766)
@@ -166,5 +166,5 @@
 int     mkdirhier              PROTO((char *path, int mode));
 void    make_backup            PROTO((char *filename));
-int     check_file_access      PROTO((char *basefile, int backup, int verbose));
+int     check_file_access      PROTO((char *basefile, int backup, int readwrite, int verbose));
 int     check_dir_access       PROTO((char *path, int verbose));
 int     check_file_exec        PROTO((char *filename));
Index: branches/eam_branches/20090820/Ohana/src/libohana/src/findexec.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/libohana/src/findexec.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/libohana/src/findexec.c	(revision 25766)
@@ -67,5 +67,5 @@
    - file backup permission OK (optional)
 */
-int check_file_access (char *basefile, int BACKUP, int VERBOSE) {
+int check_file_access (char *basefile, int BACKUP, int READWRITE, int VERBOSE) {
   
   char *path, *filename;
@@ -74,7 +74,12 @@
   gid_t gid;
   int status;
+  int valid;
 
   uid = getuid();
   gid = getgid();
+
+  // XXX this function needs to call 'getgroups' to get the full list of the user's
+  // groups.  we would then need to loop over all groups in the gid test below 
+  // to see if any match the file.  test to see how slow this is.
 
   /* check permission to write to directory */
@@ -87,8 +92,18 @@
   status = stat (basefile, &filestat);
   if (status == 0) { /* file exists, are permissions OK? */
-    if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
-	((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
-	((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
-    } else {
+    valid = FALSE;
+    if (!valid && (uid == filestat.st_uid)) {
+      valid = (filestat.st_mode & S_IRUSR) != 0;
+      valid &= !READWRITE || (filestat.st_mode & S_IWUSR);
+    }
+    if (!valid && (gid == filestat.st_gid)) {
+      valid = (filestat.st_mode & S_IRGRP) != 0;
+      valid &= !READWRITE || (filestat.st_mode & S_IWGRP);
+    }
+    if (!valid) {
+      valid = (filestat.st_mode & S_IROTH) != 0;
+      valid &= !READWRITE || (filestat.st_mode & S_IWOTH);
+    }
+    if (!valid) {
       if (VERBOSE) fprintf (stderr, "can't write to %s\n", basefile);
       return (FALSE);
@@ -102,8 +117,18 @@
     status = stat (filename, &filestat);
     if (status == 0) { /* file exists, are permissions OK? */
-      if (((uid == filestat.st_uid) && (filestat.st_mode & S_IRUSR) && (filestat.st_mode & S_IWUSR)) ||
-	  ((gid == filestat.st_gid) && (filestat.st_mode & S_IRGRP) && (filestat.st_mode & S_IWGRP)) || 
-	  ((filestat.st_mode & S_IROTH) && (filestat.st_mode & S_IWOTH))) {
-      } else {
+      valid = FALSE;
+      if (!valid && (uid == filestat.st_uid)) {
+	valid = (filestat.st_mode & S_IRUSR) != 0;
+	valid &= !READWRITE || (filestat.st_mode & S_IWUSR);
+      }
+      if (!valid && (gid == filestat.st_gid)) {
+	valid = (filestat.st_mode & S_IRGRP) != 0;
+	valid &= !READWRITE || (filestat.st_mode & S_IWGRP);
+      }
+      if (!valid) {
+	valid = (filestat.st_mode & S_IROTH) != 0;
+	valid &= !READWRITE || (filestat.st_mode & S_IWOTH);
+      }
+      if (!valid) {
 	if (VERBOSE) fprintf (stderr, "can't write to %s\n", filename);
 	return (FALSE);
Index: branches/eam_branches/20090820/Ohana/src/markrock/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/markrock/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/markrock/src/ConfigInit.c	(revision 25766)
@@ -44,5 +44,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/markrock/src/markrock.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/markrock/src/markrock.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/markrock/src/markrock.c	(revision 25766)
@@ -33,6 +33,6 @@
 
   /* if lockfile exists, program will complain and quit */
-  if (!check_file_access (argv[1], TRUE, TRUE)) exit (1);
-  if (!check_file_access (RockCat, TRUE, TRUE)) exit (1);
+  if (!check_file_access (argv[1], TRUE, TRUE, TRUE)) exit (1);
+  if (!check_file_access (RockCat, TRUE, TRUE, TRUE)) exit (1);
 
   catalog.filename = argv[1];
Index: branches/eam_branches/20090820/Ohana/src/markstar/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/markstar/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/markstar/src/ConfigInit.c	(revision 25766)
@@ -54,5 +54,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/mosastro/src/getptolemy.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/mosastro/src/getptolemy.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/mosastro/src/getptolemy.c	(revision 25766)
@@ -19,5 +19,5 @@
 
   /* load regions from GSC table, restrict to patch */
-  sky = SkyTableLoadOptimal (CATDIR, NULL, GSCFILE, SKY_DEPTH_HST, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, NULL, GSCFILE, FALSE, SKY_DEPTH_HST, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   skylist = SkyListByPatch (sky, -1, &patch);
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/Makefile
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/Makefile	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/Makefile	(revision 25766)
@@ -21,4 +21,5 @@
 $(SRC)/cgrid.$(ARCH).o		   \
 $(SRC)/coords.$(ARCH).o	   \
+$(SRC)/cdot.$(ARCH).o		   \
 $(SRC)/cplot.$(ARCH).o		   \
 $(SRC)/csystem.$(ARCH).o	   \
@@ -36,4 +37,11 @@
 $(SRC)/medianmap.$(ARCH).o	   \
 $(SRC)/mkgauss.$(ARCH).o	   \
+$(SRC)/mksersic.$(ARCH).o	   \
+$(SRC)/galradius.$(ARCH).o	   \
+$(SRC)/galradbins.$(ARCH).o	   \
+$(SRC)/galsectors.$(ARCH).o	   \
+$(SRC)/galprofiles.$(ARCH).o	   \
+$(SRC)/elliprofile.$(ARCH).o	   \
+$(SRC)/petrosian.$(ARCH).o	   \
 $(SRC)/multifit.$(ARCH).o	   \
 $(SRC)/objload.$(ARCH).o	   \
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/cdot.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/cdot.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/cdot.c	(revision 25766)
@@ -0,0 +1,38 @@
+# include "data.h"
+
+int cdot (int argc, char **argv) {
+  
+  int kapa, status;
+  Graphdata graphmode;
+  float x, y;
+  double r, d, Rmin, Rmax;
+
+  if (!style_args (&graphmode, &argc, argv, &kapa)) return FALSE;
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: dot <ra> <dec>\n");
+    return (FALSE);
+  }
+  r = atof(argv[1]);
+  d = atof(argv[2]);
+
+  Rmin = graphmode.coords.crval1 - 182.0;
+  Rmax = graphmode.coords.crval1 + 182.0;
+  // Rmid = 0.5*(Rmin + Rmax);
+
+  /* set point style and errorbar mode (these are NOT sticky) */
+  graphmode.style = 2;
+  graphmode.etype = 0;
+
+  r = ohana_normalize_angle (r);
+  while (r < Rmin) r += 360.0;
+  while (r > Rmax) r -= 360.0;
+
+  status = fRD_to_XY (&x, &y, r, d, &graphmode.coords);
+
+  if (!KapaPrepPlot (kapa, 1, &graphmode)) return (FALSE);
+  KapaPlotVector (kapa, 1, &x, "x");
+  KapaPlotVector (kapa, 1, &y, "y");
+  
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/cgrid.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/cgrid.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/cgrid.c	(revision 25766)
@@ -37,5 +37,5 @@
   /* set spacings for RA */
   minorRA = minorDEC = 0.1;
-  range = MIN (fabs(graphmode.xmax-graphmode.xmin), fabs(graphmode.ymax-graphmode.ymin));
+  range = MIN (fabs(graphmode.coords.cdelt1*(graphmode.xmax-graphmode.xmin)), fabs(graphmode.coords.cdelt2*(graphmode.ymax-graphmode.ymin)));
   if (NorthPole || SouthPole) range = 360;
   lrange = log10(MAX(fabs(range), 1e-30));
@@ -58,6 +58,7 @@
   }
   dR = range / 100.0;
+
   /* set spacings for DEC */
-  range = MIN (fabs(graphmode.xmax-graphmode.xmin), fabs(graphmode.ymax-graphmode.ymin));
+  range = MIN (fabs(graphmode.coords.cdelt1*(graphmode.xmax-graphmode.xmin)), fabs(graphmode.coords.cdelt2*(graphmode.ymax-graphmode.ymin)));
   lrange = log10(MAX(fabs(range), 1e-30));
   factor = (int) (lrange);
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/elliprofile.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/elliprofile.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/elliprofile.c	(revision 25766)
@@ -0,0 +1,64 @@
+# include "astro.h"
+
+int elliprofile (int argc, char **argv) {
+  
+  int i, ix, iy, Nx, Ny, N, center;
+  float *in;
+  double Rmaj, Rmin, phi, alpha, Io, ARatio;
+  double root1, root2, R, A1, A2, A3;
+  double Sx, Sy, Sxy;
+  double x, y, r, f, Xo, Yo;
+  Buffer *buf;
+  Vector *rvec, *fvec;
+
+  if (argc != 9) {
+    gprint (GP_ERR, "USAGE: elliprofile (buffer) (rvec) (fvec) (Xo) (Yo) (Rmaj) (Rmin) (phi)\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].header.Naxis[0];
+  Ny = buf[0].header.Naxis[1];
+
+  if ((rvec = SelectVector (argv[2], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((fvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  ResetVector (rvec, OPIHI_FLT, Nx*Ny);
+  ResetVector (fvec, OPIHI_FLT, Nx*Ny);
+
+  Xo = atof(argv[4]);
+  Yo = atof(argv[5]);
+
+  /* shape parameters */
+  Rmaj = atof (argv[6]);
+  Rmin = atof (argv[7]);
+  phi  = atof (argv[8]);
+
+  /* given Rmaj, Rmin, phi, find Sx, Sy, Sxy */
+  root1 = SQ(1.0 / Rmaj);
+  root2 = SQ(1.0 / Rmin);
+
+  // XXX check this
+  R = 0.5 * (root1 - root2);
+  A1 = 0.25*(root1 + root2) - 0.5*R*cos(2*RAD_DEG*phi);
+  A2 = 0.25*(root1 + root2) + 0.5*R*cos(2*RAD_DEG*phi);
+  A3 = -R*sin(2*RAD_DEG*phi);
+
+  Sx = 0.5/A1;
+  Sy = 0.5/A2;
+  Sxy = A3;
+
+  /* f = exp (-r^alpha), r^2 = (x^2 / 2Sx) + (y^2 / 2Sy) + Sxy*x*y */
+  in = (float *) buf[0].matrix.buffer;
+  for (i = iy = 0; iy < Ny; iy++) {
+      for (ix = 0; ix < Nx; ix++, in++, i++) {
+      x = ix + 0.5 - Xo;
+      y = iy + 0.5 - Yo;
+      rvec[0].elements.Flt[i] = sqrt(0.5*x*x/Sx + 0.5*y*y/Sy + x*y*Sxy);
+      fvec[0].elements.Flt[i] = *in;
+    }
+  }
+  rvec[0].Nelements = fvec[0].Nelements = i;
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galcontour.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galcontour.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galcontour.c	(revision 25766)
@@ -0,0 +1,89 @@
+# include "astro.h"
+
+XXX probably not a great algorithm...
+
+
+int galcontour (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, N, Nsec, NELEMENTS, Npt;
+  float *in;
+  double theta, dtheta, x, y, Xo, Yo;
+  Buffer *buf;
+  Vector *xvec, *yvec, *tvec;
+  char name[128];
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: galcontour (buffer) (Xo) (Yo) (flux)\n");
+    gprint (GP_ERR, "  generate contour points (Cx) (Cy) (Ct)\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].header.Naxis[0];
+  Ny = buf[0].header.Naxis[1];
+  
+  Xo = atof(argv[2]);
+  Yo = atof(argv[3]);
+  flux = atof(argv[4]);
+
+  if ((xvec = SelectVector ("Cx", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector ("Cy", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((tvec = SelectVector ("Ct", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  N = 0;
+  NELEMENTS = 100;
+  ResetVector (xvec, OPIHI_FLT, NELEMENTS);
+  ResetVector (yvec, OPIHI_FLT, NELEMENTS);
+  ResetVector (tvec, OPIHI_FLT, NELEMENTS);
+
+  in = (float *) buf[0].matrix.buffer;
+
+  // find the flux transition for each row until not found
+
+  // first go up:
+  for (j = Yo; j < Ny; j++) {
+    
+    // first go left
+    for (i = Xo; i >= 0; i--) {
+      F = in[i + j*Nx];
+      if (F < flux) {
+	// interpolate to flux value between f[i,j] and f[i+1,j]
+      }
+    }
+
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, in++) {
+      x = i - Xo;
+      y = j - Yo;
+      theta = DEG_RAD*atan2(y, x);
+      if (theta < -0.5*dtheta) theta += 360.0; // need to allow -0.5dtheta for first bin
+      if (theta > 360 - 0.5*dtheta) theta -= 360.0; // need to allow -0.5dtheta for first bin
+      N = (int)(theta / dtheta + 0.5);
+      if (N < 0) {
+	fprintf (stderr, "?");
+	continue;
+      }
+      if (N >= Nsec) {
+	fprintf (stderr, "!");
+	continue;
+      }
+      
+      fvec[N][0].elements.Flt[fvec[N][0].Nelements] = *in;
+      rvec[N][0].elements.Flt[rvec[N][0].Nelements] = hypot(x, y);
+      fvec[N][0].Nelements ++;
+      rvec[N][0].Nelements ++;
+
+      *in = N;
+
+      if (fvec[N][0].Nelements >= NELEMENTS) {
+	NELEMENTS += 1000;
+	for (N = 0; N < Nsec; N++) {
+	  REALLOCATE (fvec[N][0].elements.Flt, opihi_flt, NELEMENTS);
+	  REALLOCATE (rvec[N][0].elements.Flt, opihi_flt, NELEMENTS);
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galprofiles.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galprofiles.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galprofiles.c	(revision 25766)
@@ -0,0 +1,187 @@
+# include "astro.h"
+
+double Interpolate (const double x, const double y, float *in, int Nx, int Ny);
+
+int galprofiles (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, N, Nsec, NELEMENTS;
+  float *in;
+  double theta, dtheta, x, y, Xo, Yo, r, Rmax, value;
+  Buffer *buf;
+  Vector **fvec, **rvec, *tvec;
+  char name[128];
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: galprofiles (buffer) (Xo) (Yo) Nsec\n");
+    gprint (GP_ERR, "  generates Nsec profiles around the circle; the first is centered on 0.0 degrees\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].header.Naxis[0];
+  Ny = buf[0].header.Naxis[1];
+  Rmax = 0.5*hypot(Nx, Ny);
+  
+  Xo = atof(argv[2]);
+  Yo = atof(argv[3]);
+  Nsec = atof(argv[4]);
+
+  dtheta = 360.0 / Nsec;
+  // sector i ranges from (i-0.5)*dtheta to (i+0.5)*dtheta
+  // i = theta / dtheta + 0.5;
+
+  ALLOCATE (fvec, Vector *, Nsec);
+  ALLOCATE (rvec, Vector *, Nsec);
+  if ((tvec = SelectVector ("theta", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  ResetVector (tvec, OPIHI_FLT, Nsec);
+
+  // dereference pointer
+  in = (float *) buf[0].matrix.buffer;
+
+  for (i = 0; i < Nsec; i++) {
+
+    // generate the output vector names & vectors
+    sprintf (name, "flux_%d", i);
+    if ((fvec[i] = SelectVector (name, ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    sprintf (name, "rad_%d", i);
+    if ((rvec[i] = SelectVector (name, ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+    // allocate initial data space
+    N = 0;
+    NELEMENTS = 1000;
+    ResetVector (fvec[i], OPIHI_FLT, NELEMENTS);
+    ResetVector (rvec[i], OPIHI_FLT, NELEMENTS);
+
+    // angle for this profile
+    tvec[0].elements.Flt[i] = i*dtheta;
+    theta = RAD_DEG*i*dtheta;
+
+    // start at Xo,Yo and find the x,y locations for r_i, theta where r_i increments by 1 pixel
+    for (r = 0; r < Rmax; r++) {
+
+      // XXX Xo,Yo are referenced to pixels with bounds i+0.0, i+1.0
+      x = r * cos (theta) + Xo;
+      y = r * sin (theta) + Yo;
+
+      // value is NAN if we run off the image
+      value = Interpolate(x, y, in, Nx, Ny);
+      if (isnan(value)) break;
+
+      rvec[i][0].elements.Flt[N] = r;
+      fvec[i][0].elements.Flt[N] = value;
+      N++;
+
+      if (N >= NELEMENTS) {
+	NELEMENTS += 100;
+	REALLOCATE (rvec[N][0].elements.Flt, opihi_flt, NELEMENTS);
+	REALLOCATE (fvec[N][0].elements.Flt, opihi_flt, NELEMENTS);
+      }
+    }
+    fvec[i][0].Nelements = N;
+    rvec[i][0].Nelements = N;
+  }
+  return (TRUE);
+}
+
+// fast & simple API to interpolate to a subpixel position using bilinear interpolation
+// x,y in parent image coordinates (pixel centers at 0.5, 0.5)
+// stolen from psLib
+double Interpolate (const double x, const double y, float *in, int Nx, int Ny) {
+
+  // allow extrapolation a small distance beyond the edge of valid pixels, but no
+  // further (this allows the nXskip,nYskip boundary areas to be used as well)
+  float nXedge = 0.125*Nx;
+  float nYedge = 0.125*Ny;
+
+  if ((x < -nXedge) || (x > Nx + nXedge) || (y < -nYedge) || (y > Ny + nYedge)) {
+    return NAN;
+  }
+
+  // limiting cases: Nx == 1 and/or Ny == 1
+
+  // if we have a single pixel, there is no spatial information
+  if ((Nx == 1) && (Ny == 1)) {
+    return in[0];
+  }
+
+  // handle edge cases with extrapolation
+  const int ix = x - 0.5; // index of reference pixel
+  const int iy = y - 0.5; // index of reference pixel
+
+  // do numCols,Rows first so we are never < 0
+  const int Xs = MAX (MIN (ix, Nx - 2), 0);
+  const int Ys = MAX (MIN (iy, Ny - 2), 0);
+
+  const int Xe = Xs + 1;
+  const int Ye = Ys + 1;
+
+  // dx,dy range from 0.0 to 1.0 for interpolated pixels, and -0.5 to 1.5 for extrapolation
+  const double dx = x - 0.5 - Xs;
+  const double dy = y - 0.5 - Ys;
+
+  const double rx = 1.0 - dx;
+  const double ry = 1.0 - dy;
+
+  // if Nx == 1, we have no x-dir spatial information
+  if (Nx == 1) {
+    double V0 = in[Ys*Nx + Xs];
+    double V1 = in[Ye*Nx + Xs];
+
+    const double value = V0*ry + V1*dy;
+    return value;
+  }
+
+  // if Ny == 1, we have no y-dir spatial information
+  if (Ny == 1) {
+    double V0 = in[Ys*Nx + Xs];
+    double V1 = in[Ys*Nx + Xe];
+
+    const double value = V0*rx + V1*dx;
+    return value;
+  }
+
+  // Vxy
+  double V00 = in[Ys*Nx + Xs];
+  double V01 = in[Ye*Nx + Xs];
+  double V10 = in[Ys*Nx + Xe];
+  double V11 = in[Ye*Nx + Xe];
+
+  double value;
+
+  // corners
+  if ((dx < 0.0) && (dy < 0.0)) {
+    return V00;
+  }
+  if ((dx > 1.0) && (dy < 0.0)) {
+    return V10;
+  }
+  if ((dx < 0.0) && (dy > 1.0)) {
+    return V01;
+  }
+  if ((dx > 1.0) && (dy > 1.0)) {
+    return V11;
+  }
+
+  // sides
+  if (dx < 0.0) {
+    value = V00*ry + V01*dy;
+    return value;
+  }
+  if (dy < 0.0) {
+    value = V00*rx + V10*dx;
+    return value;
+  }
+  if (dx > 1.0) {
+    value = V10*ry + V11*dy;
+    return value;
+  }
+  if (dy > 1.0) {
+    value = V01*rx + V11*dx;
+    return value;
+  }
+
+  // bilinear interpolation
+  value = V00*rx*ry + V10*dx*ry + V01*rx*dy + V11*dx*dy;
+  return value;
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galradbins.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galradbins.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galradbins.c	(revision 25766)
@@ -0,0 +1,84 @@
+# include "astro.h"
+
+int MeanSurfaceBrightness (Vector *rvec, Vector *fvec, Vector *Rvec, Vector *Fvec, Vector *Avec, float Rmin, float Rmax, int bin);
+
+// given a collection of r, f points sampled at pixels, generate a pair of vectors r, f
+// where f is defined as the mean surface brightness for \alpha r_i < r < \beta r_i.
+// sample r at r_i = i
+
+// this function can be much more efficient if the input vectors are sorted by R and that
+// fact is used in generating the radial bins...
+int galradbins (int argc, char **argv) {
+  
+  int i, Nbin;
+  double Rmin, Rmax;
+  Vector *fvec, *rvec, *Fvec, *Rvec, *Avec;
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: galradius (r_in) (f_in) (r_out) (f_out) (area_out)\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((rvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((fvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Rvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Fvec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Avec = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Rmax = rvec[0].elements.Flt[0];
+  for (i = 0; i < rvec[0].Nelements; i++) {
+    Rmax = MAX(Rmax, rvec[0].elements.Flt[i]);
+  }
+  Nbin = 0.8*Rmax + 2;
+  ResetVector (Rvec, OPIHI_FLT, Nbin);
+  ResetVector (Fvec, OPIHI_FLT, Nbin);
+  ResetVector (Avec, OPIHI_FLT, Nbin);
+
+  // the first three bins are specially defined:
+
+  // 0 : r < 1.0 -- Area is pi
+  MeanSurfaceBrightness (rvec, fvec, Rvec, Fvec, Avec, 0.00, 1.00, 0);
+
+  // area is \int 2 \pi r dr = \pi (r2^2 - r1^2)
+
+  // 1 : 1.0 < r < 1.25 -- Area is \pi (1.25^2 - 1^2)
+  MeanSurfaceBrightness (rvec, fvec, Rvec, Fvec, Avec, 1.00, 1.25, 1);
+
+  // 2 : 1.25 < r < 1.60 -- Area is \pi (1.6^2 - 1.25^2)
+  MeanSurfaceBrightness (rvec, fvec, Rvec, Fvec, Avec, 1.25, 1.60, 2);
+
+  // from bin 3 on out, r = i - 1 
+  for (i = 3; i < Nbin; i++) {
+    MeanSurfaceBrightness (rvec, fvec, Rvec, Fvec, Avec, 0.8*(i-1), 1.25*(i-1), i);
+  }
+
+  return (TRUE);
+}
+
+int MeanSurfaceBrightness (Vector *rvec, Vector *fvec, Vector *Rvec, Vector *Fvec, Vector *Avec, float Rmin, float Rmax, int bin) {
+
+  int i, Npts;
+  double Fsum;
+
+  Fsum = Npts = 0;
+
+  for (i = 0; i < rvec[0].Nelements; i++) {
+    if (rvec[0].elements.Flt[i] < Rmin) continue;
+    if (rvec[0].elements.Flt[i] > Rmax) continue;
+    Fsum += fvec[0].elements.Flt[i];
+    Npts ++;
+  }
+  if (Rmin > 0.0) {
+    Rvec[0].elements.Flt[bin] = sqrt(Rmin * Rmax); // XXX what is the correct mean radius?
+  } else {
+    Rvec[0].elements.Flt[bin] = 0.5 * Rmax; // XXX what is the correct mean radius?
+  }
+  if (Npts > 0) {
+    Fvec[0].elements.Flt[bin] = Fsum / Npts; // XXX what is the correct mean radius?
+  } else {
+    Fvec[0].elements.Flt[bin] = NAN; // XXX what is the correct mean radius?
+  }
+  Avec[0].elements.Flt[bin] = M_PI * (SQ(Rmax) - SQ(Rmin));
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galradius.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galradius.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galradius.c	(revision 25766)
@@ -0,0 +1,123 @@
+# include "astro.h"
+
+// given an image and associated galaxy profile, find:
+// a) a characteristic flux level that defines a useful isophot
+// b) radius at which the profile crosses that isophot
+int galradius (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, N, Nsec, NELEMENTS, Rbin, Nout, above;
+  double theta, dtheta, x, y, Xo, Yo, r, Rmax, Rmin, value;
+  double Fmin, Fmax, dF, Fm, Fp, Fo, Rsum, Rnpt, Ro;
+  opihi_flt *flux, *radius, *values;
+  Buffer *buf;
+  Vector *fvec, *rvec, *tvec, *Fvec, *Rvec;
+  char name[128];
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: galradius (radius) (flux) (min_flux) (max_flux)\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((rvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((fvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  if ((Rvec = SelectVector ("rg", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Fvec = SelectVector ("fg", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  Fmin = atof(argv[3]);
+  Fmax = atof(argv[4]);
+
+  // fvec is a noise sample of the galaxy radial profile at points rvec
+  // rebin fvec into samples defined by the isophot 
+
+  // base selections on fluxes defined by the flux range dF
+  dF = Fmax - Fmin;
+
+  // select all points with flux in the range Fmin + 0.25*dF to Fmin + 0.75*dF
+  Fm = Fmin + 0.25*dF;
+  Fp = Fmin + 0.75*dF;
+  Fo = Fmin + 0.50*dF;
+      
+  Rsum = 0;
+  Rnpt = 0;
+  for (i = 0; i < fvec[0].Nelements; i++) {
+    if (fvec[0].elements.Flt[i] < Fm) continue;
+    if (fvec[0].elements.Flt[i] > Fp) continue;
+      
+    Rsum += rvec[0].elements.Flt[i];
+    Rnpt ++;
+  }
+
+  // determine the binned radius values
+  if (Rnpt == 0) {
+    Rbin = 1;
+  } else {
+    Rbin = MAX(1, 0.5*(Rsum / Rnpt));
+  }
+
+  // do not bother rebinning if the bin size is only 2 or less
+  if (Rbin <= 2) {
+    Nout   = fvec[0].Nelements;
+    ResetVector (Rvec, OPIHI_FLT, Nout);
+    ResetVector (Fvec, OPIHI_FLT, Nout);
+    memcpy (Fvec[0].elements.Flt, fvec[0].elements.Flt, Fvec[0].Nelements*sizeof(opihi_flt));
+    memcpy (Rvec[0].elements.Flt, rvec[0].elements.Flt, Rvec[0].Nelements*sizeof(opihi_flt));
+    flux   = fvec[0].elements.Flt;
+    radius = rvec[0].elements.Flt;
+  } else {
+    // rebin the vectors by Rbin values:
+    Nout = fvec[0].Nelements / Rbin + 1;
+    ALLOCATE (values, opihi_flt, fvec[0].Nelements);
+  
+    ResetVector (Rvec, OPIHI_FLT, Nout);
+    ResetVector (Fvec, OPIHI_FLT, Nout);
+    flux   = Fvec[0].elements.Flt;
+    radius = Rvec[0].elements.Flt;
+
+    for (i = 0; i < Nout; i++) {
+      radius[i] = (i + 0.5)*Rbin;
+      Rmin = radius[i] - 0.5*Rbin;
+      Rmax = radius[i] + 0.5*Rbin;
+
+      N = 0;
+      for (j = 0; j < fvec[0].Nelements; j++) {
+	if (rvec[0].elements.Flt[j] < Rmin) continue;
+	if (rvec[0].elements.Flt[j] > Rmax) continue;
+	values[N] = fvec[0].elements.Flt[j];
+	N++;
+      }
+
+      // take the median of the values
+      dsort (values, N);
+      if (N > 1) {
+	flux[i] = (N % 2) ? values[(int)(0.5*N)] : 0.5*(values[N/2] + values[N/2 + 1]);
+      } else {
+	flux[i] = values[0];
+      }
+    }
+    free (values);
+  }
+
+  above = TRUE;
+  for (i = 0; i < Nout; i++) {
+
+    // find the largest radius that matches the flux transition
+    if (above && (flux[i] < Fo)) {
+      if (i == 0) { 
+	// assume Fmax @ R = 0.0
+	Ro = radius[i] * (Fo - Fmax) / (flux[i] - Fmax);
+      } else {
+	Ro = radius[i-1] + (radius[i] - radius[i-1]) * (Fo - flux[i-1]) / (flux[i] - flux[i-1]);
+      }
+      above = FALSE;
+    }
+  
+    if (!above && (flux[i] >= Fo)) {
+      above = TRUE;
+    }
+  }
+
+  set_variable ("G_R50", Ro);
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galsectors.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galsectors.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/galsectors.c	(revision 25766)
@@ -0,0 +1,107 @@
+# include "astro.h"
+
+int galsectors (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, N, Nsec, NELEMENTS, Npt;
+  float *in;
+  double theta, dtheta, x, y, Xo, Yo;
+  Buffer *buf;
+  Vector **fvec, **rvec, *tvec, *Rv, *Tv, *Fv;
+  char name[128];
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: galsectors (buffer) (Xo) (Yo) Nsec\n");
+    gprint (GP_ERR, "  generates Nsec sectors around the circle; the first is centered on 0.0 degrees\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].header.Naxis[0];
+  Ny = buf[0].header.Naxis[1];
+  
+  Xo = atof(argv[2]);
+  Yo = atof(argv[3]);
+  Nsec = atof(argv[4]);
+
+  // for a test, generate R, theta vectors for the whole image:
+  if ((Rv = SelectVector ("Rvec", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Tv = SelectVector ("Tvec", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Fv = SelectVector ("Fvec", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  ResetVector (Rv, OPIHI_FLT, Nx*Ny);
+  ResetVector (Tv, OPIHI_FLT, Nx*Ny);
+  ResetVector (Fv, OPIHI_FLT, Nx*Ny);
+
+  in = (float *) buf[0].matrix.buffer;
+  Npt = 0;
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, in++) {
+      x = i - Xo;
+      y = j - Yo;
+      Rv[0].elements.Flt[Npt] = hypot(x, y);
+      Tv[0].elements.Flt[Npt] = DEG_RAD*atan2(y, x);
+      Fv[0].elements.Flt[Npt] = *in;
+      Npt ++;
+    }
+  }
+  return (TRUE);
+
+  dtheta = 360.0 / Nsec;
+  // sector i ranges from (i-0.5)*dtheta to (i+0.5)*dtheta
+  // i = theta / dtheta + 0.5;
+
+  ALLOCATE (fvec, Vector *, Nsec);
+  ALLOCATE (rvec, Vector *, Nsec);
+  if ((tvec = SelectVector ("theta", ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  ResetVector (tvec, OPIHI_FLT, Nsec);
+
+  // generate the output vector names
+  NELEMENTS = 1000;
+  for (i = 0; i < Nsec; i++) {
+    sprintf (name, "flux_%d", i);
+    if ((fvec[i] = SelectVector (name, ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    sprintf (name, "rad_%d", i);
+    if ((rvec[i] = SelectVector (name, ANYVECTOR, TRUE)) == NULL) return (FALSE);
+    ResetVector (fvec[i], OPIHI_FLT, NELEMENTS);
+    ResetVector (rvec[i], OPIHI_FLT, NELEMENTS);
+    fvec[i][0].Nelements = 0;
+    rvec[i][0].Nelements = 0;
+    tvec[0].elements.Flt[i] = i*dtheta;
+  }
+
+  in = (float *) buf[0].matrix.buffer;
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, in++) {
+      x = i - Xo;
+      y = j - Yo;
+      theta = DEG_RAD*atan2(y, x);
+      if (theta < -0.5*dtheta) theta += 360.0; // need to allow -0.5dtheta for first bin
+      if (theta > 360 - 0.5*dtheta) theta -= 360.0; // need to allow -0.5dtheta for first bin
+      N = (int)(theta / dtheta + 0.5);
+      if (N < 0) {
+	fprintf (stderr, "?");
+	continue;
+      }
+      if (N >= Nsec) {
+	fprintf (stderr, "!");
+	continue;
+      }
+      
+      fvec[N][0].elements.Flt[fvec[N][0].Nelements] = *in;
+      rvec[N][0].elements.Flt[rvec[N][0].Nelements] = hypot(x, y);
+      fvec[N][0].Nelements ++;
+      rvec[N][0].Nelements ++;
+
+      *in = N;
+
+      if (fvec[N][0].Nelements >= NELEMENTS) {
+	NELEMENTS += 1000;
+	for (N = 0; N < Nsec; N++) {
+	  REALLOCATE (fvec[N][0].elements.Flt, opihi_flt, NELEMENTS);
+	  REALLOCATE (rvec[N][0].elements.Flt, opihi_flt, NELEMENTS);
+	}
+      }
+    }
+  }
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/init.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/init.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/init.c	(revision 25766)
@@ -5,4 +5,5 @@
 int cgrid                   PROTO((int, char **));
 int coords                  PROTO((int, char **));
+int cdot                    PROTO((int, char **));
 int cplot                   PROTO((int, char **));
 int csystem                 PROTO((int, char **));
@@ -22,5 +23,12 @@
 int imsub                   PROTO((int, char **));
 int medianmap               PROTO((int, char **));
+int galsectors              PROTO((int, char **));
+int galprofiles             PROTO((int, char **));
+int galradius               PROTO((int, char **));
+int galradbins              PROTO((int, char **));
+int elliprofile             PROTO((int, char **));
+int petrosian               PROTO((int, char **));
 int mkgauss                 PROTO((int, char **));
+int mksersic                PROTO((int, char **));
 int multifit                PROTO((int, char **));
 int objload                 PROTO((int, char **));
@@ -44,4 +52,5 @@
   {1, "cgrid",       cgrid,        "plot sky coordinate grid"},
   {1, "coords",      coords,       "load coordinates for buffer from file"},
+  {1, "cdot",        cdot,         "plot point in sky coordinates"},
   {1, "cplot",       cplot,        "plot vectors in sky coordinates"},
   {1, "csystem",     csystem,      "convert between coordinate systems"},
@@ -61,4 +70,11 @@
   {1, "medianmap",   medianmap,    "small median image"},
   {1, "mkgauss",     mkgauss,      "generate a 2-D gaussian centered in image"},
+  {1, "mksersic",    mksersic,     "generate a 2-D sersic profile"},
+  {1, "galsectors",  galsectors,   "generate radial vectors for sectors of width dtheta"},
+  {1, "galprofiles", galprofiles,  "generate radial vectors with interpolation along paths"},
+  {1, "galradius",   galradius,    "generate radial vectors with interpolation along paths"},
+  {1, "galradbins",  galradbins,   "generate radial vectors with interpolation along paths"},
+  {1, "elliprofile", elliprofile,  "generate radial vectors with interpolation along paths"},
+  {1, "petrosian",   petrosian,    "petrosian parameters given radial bins"},
   {1, "multifit",    multifit,     "fit multi-order spectrum"},
   {1, "objload",     objload,      "plot obj data on Ximage "},
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/mksersic.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/mksersic.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/mksersic.c	(revision 25766)
@@ -0,0 +1,87 @@
+# include "astro.h"
+
+int mksersic (int argc, char **argv) {
+  
+  int i, j, Nx, Ny, N, center;
+  float *in;
+  double Rmaj, Rmin, Theta, alpha, Io, ARatio;
+  double root1, root2, R, A1, A2, A3;
+  double Sx, Sy, Sxy;
+  double x, y, r, f, Xo, Yo;
+  Buffer *buf;
+
+  Xo = Yo = 0;
+  center = TRUE;
+  if ((N = get_argument (argc, argv, "-coord"))) {
+    remove_argument (N, &argc, argv);
+    Xo = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    Yo = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+    center = FALSE;
+  }
+
+  Theta = 0.0;
+  if ((N = get_argument (argc, argv, "-angle"))) {
+    remove_argument (N, &argc, argv);
+    Theta = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  ARatio = 1.0;
+  if ((N = get_argument (argc, argv, "-aratio"))) {
+    remove_argument (N, &argc, argv);
+    ARatio = atof (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: mksersic (buffer) (Io) (Rmaj) (alpha)\n");
+    return (FALSE);
+  }
+
+  /* select input / output buffers */
+  if ((buf = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  Nx = buf[0].header.Naxis[0];
+  Ny = buf[0].header.Naxis[1];
+  if (center) {
+    Xo = 0.5*Nx;
+    Yo = 0.5*Ny;
+  }
+  
+  Io = atof (argv[2]);
+
+  /* shape parameters */
+  Rmaj = atof (argv[3]);
+  Rmin = Rmaj / ARatio;
+
+  alpha = atof (argv[4]);
+
+  /* given Rmaj, Rmin, Theta, find Sx, Sy, Sxy */
+  root1 = SQ(1.0 / Rmaj);
+  root2 = SQ(1.0 / Rmin);
+
+  // XXX check this
+  R = 0.5 * (root1 - root2);
+  A1 = 0.25*(root1 + root2) - 0.5*R*cos(2*RAD_DEG*Theta);
+  A2 = 0.25*(root1 + root2) + 0.5*R*cos(2*RAD_DEG*Theta);
+  A3 = -R*sin(2*RAD_DEG*Theta);
+
+  Sx = 0.5/A1;
+  Sy = 0.5/A2;
+  Sxy = A3;
+
+  /* f = exp (-r^alpha), r = (x^2 / 2Sx) + (y^2 / 2Sy) + Sxy*x*y */
+  in = (float *) buf[0].matrix.buffer;
+  for (j = 0; j < Ny; j++) {
+    for (i = 0; i < Nx; i++, in++) {
+      x = i + 0.5 - Xo;
+      y = j + 0.5 - Yo;
+      r = pow((0.5*x*x/Sx + 0.5*y*y/Sy + x*y*Sxy), alpha);
+      f = Io*exp (-r);
+      *in += f;
+    }
+  }
+
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/petrosian.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/petrosian.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/petrosian.c	(revision 25766)
@@ -0,0 +1,90 @@
+# include "astro.h"
+
+int petrosian (int argc, char **argv) {
+  
+  int i, above;
+  float *in;
+  double Fsum, Asum, Area, R_90, rad_90, flux_90;
+  Vector *rvec, *avec, *fvec, *Rvec, *Fvec, *Svec, *Avec;
+
+  if (argc != 8) {
+    gprint (GP_ERR, "USAGE: petrosian (radius) (area) (flux) (P_ratio) (P_flux) (P_sb) (P_area)\n");
+    return (FALSE);
+  }
+
+  /* select input vectors */
+  if ((rvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((avec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((fvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Rvec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Fvec = SelectVector (argv[5], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Svec = SelectVector (argv[6], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Avec = SelectVector (argv[7], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  // difficult work goes into cleaning the input galaxy profile:
+  // a) extract radial profiles applying 180 degree symmetry requirement
+  // b) determine the axial ratio and position angle (at r_50)
+  // c) extract normalized radial profiles applying outlier clipping
+  // 
+  // the resulting vectors r, f represent the mean surface brightness at a radius r_i, 
+  // measured between \alpha*r_i and \beta*r_i: f(r_i) = \sum_\alpha*r_i^\beta*r_i flux(r)
+
+  // given a clean set of vectors representing the f_i, r_i, determine F_P, R_P such that:
+  // f(r_i) / \sum_0^r_i f(r) = f_P 
+
+  // generate a vector representing f_P(r_i):
+
+  ResetVector (Fvec, OPIHI_FLT, fvec[0].Nelements);
+  ResetVector (Rvec, OPIHI_FLT, fvec[0].Nelements);
+  ResetVector (Svec, OPIHI_FLT, fvec[0].Nelements);
+  ResetVector (Avec, OPIHI_FLT, fvec[0].Nelements);
+
+  above = TRUE;
+  Fsum = 0.0;
+  Asum = 0.0;
+  Area = avec[0].elements.Flt[0];
+  for (i = 0; i < fvec[0].Nelements; i++) {
+    // for nan bins, we keep the area for use with the next valid bin
+    if (isnan(fvec[0].elements.Flt[i])) {
+      Area += avec[0].elements.Flt[i];
+      continue;
+    } 
+    Fsum += fvec[0].elements.Flt[i] * Area;
+    Asum += Area;
+    if (i+1 < fvec[0].Nelements) {
+      Area = avec[0].elements.Flt[i+1];
+    }
+
+    Rvec[0].elements.Flt[i] = Asum * fvec[0].elements.Flt[i] / Fsum;
+    Fvec[0].elements.Flt[i] = Fsum;
+    Svec[0].elements.Flt[i] = Fsum / Asum;
+    Avec[0].elements.Flt[i] = Asum;
+
+    // anytime we transition below the petrosian ratio R_90, calculate the radius and flux
+    // we will keep and report the last (largest radius) value
+    if (above && (Rvec[0].elements.Flt[i] < R_90)) {
+      // interpolate Rvec between i-1 and i to R_90 to get flux (Fvec) and radius (rvec)
+
+      if (i == 0) { 
+	// assume Fmax @ R = 0.0
+	rad_90  = rvec[0].elements.Flt[i] * (R_90 - 1.0) / (Rvec[0].elements.Flt[i] - 1.0);
+	flux_90 = Fvec[0].elements.Flt[i] * (R_90 - 1.0) / (Rvec[0].elements.Flt[i] - 1.0);
+      } else {
+	rad_90  = rvec[0].elements.Flt[i-1] + (rvec[0].elements.Flt[i] - rvec[0].elements.Flt[i-1]) * (R_90 - Rvec[0].elements.Flt[i-1]) / (Rvec[0].elements.Flt[i] - Rvec[0].elements.Flt[i-1]);
+	flux_90 = Fvec[0].elements.Flt[i-1] + (Fvec[0].elements.Flt[i] - Fvec[0].elements.Flt[i-1]) * (R_90 - Rvec[0].elements.Flt[i-1]) / (Rvec[0].elements.Flt[i] - Rvec[0].elements.Flt[i-1]);
+      }
+
+      above = FALSE;
+    }
+    
+    // reset on transitions up, but do not re-calculate rad_90, flux_90
+    if (!above && (Rvec[0].elements.Flt[i] >= R_90)) {
+      above = TRUE;
+    }
+  }
+
+  set_variable ("P_R90", rad_90);
+  set_variable ("P_F90", flux_90);
+
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/region.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/region.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.astro/region.c	(revision 25766)
@@ -6,5 +6,5 @@
   double Ra, Dec, Radius;
   float dx, dy;
-  int N, kapa;
+  int N, kapa, NoClear;
   char *name;
   Graphdata graphmode;
@@ -46,4 +46,10 @@
     remove_argument (N, &argc, argv);
     graphmode.flipnorth = FALSE;
+  }
+
+  NoClear = FALSE;
+  if ((N = get_argument (argc, argv, "-no-clear"))) {
+    remove_argument (N, &argc, argv);
+    NoClear = TRUE;
   }
 
@@ -122,10 +128,10 @@
   graphmode.coords.cdelt1 = graphmode.coords.cdelt2 = 1.0;
 
-  KapaClearSections (kapa);
+  if (!NoClear) KapaClearSections (kapa);
   KapaSetLimits (kapa, &graphmode);
 
   /* drop this? */
-  sprintf (string, "%8.4f %8.4f (%f)", Ra, Dec, Radius);
-  KapaSendLabel (kapa, string, 2);
+  // sprintf (string, "%8.4f %8.4f (%f)", Ra, Dec, Radius);
+  // KapaSendLabel (kapa, string, 2);
 
   // XXX is this the right thing to be doing?
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.basic/substr.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.basic/substr.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.basic/substr.c	(revision 25766)
@@ -16,9 +16,9 @@
   // add a range check here
   if ((N1 < 0) || (N1 >=  strlen(argv[1]))) {
-      gprint (GP_ERR, "ERROR: N1 out of range\n");
+      gprint (GP_ERR, "ERROR: start value out of range in substr command\n");
       return (FALSE);
   }
   if ((N2 < 0) || ((N2+N1) >  strlen(argv[1]))) {
-      gprint (GP_ERR, "ERROR: N2 out of range\n");
+      gprint (GP_ERR, "ERROR: end value out of range in substr command\n");
       return (FALSE);
   }
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/Makefile	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/Makefile	(revision 25766)
@@ -97,4 +97,5 @@
 $(SRC)/rebin.$(ARCH).o		\
 $(SRC)/resize.$(ARCH).o	\
+$(SRC)/relocate.$(ARCH).o	\
 $(SRC)/roll.$(ARCH).o		\
 $(SRC)/rotate.$(ARCH).o	\
@@ -110,5 +111,5 @@
 $(SRC)/style.$(ARCH).o		   \
 $(SRC)/subraster.$(ARCH).o	   \
-$(SRC)/subset.$(ARCH).o	   \
+$(SRC)/subset.$(ARCH).o	           \
 $(SRC)/svd.$(ARCH).o		   \
 $(SRC)/swapbytes.$(ARCH).o	   \
@@ -118,11 +119,13 @@
 $(SRC)/tvcolors.$(ARCH).o	   \
 $(SRC)/tvcontour.$(ARCH).o	   \
-$(SRC)/tvgrid.$(ARCH).o	   \
+$(SRC)/tvgrid.$(ARCH).o	           \
 $(SRC)/uniq.$(ARCH).o		   \
-$(SRC)/unsign.$(ARCH).o	   \
+$(SRC)/unsign.$(ARCH).o	           \
 $(SRC)/vbin.$(ARCH).o		   \
+$(SRC)/vgroup.$(ARCH).o		   \
 $(SRC)/vclip.$(ARCH).o		   \
-$(SRC)/vgauss.$(ARCH).o           \
-$(SRC)/vmaxwell.$(ARCH).o           \
+$(SRC)/vgauss.$(ARCH).o            \
+$(SRC)/vellipse.$(ARCH).o          \
+$(SRC)/vmaxwell.$(ARCH).o          \
 $(SRC)/vgrid.$(ARCH).o		   \
 $(SRC)/vload.$(ARCH).o		   \
@@ -130,5 +133,5 @@
 $(SRC)/vpop.$(ARCH).o		   \
 $(SRC)/vroll.$(ARCH).o		   \
-$(SRC)/vsmooth.$(ARCH).o	\
+$(SRC)/vsmooth.$(ARCH).o	   \
 $(SRC)/vstats.$(ARCH).o		   \
 $(SRC)/wd.$(ARCH).o		   \
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/init.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/init.c	(revision 25766)
@@ -85,4 +85,5 @@
 int rebin            PROTO((int, char **));
 int resize           PROTO((int, char **));
+int relocate         PROTO((int, char **));
 int roll             PROTO((int, char **));
 int rotate           PROTO((int, char **));
@@ -110,8 +111,10 @@
 int unsign           PROTO((int, char **));
 int vbin             PROTO((int, char **));
+int vgroup           PROTO((int, char **));
 int vclip            PROTO((int, char **));
 int vect_select      PROTO((int, char **));
 int vgrid            PROTO((int, char **));
 int vgauss           PROTO((int, char **));
+int vellipse         PROTO((int, char **));
 int vmaxwell         PROTO((int, char **));
 int vload            PROTO((int, char **));
@@ -218,4 +221,5 @@
   {1, "rebin",        rebin,            "rebin image data by factor of N"},
   {1, "resize",       resize,           "set graphics/image window size"},
+  {1, "relocate",     relocate,         "set graphics/image window position"},
   {1, "roll",         roll,             "roll image to new start point"},
   {1, "rotate",       rotate,           "rotate image"},
@@ -243,8 +247,10 @@
   {1, "uniq",         uniq,             "create a uniq vector subset from a vector"},
   {1, "unsign",       unsign,           "toggle the UNSIGN status"},
-  {1, "vbin",         vbin,             "rebin vector data by a fector of N"},
+  {1, "vbin",         vbin,             "rebin vector data by a factor of N"},
+  {1, "vgroup",       vgroup,           "group y vector into bins defined by x vector values"},
   {1, "vclip",        vclip,            "clip values in a vector to be within a range"},
   {1, "vectors",      list_vectors,     "list vectors"},
   {1, "vgauss",       vgauss,           "fit a Gaussian to a vector"},
+  {1, "vellipse",     vellipse,         "fit a Ellipse to a vector pair"},
   {1, "vgrid",        vgrid,            "generate an image from a triplet of vectors"},
   {1, "vhistogram",   histogram,        "generate histogram from vector"},
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/relocate.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/relocate.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/relocate.c	(revision 25766)
@@ -0,0 +1,33 @@
+# include "data.h"
+
+int relocate (int argc, char **argv) {
+
+  char *end;
+  int x, y;
+  int N, kapa;
+  char *name;
+  
+  /* display source */
+  name = NULL;
+  if ((N = get_argument (argc, argv, "-n"))) {
+    remove_argument (N, &argc, argv);
+    name = strcreate (argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+  if (!GetImage (NULL, &kapa, name)) return (FALSE);
+  FREE (name);
+
+  if (argc != 3) {
+    gprint (GP_ERR, "USAGE: relocate x y [-n]\n");
+    return (FALSE);
+  }
+
+  /* x & y are pixels for the screen -- this command has no meaning for non-X */
+
+  x = atoi (argv[1]);
+  y = atoi (argv[2]);
+
+  KiiRelocate (kapa, x, y);
+  return (TRUE);
+}
+
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/rotate.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/rotate.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/rotate.c	(revision 25766)
@@ -287,5 +287,5 @@
       if (Y >= NY - 1) continue;
 
-      c = &in_buff[X * NX*Y];
+      c = &in_buff[X + NX*Y];
       fx = x - X;
       fy = y - Y;
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/subset.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/subset.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/subset.c	(revision 25766)
@@ -6,5 +6,5 @@
   
   char *out;
-  int  i, Npts, size;
+  int  i, Npts, size, valid;
   Vector *ivec, *ovec, *tvec;
 
@@ -12,6 +12,10 @@
   ivec = ovec = tvec = NULL;
 
-  if ((argc < 6) || strcmp(argv[2], "=") || strcmp (argv[4], "if")) {
-    gprint (GP_ERR, "SYNTAX: subset vec = vec if (logic expression)\n");
+  valid = TRUE;
+  valid &= (argc >= 6);
+  valid &= !strcmp(argv[2], "=");
+  valid &= !strcmp(argv[4], "if") || !strcmp (argv[4], "where");
+  if (!valid) {
+    gprint (GP_ERR, "SYNTAX: subset vec = vec [if/where] (logic expression)\n");
     return (FALSE);
   }
@@ -76,5 +80,5 @@
   return (TRUE);
 
- error:
+error:
   DeleteVector (tvec);
   DeleteVector (ovec);
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/tvcolors.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/tvcolors.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/tvcolors.c	(revision 25766)
@@ -19,4 +19,5 @@
   if (argc != 2) {
     gprint (GP_ERR, "USAGE: tvcolors (colormap)\n");
+    gprint (GP_ERR, " colormap options : greyscale, -greyscale, rainbow, heat, fullcolor, ruffcolor (also grayscale, -grayscale)\n");
     return (FALSE);
   }
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/vellipse.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/vellipse.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/vellipse.c	(revision 25766)
@@ -0,0 +1,272 @@
+# include "data.h"
+
+/* local private functions */
+opihi_flt fellipseOD (opihi_flt theta, opihi_flt *par, int Npar, opihi_flt *dpar);
+
+// enum {PAR_X0, PAR_Y0, PAR_RX, PAR_RY, PAR_T0, PAR_P0};
+enum {PAR_RMIN, PAR_EPSILON, PAR_PHI};
+
+# define GET_VAR(V,A) { \
+  char *c; \
+  c = get_variable (A); \
+  if (c == NULL) { \
+    gprint (GP_ERR, "missing fit parameter A\n"); \
+    return (FALSE); \
+  } \
+  V = atof (c); \
+  free (c); }
+
+int vellipse (int argc, char **argv) {
+
+  int i, N, Npts, Npar, Quiet;
+  opihi_flt par[6], *pos, *dpos, *theta, **covar;
+  opihi_flt chisq, ochisq, dchisq;
+  // opihi_flt Rmaj;
+  opihi_flt Xmin, Xmax, Ymin, Ymax;
+  Vector *xvec, *yvec, *Xvec, *Yvec, *tvec;
+
+  Quiet = FALSE;
+  if ((N = get_argument (argc, argv, "-q"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+  if ((N = get_argument (argc, argv, "-quiet"))) {
+    Quiet = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: vellipse <xobs> <yobs> <xfit> <yfit> (theta)\n");
+    // gprint (GP_ERR, " uses guesses: E_X0, E_Y0, E_RMAJ, E_RMIN, E_THETA\n");
+    gprint (GP_ERR, " uses guesses: E_RMAJ, E_RMIN, E_PHI\n");
+    return (FALSE);
+  }
+  
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Xvec = SelectVector (argv[3], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((Yvec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((tvec = SelectVector (argv[5], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+
+  REQUIRE_VECTOR_FLT (xvec, FALSE); 
+  REQUIRE_VECTOR_FLT (yvec, FALSE); 
+
+  // GET_VAR (par[PAR_X0], "E_X0");
+  // GET_VAR (par[PAR_Y0], "E_Y0");
+  // GET_VAR (par[PAR_RX], "E_RMAJ");
+  // GET_VAR (par[PAR_RY], "E_RMIN");
+  // GET_VAR (par[PAR_T0], "E_THETA");
+  // GET_VAR (par[PAR_P0], "E_PHI");
+  // Npar = 6;
+
+  // we need to generate a vector of alternating x,y values and the independent variable theta:
+  Xmax = Ymax = Xmin = Ymin = 0.0;
+  ALLOCATE (pos,   opihi_flt, 2*xvec[0].Nelements); 
+  ALLOCATE (dpos,  opihi_flt, 2*xvec[0].Nelements); 
+  ALLOCATE (theta, opihi_flt, 2*xvec[0].Nelements); 
+  for (i = 0; i < xvec[0].Nelements; i++) {
+    pos[2*i+0]   = xvec[0].elements.Flt[i];
+    pos[2*i+1]   = yvec[0].elements.Flt[i];
+    Xmin = MIN (Xmin, xvec[0].elements.Flt[i]);
+    Xmax = MAX (Xmax, xvec[0].elements.Flt[i]);
+    Ymin = MIN (Ymin, yvec[0].elements.Flt[i]);
+    Ymax = MAX (Ymax, yvec[0].elements.Flt[i]);
+    dpos[2*i+0]  = 1.0;
+    dpos[2*i+1]  = 1.0;
+    theta[2*i+0] = atan2(yvec[0].elements.Flt[i], xvec[0].elements.Flt[i]);
+    theta[2*i+1] = theta[2*i+0];
+    // fprintf (stderr, "x,y: %f, %f -> %f, %f\n", yvec[0].elements.Flt[i], xvec[0].elements.Flt[i], yvec[0].elements.Flt[i] - par[PAR_Y0], xvec[0].elements.Flt[i] - par[PAR_X0]);
+    // fprintf (stderr, "x,y: %f, %f -> %f, %f\n", yvec[0].elements.Flt[i], xvec[0].elements.Flt[i], yvec[0].elements.Flt[i] - par[PAR_Y0], xvec[0].elements.Flt[i] - par[PAR_X0]);
+    // fprintf (stderr, "theta: %f - %f : %f\n", DEG_RAD*theta[2*i+0], tvec[0].elements.Flt[i], DEG_RAD*theta[2*i+0] - tvec[0].elements.Flt[i]);
+  }
+  Npts = 2*xvec[0].Nelements;
+
+  // basic guess from range, PHI in degrees, converted to radians
+  // GET_VAR (Rmaj,          "E_RMAJ");
+  // GET_VAR (par[PAR_RMIN], "E_RMIN");
+  // GET_VAR (par[PAR_PHI],  "E_PHI");
+  par[PAR_PHI] = 0.0;
+  par[PAR_EPSILON] = 0.5;
+  par[PAR_RMIN] = 0.25*((Xmax - Xmin) + (Ymax - Ymin));
+  Npar = 3;
+
+  ochisq = mrqinit (theta, pos, dpos, Npts, par, Npar, fellipseOD, !Quiet);
+  dchisq = ochisq + 2*Npts;
+  chisq  = ochisq + dchisq;
+
+  for (i = 0; (i < 20) && (chisq > 1e-3) && ((dchisq > 0.001*(Npts - Npar)) || (dchisq <= 0.0)); i++) {
+    chisq = mrqmin (theta, pos, dpos, Npts, par, Npar, fellipseOD, !Quiet);
+    dchisq = ochisq - chisq;
+    ochisq = chisq;
+    if (!Quiet) gprint (GP_ERR, "dchisq: %f, Ndof: %d\n", dchisq, Npts - Npar);
+  }  
+  if (!Quiet) gprint (GP_ERR, "%d iterations\n", i); 
+
+  ResetVector (Xvec, OPIHI_FLT, xvec[0].Nelements);
+  ResetVector (Yvec, OPIHI_FLT, xvec[0].Nelements);
+  for (i = 0; i < xvec[0].Nelements; i++) {
+    Xvec[0].elements.Flt[i] = fellipseOD (theta[2*i+0], par, Npar, dpos);
+    Yvec[0].elements.Flt[i] = fellipseOD (theta[2*i+1], par, Npar, dpos);
+  }
+  Xvec[0].Nelements = xvec[0].Nelements;
+  Yvec[0].Nelements = xvec[0].Nelements;
+
+  covar = mrqcovar (Npar);
+  //set_variable ("E_X0",   par[PAR_X0]);
+  //set_variable ("E_Y0",   par[PAR_Y0]);
+  //set_variable ("E_RMAJ", par[PAR_RX]);
+  //set_variable ("E_RMIN", par[PAR_RY]);
+  //set_variable ("E_T0",   par[PAR_T0]);
+  //set_variable ("E_P0",   par[PAR_P0]);
+
+  set_variable ("E_RMAJ", par[PAR_RMIN] / par[PAR_EPSILON]);
+  set_variable ("E_RMIN", par[PAR_RMIN]);
+  set_variable ("E_PHI",  DEG_RAD*par[PAR_PHI]);
+
+  // set_variable ("dE_X0",   sqrt(covar[PAR_X0][PAR_X0]));
+  // set_variable ("dE_Y0",   sqrt(covar[PAR_Y0][PAR_Y0]));
+  // set_variable ("dE_RMAJ", sqrt(covar[PAR_RX][PAR_RX]));
+  // set_variable ("dE_RMIN", sqrt(covar[PAR_RY][PAR_RY]));
+  // set_variable ("dE_T0",   sqrt(covar[PAR_T0][PAR_T0]));
+  // set_variable ("dE_P0",   sqrt(covar[PAR_P0][PAR_P0]));
+
+  set_variable ("dE_RMAJ", sqrt(covar[PAR_EPSILON][PAR_EPSILON]*covar[PAR_RMIN][PAR_RMIN]));
+  set_variable ("dE_RMIN", sqrt(covar[PAR_RMIN][PAR_RMIN]));
+  set_variable ("dE_PHI",  DEG_RAD*sqrt(covar[PAR_PHI][PAR_PHI]));
+
+  // if (!Quiet) gprint (GP_ERR, "Xo : %f +/- %f\n", par[PAR_X0], sqrt(covar[PAR_X0][PAR_X0]));
+  // if (!Quiet) gprint (GP_ERR, "Yo : %f +/- %f\n", par[PAR_Y0], sqrt(covar[PAR_Y0][PAR_Y0]));
+  // if (!Quiet) gprint (GP_ERR, "RX : %f +/- %f\n", par[PAR_RX], sqrt(covar[PAR_RX][PAR_RX]));
+  // if (!Quiet) gprint (GP_ERR, "RY : %f +/- %f\n", par[PAR_RY], sqrt(covar[PAR_RY][PAR_RY]));
+  // if (!Quiet) gprint (GP_ERR, "To : %f +/- %f\n", par[PAR_T0], sqrt(covar[PAR_T0][PAR_T0]));
+  // if (!Quiet) gprint (GP_ERR, "Po : %f +/- %f\n", par[PAR_P0], sqrt(covar[PAR_P0][PAR_P0]));
+
+  if (!Quiet) gprint (GP_ERR, "RMAJ : %f +/- %f\n", par[PAR_RMIN] / par[PAR_EPSILON], 0.0);
+  if (!Quiet) gprint (GP_ERR, "RMIN : %f +/- %f\n", par[PAR_RMIN], sqrt(covar[PAR_RMIN][PAR_RMIN]));
+  if (!Quiet) gprint (GP_ERR, "PHI  : %f +/- %f\n", DEG_RAD*par[PAR_PHI],  sqrt(covar[PAR_PHI][PAR_PHI]));
+
+  free (pos);
+  free (dpos);
+  free (theta);
+
+  mrqfree (Npar);
+  return (TRUE);
+}
+
+# if (0)
+/**
+ * the full chisq is built of two associated sums over coordinates:
+ * chisq = sum ((X_obs - X_fit(t))^2 + (Y_obs - Y_fit(t))^2)
+ * 
+ * the independent variable is Theta:
+ * X_fit = X0 + RX*cos(theta)*cos(phi) - RY*sin(theta)*sin(phi)
+ * Y_fit = Y0 + RX*cos(theta)*sin(phi) + RY*sin(theta)*cos(phi)
+ *
+ * alternating calls to fellipseOD refer alternatively to X or Y
+ *
+ * parameters: Xo, Yo (center), RX, RY (axes), To (angle), Po (phase)
+ */
+
+opihi_flt fellipseOD (opihi_flt theta, opihi_flt *par, int Npar, opihi_flt *dpar) {
+  
+  static int pass = 0;
+
+  opihi_flt csphi = cos(par[PAR_P0]);
+  opihi_flt snphi = sin(par[PAR_P0]);
+
+  opihi_flt dtheta = theta - par[PAR_T0];
+  opihi_flt cstht = cos(dtheta);
+  opihi_flt sntht = sin(dtheta);
+
+  // value is X
+  if (pass == 0) {
+    pass = 1;
+
+    opihi_flt value = par[PAR_X0] + par[PAR_RX]*cstht*csphi - par[PAR_RY]*sntht*snphi;
+
+    dpar[PAR_X0] = 1.0;
+    dpar[PAR_Y0] = 0.0;
+    dpar[PAR_RX] = +cstht*csphi;
+    dpar[PAR_RY] = -sntht*snphi;
+    dpar[PAR_P0] = -par[PAR_RX]*cstht*snphi - par[PAR_RY]*sntht*csphi;
+    dpar[PAR_T0] = -par[PAR_RX]*sntht*csphi - par[PAR_RY]*cstht*snphi;
+
+    return (value);
+  }  
+
+  // value is Y
+  if (pass == 1) {
+    pass = 0;
+
+    opihi_flt value = par[PAR_Y0] + par[PAR_RX]*cstht*snphi + par[PAR_RY]*sntht*csphi;
+
+    dpar[PAR_X0]  = 0.0;
+    dpar[PAR_Y0]  = 1.0;
+    dpar[PAR_RX]  = +cstht*snphi;
+    dpar[PAR_RY]  = +sntht*csphi;
+    dpar[PAR_P0]  = +par[PAR_RX]*cstht*csphi - par[PAR_RY]*sntht*snphi;
+    dpar[PAR_T0]  = -par[PAR_RX]*sntht*snphi + par[PAR_RY]*cstht*csphi;
+    return (value);
+  }  
+  abort();
+}
+
+# endif
+
+/**
+ * the full chisq is built of two associated sums over coordinates:
+ * chisq = sum ((X_obs - X_fit(t))^2 + (Y_obs - Y_fit(t))^2)
+ * 
+ * the independent variable is theta (angle from 0,0 to point):
+ * X_fit = RMIN*R*cos(theta)
+ * Y_fit = RMIN*R*sin(theta)
+ * R = 1 / sqrt(sin^2(theta-phi) + epsilon^2 * cos^2(theta-phi))
+ *
+ * alternating calls to fellipseOD refer alternatively to X or Y
+ *
+ * RMIN, EPSILON, PHI
+ */
+
+opihi_flt fellipseOD (opihi_flt alpha, opihi_flt *par, int Npar, opihi_flt *dpar) {
+  
+  static int pass = 0;
+
+  opihi_flt cs_alpha = cos(alpha);
+  opihi_flt sn_alpha = sin(alpha);
+
+  opihi_flt cs_phi = cos(alpha - par[PAR_PHI]);
+  opihi_flt sn_phi = sin(alpha - par[PAR_PHI]);
+
+  opihi_flt r     = 1.0 / sqrt(SQ(sn_phi) + SQ(par[PAR_EPSILON]*cs_phi));
+  opihi_flt r3    = pow(r, 3.0);
+  opihi_flt drdE  = -0.5 * r3 * SQ(cs_phi) * 2.0 * par[PAR_EPSILON];
+  opihi_flt drdP  = -0.5 * r3 * (SQ(par[PAR_EPSILON]) - 1) * 2.0 * cs_phi * sn_phi;
+
+  // value is X
+  if (pass == 0) {
+    pass = 1;
+
+    opihi_flt value = par[PAR_RMIN]*cs_alpha*r;
+
+    dpar[PAR_RMIN]    = r*cs_alpha;
+    dpar[PAR_EPSILON] = par[PAR_RMIN]*cs_alpha*drdE;
+    dpar[PAR_PHI]     = 4.0*par[PAR_RMIN]*cs_alpha*drdP;
+
+    return (value);
+  }  
+
+  // value is Y
+  if (pass == 1) {
+    pass = 0;
+
+    opihi_flt value = par[PAR_RMIN]*sn_alpha*r;
+
+    dpar[PAR_RMIN]    = r*sn_alpha;
+    dpar[PAR_EPSILON] = par[PAR_RMIN]*sn_alpha*drdE;
+    dpar[PAR_PHI]     = 4.0*par[PAR_RMIN]*sn_alpha*drdP;
+
+    return (value);
+  }  
+  abort();
+}
+
Index: branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/vgroup.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/vgroup.c	(revision 25766)
+++ branches/eam_branches/20090820/Ohana/src/opihi/cmd.data/vgroup.c	(revision 25766)
@@ -0,0 +1,71 @@
+# include "data.h"
+
+int vgroup (int argc, char **argv) {
+  
+  int i, j, N;
+  Vector *xin, *yin, *xout, *yout;
+  opihi_flt xmin, xmax, sum;
+  double *values;
+
+  // Normalize = FALSE;
+  // if ((N = get_argument (argc, argv, "-norm"))) {
+  //   remove_argument (N, &argc, argv);
+  //   Normalize = TRUE;
+  // }
+  // 
+  // Ignore = FALSE;
+  // IgnoreValue = 0.0;
+  // if ((N = get_argument (argc, argv, "-ignore"))) {
+  //   Ignore = TRUE;
+  //   remove_argument (N, &argc, argv);
+  //   IgnoreValue = atof (argv[N]);
+  //   remove_argument (N, &argc, argv);
+  // }
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: vbin <xin> <yin> <xout> <yout>\n");
+    gprint (GP_ERR, " group x,y values in bins defined by <xout>\n");
+    return (FALSE);
+  }
+
+  if ((xin  = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yin  = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((xout = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);
+  if ((yout = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
+
+  // re-binning creates a float vector
+  ResetVector (yout, OPIHI_FLT, xout[0].Nelements);
+
+  // storage vector
+  ALLOCATE (values, double, xin[0].Nelements);
+
+  for (i = 0; i < xout[0].Nelements - 1; i++) {
+    xmin = xout[0].elements.Flt[i];
+    xmax = xout[0].elements.Flt[i+1];
+
+    N = 0;
+    for (j = 0; j < xin[0].Nelements; j++) {
+      if (xin[0].elements.Flt[j] < xmin) continue;
+      if (xin[0].elements.Flt[j] > xmax) continue;
+      values[N] = yin[0].elements.Flt[j];
+      N++;
+    }
+    
+    dsort (values, N);
+    if (N > 1) {
+      sum = (N % 2) ? values[(int)(0.5*N)] : 0.5*(values[N/2] + values[N/2 + 1]);
+    } else {
+      sum = values[0];
+    }
+
+    // measure the stat for this bin
+    // sum = 0.0;
+    // for (j = 0; j < N; j++) {
+    //   sum += values[j];
+    // }
+    // sum /= N;
+    yout[0].elements.Flt[i] = sum;
+  }
+  free (values);
+  return (TRUE);
+}
Index: branches/eam_branches/20090820/Ohana/src/opihi/dvo/Makefile
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/dvo/Makefile	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/dvo/Makefile	(revision 25766)
@@ -73,5 +73,4 @@
 $(SRC)/imrough.$(ARCH).o	  	\
 $(SRC)/imsearch.$(ARCH).o	  	\
-$(SRC)/imstats.$(ARCH).o	  	\
 $(SRC)/lcat.$(ARCH).o		  	\
 $(SRC)/lcurve.$(ARCH).o	  	\
Index: branches/eam_branches/20090820/Ohana/src/opihi/dvo/gimages.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/dvo/gimages.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/dvo/gimages.c	(revision 25766)
@@ -124,5 +124,7 @@
       }
 
+      // find coordinates of image center
       XY_to_RD (&Ro, &Do, Xo, Yo, &image[i].coords);
+      if (fabs(Ro - Ra) > 120.0) continue;
 
       local.crval1 = Ro;
@@ -138,35 +140,22 @@
 	Xs = -0.5*image[i].NX;
 	Ys = -0.5*image[i].NY;
-	Xe = +0.5*image[i].NX;
-	Ye = +0.5*image[i].NY;
       } else {
 	Xs = 0.0;
 	Ys = 0.0;
-	Xe = image[i].NX;
-	Ye = image[i].NY;
       }
       
+      // find coordinates of an image corner
       XY_to_RD (&Ro, &Do, Xs, Ys, &image[i].coords);
-      RD_to_XY (&Xo, &Xo, Ro, Do, &local);
+
+      // find radius of image in arcsec
+      RD_to_XY (&Xo, &Yo, Ro, Do, &local);
       Radius = hypot (Xo, Yo);
       // fprintf (stderr, "%s: %f %f    %f ", image[i].name, local.crval1, local.crval2, Radius);
 
-      XY_to_RD (&Ro, &Do, Xs, Ye, &image[i].coords);
-      RD_to_XY (&Xo, &Xo, Ro, Do, &local);
-      Radius = MAX (Radius, hypot (Xo, Yo));
-      // fprintf (stderr, "%f ", Radius);
-
-      XY_to_RD (&Ro, &Do, Xe, Ys, &image[i].coords);
-      RD_to_XY (&Xo, &Xo, Ro, Do, &local);
-      Radius = MAX (Radius, hypot (Xo, Yo));
-      // fprintf (stderr, "%f ", Radius);
-
-      XY_to_RD (&Ro, &Do, Xe, Ye, &image[i].coords);
-      RD_to_XY (&Xo, &Xo, Ro, Do, &local);
-      Radius = MAX (Radius, hypot (Xo, Yo));
-      // fprintf (stderr, "%f ", Radius);
-
+      // check for distances to coordinates in arcsec
       RD_to_XY (&Xo, &Yo, Ra, Dec, &local);
       // fprintf (stderr, " : %f\n", hypot(Xo,Yo));
+
+      // skip images with center too far from coordinaes
       if (hypot(Xo,Yo) > 1.5*Radius) continue;
       // fprintf (stderr, " ** try me **\n");
Index: branches/eam_branches/20090820/Ohana/src/opihi/dvo/imbox.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/dvo/imbox.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/dvo/imbox.c	(revision 25766)
@@ -3,5 +3,5 @@
 int imbox (int argc, char **argv) {
   
-  int j, kapa, Nskip, status, InPic, flipped, N, haveNx, haveNy, Nx, Ny, SOLO_PHU;
+  int j, kapa, Nskip, status, InPic, flipped, N, haveNx, haveNy, Nx, Ny, SOLO_PHU, Npts, NPTS;
   Vector Xvec, Yvec;
   double r, d, x[4], y[4], Rmin, Rmax, Rmid;
@@ -36,6 +36,8 @@
   
   /* project this image to screen display coords */
-  SetVector (&Xvec, OPIHI_FLT, 8);
-  SetVector (&Yvec, OPIHI_FLT, 8);
+  Npts = 0;
+  NPTS = 200; 
+  SetVector (&Xvec, OPIHI_FLT, NPTS);
+  SetVector (&Yvec, OPIHI_FLT, NPTS);
 
   while (gfits_fread_header (f, &header)) {
@@ -82,28 +84,30 @@
 	while (r > Rmid) r-= 360.0;
       }
-      status |= RD_to_XY (&Xvec.elements.Flt[2*j], &Yvec.elements.Flt[2*j], r, d, &graphmode.coords);
+      status |= RD_to_XY (&Xvec.elements.Flt[Npts + 2*j], &Yvec.elements.Flt[Npts + 2*j], r, d, &graphmode.coords);
       if (j > 0) {
-	Xvec.elements.Flt[2*j - 1] = Xvec.elements.Flt[2*j];
-	Yvec.elements.Flt[2*j - 1] = Yvec.elements.Flt[2*j];
+	Xvec.elements.Flt[Npts + 2*j - 1] = Xvec.elements.Flt[Npts + 2*j];
+	Yvec.elements.Flt[Npts + 2*j - 1] = Yvec.elements.Flt[Npts + 2*j];
       }
     }
-    Xvec.elements.Flt[7] = Xvec.elements.Flt[0];
-    Yvec.elements.Flt[7] = Yvec.elements.Flt[0];
+    Xvec.elements.Flt[Npts + 7] = Xvec.elements.Flt[Npts + 0];
+    Yvec.elements.Flt[Npts + 7] = Yvec.elements.Flt[Npts + 0];
+
     InPic = FALSE;
     for (j = 0; j < 8; j+=2) {
-      if ((Xvec.elements.Flt[j] >= graphmode.xmin) && 
-	  (Xvec.elements.Flt[j] <= graphmode.xmax) && 
-	  (Yvec.elements.Flt[j] >= graphmode.ymin) && 
-	  (Yvec.elements.Flt[j] <= graphmode.ymax))
-	InPic = TRUE;
+      if ((Xvec.elements.Flt[Npts + j] >= graphmode.xmin) && 
+    	  (Xvec.elements.Flt[Npts + j] <= graphmode.xmax) && 
+    	  (Yvec.elements.Flt[Npts + j] >= graphmode.ymin) && 
+    	  (Yvec.elements.Flt[Npts + j] <= graphmode.ymax))
+    	InPic = TRUE;
+    }
+    if (!InPic) continue;
+
+    Npts += 8;
+    if (Npts + 8 >= NPTS) {  /* need to leave room for 4 point image */
+      NPTS += 200;
+      REALLOCATE (Xvec.elements.Flt, opihi_flt, NPTS);
+      REALLOCATE (Yvec.elements.Flt, opihi_flt, NPTS);
     }
 
-    Xvec.Nelements = Yvec.Nelements = 8;
-    if (InPic) {
-      graphmode.style = 2; /* points */
-      graphmode.ptype = 100; /* connect pairs of points */
-      graphmode.etype = 0;
-      PlotVectorPair (kapa, &Xvec, &Yvec, &graphmode);
-    }
   skip:
     Nskip = gfits_data_size (&header);
@@ -111,4 +115,13 @@
     gfits_free_header (&header);
   }
+
+  Xvec.Nelements = Yvec.Nelements = Npts;
+  if (Npts > 0) {
+    graphmode.style = 2; /* points */
+    graphmode.ptype = 100; /* connect pairs of points */
+    graphmode.etype = 0;
+    PlotVectorPair (kapa, &Xvec, &Yvec, &graphmode);
+  }
+
   fclose (f);
   free (Xvec.elements.Flt);
Index: branches/eam_branches/20090820/Ohana/src/opihi/dvo/init.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/dvo/init.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/dvo/init.c	(revision 25766)
@@ -102,5 +102,4 @@
   {1, "subpix",      subpix,       "get subpixel positions"},
   {1, "version",     version,      "show version information"},
-//{1, "imstats",     imstats,      "plot image statistics"},
 //{1, "addxtra",     addxtra,      "add extra data to object"},
 //{1, "getxtra",     getxtra,      "get extra data from object"},
Index: branches/eam_branches/20090820/Ohana/src/opihi/dvo/photometry.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/dvo/photometry.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/dvo/photometry.c	(revision 25766)
@@ -325,5 +325,7 @@
     return (FALSE);
   }
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+
+  // XXX now that DVO does not allow write access, we can drop the MasterPhotcodeFile
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, FALSE)) {
     gprint (GP_ERR, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     return (FALSE);
Index: branches/eam_branches/20090820/Ohana/src/opihi/dvo/region_list.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/dvo/region_list.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/dvo/region_list.c	(revision 25766)
@@ -42,5 +42,5 @@
 
   if (sky != NULL) SkyTableFree (sky);
-  sky = SkyTableLoadOptimal (CATDIR, skyfile, gscfile, skydepth, verbose);
+  sky = SkyTableLoadOptimal (CATDIR, skyfile, gscfile, FALSE, skydepth, verbose);
   if (sky == NULL) return FALSE;
 
Index: branches/eam_branches/20090820/Ohana/src/opihi/dvo/skycoverage.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/dvo/skycoverage.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/dvo/skycoverage.c	(revision 25766)
@@ -16,4 +16,6 @@
   Coords coords;
   int typehash;
+  int PhotcodeSelect;
+  PhotCode *PhotcodeValue;
 
   WITH_MOSAIC = FALSE;
@@ -43,4 +45,18 @@
     remove_argument (N, &argc, argv);
     ByName = TRUE;
+  }
+
+  PhotcodeValue = NULL;
+  PhotcodeSelect = FALSE;
+  if ((N = get_argument (argc, argv, "-photcode"))) {
+    if (!InitPhotcodes ()) return (FALSE);
+    PhotcodeSelect = TRUE;
+    remove_argument (N, &argc, argv);
+    PhotcodeValue = GetPhotcodebyName (argv[N]);
+    if (PhotcodeValue == NULL) {
+      gprint (GP_ERR, "photcode not found in photcode table\n");
+      return (FALSE);
+    }
+    remove_argument (N, &argc, argv);
   }
 
@@ -85,5 +101,6 @@
  
   if (argc != 4) {
-    gprint (GP_ERR, "USAGE: skycoverage (buffer) (pixscale) (Npts) [-time start range] [-name name]\n");
+    gprint (GP_ERR, "USAGE: skycoverage (buffer) (pixscale) (Npts)\n");
+    gprint (GP_ERR, "  options: [-time start range] [-trange start stop] [-name name] [-photcode name] [+mosaic] [-mosaic] [-ra-center RA]\n");
     gprint (GP_ERR, "       (buffer) saves bitmapped AIT plot\n");
     gprint (GP_ERR, "       (pixscale) specifies the pixel size in degrees\n");
@@ -128,6 +145,6 @@
     for (xs = 0; xs < Nx; xs++) {
       status = XY_to_RD (&r, &d, (double)(xs), (double)(ys), &coords);
-      status &= (r > 0);
-      status &= (r < 360);
+      status &= (r >= 0);
+      status &= (r <= 360);
       if (status) {
 	V[ys*Nx + xs] = 2;
@@ -141,4 +158,13 @@
     if (ByName && strcmp (name, image[i].name)) continue;
     if (TimeSelect && ((image[i].tzero < tzero) || (image[i].tzero+image[i].trate*image[i].NY > tzero + trange))) continue;
+
+    if (PhotcodeSelect) {
+      if (PhotcodeValue[0].type == PHOT_DEP) {
+	if (PhotcodeValue[0].code != image[i].photcode) continue;
+      } else {
+	if (PhotcodeValue[0].code != GetPhotcodeEquivCodebyCode (image[i].photcode)) continue;
+      }
+    }
+
     if (!FindMosaicForImage (image, Nimage, i)) continue;
 
@@ -167,4 +193,6 @@
 	XY_to_RD (&r, &d, Xi, Yi, &image[i].coords);
 	r = ohana_normalize_angle (r);
+	if (r - RaCenter > +180.0) r -= 360.0;
+	if (r - RaCenter < -180.0) r += 360.0;
 	status = RD_to_XY (&Xs, &Ys, r, d, &coords);
 	if (Xs < 0) continue;
Index: branches/eam_branches/20090820/Ohana/src/opihi/lib.data/mrqmin.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/lib.data/mrqmin.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/lib.data/mrqmin.c	(revision 25766)
@@ -17,5 +17,5 @@
 
   int k, j, i;
-  opihi_flt ydiff, wt, chisq;
+  opihi_flt ymodel, ydiff, wt, chisq;
 
   for (j = 0; j < Npar; j++) {
@@ -27,6 +27,9 @@
   for (i = 0; i < Npts; i++) {
 
-    ydiff = funcs (x[i], par, Npar, dyda) - y[i];
+    ymodel = funcs (x[i], par, Npar, dyda);
+    ydiff = ymodel - y[i];
     chisq += SQ(ydiff) * dy[i];
+
+    // fprintf (stderr, "%f %f - %f : %f -> %f\n", x[i], y[i], ymodel, dy[i], chisq);
 
     for (j = 0; j < Npar; j++) {
@@ -85,5 +88,5 @@
 
   /* if good, save temp values */
-  if (rho > 0) {
+  if ((chisq > 1e-3) && (rho > -1e-6)) {
     lambda *= 0.1;
     ochisq = chisq;
Index: branches/eam_branches/20090820/Ohana/src/opihi/lib.shell/command.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/opihi/lib.shell/command.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/opihi/lib.shell/command.c	(revision 25766)
@@ -5,6 +5,9 @@
 
   int i, status, argc;
-  char **argv, **targv;
+  char **argv, **targv, *rawline;
   Command *cmd;
+
+  rawline = NULL;
+  // rawline = strcreate (line);
 
   /* force a space between ! and first word: !ls becomes ! ls */
@@ -31,5 +34,8 @@
 
   argv = parse_commands (line, &argc);
-  if (argc == 0) return (TRUE);  /* empty command or assignment */
+  if (argc == 0) {
+      FREE (rawline);
+      return (TRUE);  /* empty command or assignment */
+  }
 
   /* save the original values of argv since command may modify the array */
@@ -54,4 +60,5 @@
     msg = get_variable_ptr ("ERRORMSG");
     if (msg != (char *) NULL) gprint (GP_ERR, "%s\n", msg);
+    // gprint (GP_ERR, "error on line: %s\n", rawline);
   }
 
@@ -62,4 +69,5 @@
   # endif
 
+  FREE (rawline);
   return (status);
 }
Index: branches/eam_branches/20090820/Ohana/src/photdbc/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/photdbc/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/photdbc/src/ConfigInit.c	(revision 25766)
@@ -64,5 +64,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/photdbc/src/photdbc.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/photdbc/src/photdbc.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/photdbc/src/photdbc.c	(revision 25766)
@@ -17,5 +17,5 @@
 
   // the output catalog needs to inherit the SKY_DEPTH of the input catalog
-  sky = SkyTableLoadOptimal (CATDIR, NULL, GSCFILE, SKY_DEPTH_HST, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, NULL, GSCFILE, TRUE, SKY_DEPTH_HST, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   skylist = SkyListByPatch (sky, -1, &REGION);
Index: branches/eam_branches/20090820/Ohana/src/relastro/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/relastro/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/relastro/src/ConfigInit.c	(revision 25766)
@@ -60,5 +60,5 @@
   /* update master photcode table if not defined */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/relastro/src/load_images.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/relastro/src/load_images.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/relastro/src/load_images.c	(revision 25766)
@@ -11,5 +11,5 @@
 
   // load the current sky table (layout of all SkyRegions) 
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   
Index: branches/eam_branches/20090820/Ohana/src/relastro/src/relastro_objects.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/relastro/src/relastro_objects.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/relastro/src/relastro_objects.c	(revision 25766)
@@ -11,5 +11,5 @@
 
   // load the current sky table (layout of all SkyRegions) 
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   
Index: branches/eam_branches/20090820/Ohana/src/relphot/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/relphot/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/relphot/src/ConfigInit.c	(revision 25766)
@@ -58,5 +58,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/Ohana/src/relphot/src/StarOps.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/relphot/src/StarOps.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/relphot/src/StarOps.c	(revision 25766)
@@ -193,4 +193,6 @@
   for (i = 0; i < Ncatalog; i++) {
     for (j = 0; j < catalog[i].Naverage; j++) {
+
+      // update average photometry for each of the average filters
       for (Ns = 0; Ns < Nsecfilt; Ns++) {
 
@@ -207,6 +209,8 @@
 	  if (isnan(Msys)) continue;
 
-	  // XXX this is a hack for the 2MASS search; better to save an average value?
-	  if (catalog[i].measure[m].psfQual < 0.85) continue;
+	  // XXX only apply this filter for psphot data from GPC1 for now...
+	  if (0 && (catalog[i].measure[m].photcode > 10000) && (catalog[i].measure[m].photcode < 10500)) {
+	      if (catalog[i].measure[m].psfQual < 0.85) continue;
+	  }
 
 	  list[N] = Msys - catalog[i].measure[m].Mcal;
@@ -224,4 +228,57 @@
 	catalog[i].secfilt[Nsecfilt*j+Ns].Ncode = N;
 	catalog[i].secfilt[Nsecfilt*j+Ns].Nused = stats.Nmeas;
+      }
+
+      // update average flags based on the detection stats.  
+      // XXX we need to clean this up -- this is a serious set of hacks...
+      if (0) { 
+	int Galaxy2MASS, GalaxySDSS, goodPS1, nEXT, nPSF, good2MASS;
+
+	Galaxy2MASS = FALSE; // best guess for galaxy based on 2MASS J measurements (gal_contam == measure.flags[0x00400000 | 0x00800000])
+	GalaxySDSS = FALSE;  // best guess for galaxy based on SDSS measurements (XXX need to fix SDSS flags)
+	goodPS1 = FALSE;     // true if any PS1 measurements have psfQual > 0.85
+	good2MASS = FALSE;   // true if 2MASS J measurements have significant detections
+	nEXT = nPSF = 0;     // number of PS1 PSF vs EXT measurements
+
+	m = catalog[i].average[j].measureOffset;
+	for (k = 0; k < catalog[i].average[j].Nmeasure; k++, m++) {
+
+	  // PS1 data :
+	  if ((catalog[i].measure[m].photcode >= 10000) && (catalog[i].measure[m].photcode <= 10500)) {
+	    if (catalog[i].measure[m].psfQual > 0.85) {
+	      goodPS1 = TRUE;
+	      if (!isnan(catalog[i].measure[m].Map)) {
+		if (catalog[i].measure[m].M - catalog[i].measure[m].Map > 0.5) {
+		  nEXT ++;
+		} else {
+		  nPSF ++;
+		}
+	      }
+	    }
+	  }
+	  
+	  // 2MASS data:
+	  if (catalog[i].measure[m].photcode == 2011) {
+	    if (catalog[i].measure[m].photFlags & 0x00c00000) {
+	      Galaxy2MASS = TRUE;
+	    }
+	    if (catalog[i].measure[m].photFlags & 0x00000007) {
+	      good2MASS = TRUE; 
+	    }
+	  }  
+	}
+
+	if (nEXT && (nEXT > nPSF)) {
+	  catalog[i].average[j].flags |= 0x00010000;
+	}
+	if (goodPS1) {
+	  catalog[i].average[j].flags |= 0x00020000;
+	}
+	if (Galaxy2MASS) {
+	  catalog[i].average[j].flags |= 0x00040000;
+	}
+	if (good2MASS) {
+	  catalog[i].average[j].flags |= 0x00080000;
+	}
       }
     }
Index: branches/eam_branches/20090820/Ohana/src/relphot/src/load_images.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/relphot/src/load_images.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/relphot/src/load_images.c	(revision 25766)
@@ -11,5 +11,5 @@
 
   // load the current sky table (layout of all SkyRegions) 
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   
Index: branches/eam_branches/20090820/Ohana/src/relphot/src/relphot_objects.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/relphot/src/relphot_objects.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/relphot/src/relphot_objects.c	(revision 25766)
@@ -11,5 +11,5 @@
 
   // load the current sky table (layout of all SkyRegions) 
-  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, SKY_DEPTH, VERBOSE);
+  sky = SkyTableLoadOptimal (CATDIR, SKY_TABLE, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
   SkyTableSetFilenames (sky, CATDIR, "cpt");
   
@@ -68,4 +68,8 @@
     
     if (VERBOSE) fprintf (stderr, "saving catalog %s\n", catalog.filename);
+    
+    // we can optionally convert output format here
+    // but it would be better to define a dvo crawler program to do this
+    // catalog.catformat = DVO_FORMAT_PS1_V1;  
     dvo_catalog_save (&catalog, VERBOSE); 
     dvo_catalog_unlock (&catalog);
Index: branches/eam_branches/20090820/Ohana/src/tools/src/mktemp.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/tools/src/mktemp.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/tools/src/mktemp.c	(revision 25766)
@@ -1,17 +1,116 @@
 # include <stdio.h>
 # include <stdlib.h>
+# include <string.h>
+
+# define FALSE 0
+# define TRUE 1
 
 int main (int argc, char **argv) {
 
-  if (argc != 2) {
-    fprintf (stderr, "USAGE: %s (template)\n", argv[0]);
-    exit (1);
+  int i, j, Ntotal;
+  char *tmpdir, *template, deftemplate[32], *prefix, defprefix[32], *filename;
+  int make_directory, fail_silently, unsafe_mode, full_path;
+
+  tmpdir = NULL;
+  prefix = NULL;
+  template = NULL;
+  filename = NULL;
+
+  make_directory = FALSE;
+  fail_silently = FALSE;
+  unsafe_mode = FALSE;
+  full_path = TRUE;
+
+  for (i = 1; i < argc; i++) {
+    // -options must be first
+    if (argv[i][0] == '-') {
+      if (!strcmp(argv[i], "-V")) {
+	fprintf (stdout, "mktemp version Ohana $Revision: $\n");
+	exit (0);
+      }
+      if (!strcmp(argv[i], "-p")) {
+	if (argc <= i + 1) usage();
+	i++;
+	prefix = argv[i];
+	full_path = FALSE;
+	continue;
+      }
+      for (j = 1; j < strlen(argv[i]); j++) {
+	if (argv[i][j] == 'q') {
+	  fail_silently = TRUE;
+	  continue;
+	}
+	if (argv[i][j] == 't') {
+	  full_path = FALSE;
+	  continue;
+	}
+	if (argv[i][j] == 'd') {
+	  // make directory
+	  make_directory = TRUE;
+	  continue;
+	}
+	if (argv[i][j] == 'u') {
+	  unsafe_mode = TRUE;
+	  continue;
+	}
+	// unknown option
+	usage();
+      }
+      continue;
+    }
+    // report an error if too many arguments are given
+    if (template) usage();
+    template = argv[i];
   }
 
-  if (mkstemp (argv[1]) == -1) exit (1);
+  if (!full_path) {
+    // prefix = TMPDIR ? TMPDIR : (prefix ? prefix : /tmp)
+    tmpdir = getenv("TMPDIR");
+    if (tmpdir) {
+      prefix = tmpdir;
+    }
+    if (!prefix) {
+      strcpy (defprefix, "/tmp");
+      prefix = defprefix;
+    }
+    if (template && strchr(template, '/')) usage();
+  }
 
-  fprintf (stdout, "%s\n", argv[1]);
+  if (!template) {
+    if (full_path) {
+      strcpy (deftemplate, "/tmp/tmp.XXXXXXXXXX");
+    } else {
+      strcpy (deftemplate, "tmp.XXXXXXXXXX");
+    }
+    template = deftemplate;
+  }
+
+  // filename = full_path ? prefix/template : template;
+  if (!full_path) {
+    Ntotal = strlen(prefix) + strlen(template) + 2;
+    filename = (char *) malloc (Ntotal);
+    snprintf (filename, Ntotal, "%s/%s", prefix, template);
+    template = filename;
+  }
+
+  if (make_directory) {
+    if (mkdtemp (template) == -1) {
+      if (!fail_silently) fprintf (stderr, "failed to make temp file from %s\n", template);
+      exit (1);
+    }
+  } else {
+    if (mkstemp (template) == -1) {
+      if (!fail_silently) fprintf (stderr, "failed to make temp file from %s\n", template);
+      exit (1);
+    }
+  }
+
+  fprintf (stdout, "%s\n", template);
 
   exit (0);
 }
  
+usage() {
+  fprintf (stderr, "Usage: mktemp [-V] | [-dqtu] [-p prefix] [template]\n");
+  exit (1);
+}
Index: branches/eam_branches/20090820/Ohana/src/uniphot/src/ConfigInit.c
===================================================================
--- branches/eam_branches/20090820/Ohana/src/uniphot/src/ConfigInit.c	(revision 25206)
+++ branches/eam_branches/20090820/Ohana/src/uniphot/src/ConfigInit.c	(revision 25766)
@@ -36,5 +36,5 @@
   /* XXX this does not yet write out the master photcode table */
   sprintf (CatdirPhotcodeFile, "%s/Photcodes.dat", CATDIR);
-  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile)) {
+  if (!LoadPhotcodes (CatdirPhotcodeFile, MasterPhotcodeFile, TRUE)) {
     fprintf (stderr, "error loading photcode table %s or master file %s\n", CatdirPhotcodeFile, MasterPhotcodeFile);
     exit (1);
Index: branches/eam_branches/20090820/PS-IPP-PStamp/lib/PS/IPP/PStamp/Job.pm
===================================================================
--- branches/eam_branches/20090820/PS-IPP-PStamp/lib/PS/IPP/PStamp/Job.pm	(revision 25206)
+++ branches/eam_branches/20090820/PS-IPP-PStamp/lib/PS/IPP/PStamp/Job.pm	(revision 25766)
@@ -21,5 +21,4 @@
 
 use IPC::Cmd 0.36 qw( can_run run );
-
 use PS::IPP::Metadata::List qw( parse_md_list );
 use PS::IPP::Config qw( :standard );
@@ -35,6 +34,8 @@
     my $img_type = shift;   # required
     my $id       = shift;   # required unless req_type eq bycoord or byskycell
+    my $tess_id  = shift;
     my $component= shift;   # class_id or skycell_id
     my $inverse  = shift;
+    my $need_magic = shift;
     my $x        = shift;
     my $y        = shift;
@@ -42,10 +43,24 @@
     my $mjd_max  = shift;
     my $filter   = shift;
+    my $label    = shift;
     my $verbose  = shift;
 
 
     # we die in response to bad data in request files
-    die "Unknown req_type: $req_type" if ($req_type ne "byid") and ($req_type ne "byexp")
-                                        and ($req_type ne "bycoord") and ($req_type ne "bydiff");
+    die "Unknown req_type: $req_type" 
+        if ($req_type ne "byid") and
+           ($req_type ne "byexp") and 
+           ($req_type ne "bycoord") and 
+           ($req_type ne "bydiff") and 
+           ($req_type ne "byskycell");
+
+    my $dateobs_begin;
+    my $dateobs_end;
+    if (!iszero($mjd_min)) {
+        $dateobs_begin = mjd_to_dateobs($mjd_min);
+    }
+    if (!iszero($mjd_max)) {
+        $dateobs_end = mjd_to_dateobs($mjd_max);
+    }
 
     if (($req_type eq "byid") and ($img_type eq "diff")) {
@@ -77,4 +92,5 @@
             $req_type = "byid";
             $id = $image->{warp_id};
+            $component = $image->{skycell_id};
             return undef if !$id;
             # fall through and lookup by warp_id
@@ -95,5 +111,5 @@
         # regtool -dbname $image_db -processedimfile -time_begin $mjd_min -time_end = $mjd_max -filter $filter
         #
-        my $results = lookup_bycoord($ipprc, $image_db, $x, $y, $mjd_min, $mjd_max, $filter, $verbose);
+        my $results = lookup_bycoord($ipprc, $image_db, $x, $y, $dateobs_begin, $dateobs_end, $filter, $verbose);
 
         # now take the results and lookup byexp
@@ -102,7 +118,16 @@
         $req_type = "byexp";
         $id = $results->{exp_name};
-    }
-
-    my $results = lookup($ipprc, $image_db, $req_type, $img_type, $id, $component, $verbose);
+    } elsif ($req_type eq "byskycell") {
+        if (($img_type eq "raw") or ($img_type eq "chip")) {
+            print STDERR "REQ_TYPE byskycell not supported for IMG_TYPE raw or chip\n";
+            return undef;
+        }
+        if (!$tess_id or !$component) {
+            print STDERR "component and tess_id are required for REQ_TYPE byskycell\n";
+            return undef;
+        }
+    }
+
+    my $results = lookup($ipprc, $image_db, $req_type, $img_type, $id, $tess_id, $component, $need_magic, $dateobs_begin, $dateobs_end, $filter, $label, $verbose);
 
     return $results;
@@ -115,5 +140,11 @@
     my $img_type = shift;
     my $id       = shift;
+    my $tess_id  = shift;
     my $component= shift;
+    my $need_magic = shift;
+    my $dateobs_begin = shift;
+    my $dateobs_end   = shift;
+    my $filter = shift;
+    my $label = shift;
     my $verbose  = shift;
 
@@ -139,9 +170,9 @@
     my $skycell_id;
 
-    # special class_id value "null" means ignore
-    if ($component and ($component eq "null")) {
+    if (isnull($component)) {
         $component = undef;
     }
 
+    my $magic_arg = $need_magic ? " -destreaked" : "";
     if ($img_type eq "raw") {
         $class_id = $component;
@@ -196,7 +227,18 @@
     } elsif ($req_type eq "byexp") {
         $command .= " -exp_name $id";
+    } elsif ($req_type eq "byskycell") {
+        $command .= " -tess_id $tess_id -skycell_id $skycell_id";
     } else {
         die "Unknown req_type supplied: $req_type";
     }
+
+    if ($img_type ne "stack") {
+        $command .= $magic_arg;
+        $command .= " -dateobs_begin $dateobs_begin" if $dateobs_begin;
+        $command .= " -dateobs_end $dateobs_end" if $dateobs_end;
+    }
+
+    $command .= " -filter $filter" if !isnull($filter);
+    $command .= " -label $label" if !isnull($label);
 
     # run the tool and parse the output
@@ -233,4 +275,9 @@
             # just above probably solved the problem I was trying to solve with this test)
             next if !$base;
+        } else {
+            # raw images don't have path_base yet. Manufacture one
+            my $uri = $image->{uri};
+            my $path_base = $uri =~ s/\.fits//g;
+            $image->{$path_base} = $path_base;
         }
         if (!$camera) {
@@ -381,6 +428,6 @@
     my $x        = shift;
     my $y        = shift;
-    my $mjd_min  = shift;
-    my $mjd_max  = shift;
+    my $dateobs_begin  = shift;
+    my $dateobs_end  = shift;
     my $filter   = shift;
     my $verbose  = shift;
@@ -398,13 +445,11 @@
 
     my $args;
-    if ($mjd_min) {
-        my $dateobs_min = mjd_to_dateobs($mjd_min);
-        $args .= " -dateobs_begin $dateobs_min";
-    }
-    if ($mjd_max) {
-        my $dateobs_max = mjd_to_dateobs($mjd_max);
-        $args .= " -dateobs_end $dateobs_max";
-    }
-    if ($filter) {
+    if (!isnull($dateobs_begin)) {
+        $args .= " -dateobs_begin $dateobs_begin";
+    }
+    if (!isnull($dateobs_end)) {
+        $args .= " -dateobs_end $dateobs_end";
+    }
+    if (!isnull($filter)) {
         $args .= " -filter $filter";
     }
@@ -562,5 +607,16 @@
     my ($sec, $min, $hr, $day, $mon, $year) = gmtime($ticks);
 
-    return sprintf "'%4d-%02d-%02d %02d:%02d:%02d'", $year+1900, $mon+1, $day, $hr, $min, $sec;
+    return sprintf "'%4d-%02d-%02dT%02d:%02d:%02dZ'", $year+1900, $mon+1, $day, $hr, $min, $sec;
+}
+
+sub isnull {
+    my $val = shift;
+
+    return (!defined($val) or (lc($val) eq "null"));
+}
+
+sub iszero {
+    my $val = shift;
+    return (!defined($val) or ($val == 0));
 }
 
Index: branches/eam_branches/20090820/dbconfig/add.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/add.md	(revision 25766)
+++ branches/eam_branches/20090820/dbconfig/add.md	(revision 25766)
@@ -0,0 +1,25 @@
+addRun METADATA
+    add_id          S64     0       # Primary Key AUTO_INCREMENT
+    cam_id          S64     0       # Key INDEX(add_id,cam_id) fkey(cam_id) ref camRun(cam_id)
+    state           STR     64      # key
+    workdir         STR     255
+    workdir_state   STR     64
+    label           STR	    64
+    dvodb	    STR	    255
+    magicked        S64     0
+END
+
+addProcessedExp METADATA
+    add_id          S64     0       # Primary Key AUTO_INCREMENT
+    dtime_addstar   F32     0.0
+
+    n_stars         S32     0
+    
+    path_base	    STR	    255
+    fault           S16     0       # Key NOT NULL
+END
+
+addMask METADATA
+    label           STR    64       # Primary Key
+END
+    
Index: branches/eam_branches/20090820/dbconfig/changes.txt
===================================================================
--- branches/eam_branches/20090820/dbconfig/changes.txt	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/changes.txt	(revision 25766)
@@ -1082,5 +1082,5 @@
 
 ALTER TABLE rcRun ADD COLUMN fault SMALLINT DEFAULT 0;
-ALTER TABLE rcRun ADD COLUMN status_fs VARCHAR(64) AFTER state;
+ALTER TABLE rcRun ADD COLUMN status_fs_name VARCHAR(64) AFTER state;
 
 ALTER TABLE diffSkyfile ADD COLUMN deconv_max FLOAT AFTER kernel_yy;
@@ -1206,2 +1206,96 @@
 ALTER TABLE magicDSRun ADD COLUMN inv_magic_id BIGINT AFTER magic_id;
 ALTER TABLE magicDSRun ADD FOREIGN KEY (inv_magic_id) REFERENCES magicRun(magic_id);
+
+-- Adding columns for debugging publishing problems
+
+ALTER TABLE publishDone ADD COLUMN hostname VARCHAR(64) AFTER path_base;
+ALTER TABLE publishDone ADD COLUMN dtime_script FLOAT AFTER hostname;
+
+-- Version 1.1.55
+-- addstar stage tables:
+
+CREATE TABLE addRun (
+    add_id BIGINT AUTO_INCREMENT,
+    cam_id BIGINT,
+    state VARCHAR(64),
+    workdir VARCHAR(255),
+    workdir_state VARCHAR(64),
+    label VARCHAR(64),
+    dvodb VARCHAR(255),
+    magicked BIGINT,
+    PRIMARY KEY(add_id),
+    KEY(add_id),
+    KEY(cam_id),
+    KEY(state),
+    KEY(workdir_state),
+    KEY(label),
+    INDEX(add_id, cam_id),
+    FOREIGN KEY(cam_id) REFERENCES camRun(cam_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE addProcessedExp (
+    add_id BIGINT AUTO_INCREMENT,
+    dtime_addstar FLOAT,
+    n_stars INT,
+    path_base VARCHAR(255),
+    fault SMALLINT NOT NULL,
+    PRIMARY KEY(add_id),
+    FOREIGN KEY(add_id) REFERENCES addRun(add_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE addMask (
+    label VARCHAR(64),
+    PRIMARY KEY(label)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+
+ALTER TABLE pzDownloadImfile ADD COLUMN bytes INT;
+ALTER TABLE pzDownloadImfile ADD COLUMN md5sum VARCHAR(32);
+ALTER TABLE newImfile ADD COLUMN bytes INT;
+ALTER TABLE newImfile ADD COLUMN md5sum VARCHAR(32);
+ALTER TABLE rawImfile ADD COLUMN bytes INT;
+ALTER TABLE rawImfile ADD COLUMN md5sum VARCHAR(32);
+ALTER TABLE rawImfile ADD COLUMN burntool_state SMALLINT;
+
+-- Vesion 1.1.56
+
+-- Merge the rcDSProduct and rcDestination tables
+
+ALTER TABLE rcDestination ADD COLUMN dbname varchar(64) AFTER last_fileset;
+ALTER TABLE rcDestination ADD COLUMN dbhost varchar(64) AFTER dbname;
+
+UPDATE rcDestination JOIN rcDSProduct USING(prod_id)
+    SET rcDestination.name = rcDSProduct.name, 
+        rcDestination.dbname = rcDSProduct.dbname, 
+        rcDestination.dbhost = rcDSProduct.dbhost;
+
+ALTER TABLE rcDestination DROP foreign key rcDestination_ibfk_1 ;
+ALTER TABLE rcDestination DROP key prod_id;
+ALTER TABLE rcDestination DROP COLUMN prod_id;
+
+-- change references to rcDSProduct in rcDSFileset to reference rcDestination
+
+ALTER TABLE rcDSFileset DROP foreign key rcDSFileset_ibfk_2;
+ALTER TABLE rcDSFileset DROP key prod_id;
+ALTER TABLE rcDSFileset CHANGE COLUMN prod_id dest_id BIGINT NOT NULL DEFAULT '0';
+ALTER TABLE rcDSFileset ADD KEY (dest_id);
+ALTER TABLE rcDSFileset ADD FOREIGN KEY (dest_id) REFERENCES rcDestination(dest_id);
+
+-- finally drop the obsolete table
+DROP TABLE rcDSProduct;
+
+-- The following changes should have been made to the gpc1 database ages ago
+-- do not apply if these columns exist
+ALTER TABLE pstampRequest DROP COLUMN outFileset;
+ALTER TABLE pstampRequest ADD COLUMN name VARCHAR(64) UNIQUE AFTER state;
+ALTER TABLE pstampRequest ADD COLUMN reqType VARCHAR(16) AFTER name;
+ALTER TABLE pstampRequest ADD COLUMN outProduct VARCHAR(64) after reqType;
+ALTER TABLE pstampRequest ADD COLUMN fault SMALLINT AFTER uri;
+-- end of old changes
+
+-- This change is new
+ALTER TABLE pstampRequest ADD COLUMN label VARCHAR(64) AFTER reqType;
+
+ALTER TABLE distRun ADD COLUMN magic_ds_id BIGINT AFTER stage_id;
+
+ALTER TABLE pstampJob ADD COLUMN options BIGINT;
Index: branches/eam_branches/20090820/dbconfig/config.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/config.md	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/config.md	(revision 25766)
@@ -2,4 +2,4 @@
     pkg_name        STR     ippdb
     pkg_namespace   STR     ippdb
-    pkg_version     STR     1.1.54
+    pkg_version     STR     1.1.55
 END
Index: branches/eam_branches/20090820/dbconfig/dist.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/dist.md	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/dist.md	(revision 25766)
@@ -14,4 +14,5 @@
     stage       STR         64
     stage_id    S64         0
+    magic_ds_id S64         0
     label       STR         64      # Key
     outroot     STR         255
Index: branches/eam_branches/20090820/dbconfig/ipp.m4
===================================================================
--- branches/eam_branches/20090820/dbconfig/ipp.m4	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/ipp.m4	(revision 25766)
@@ -14,4 +14,5 @@
 include(chip.md)
 include(cam.md)
+include(add.md)
 include(fake.md)
 include(warp.md)
Index: branches/eam_branches/20090820/dbconfig/new.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/new.md	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/new.md	(revision 25766)
@@ -22,4 +22,6 @@
     uri         STR         255
     epoch       UTC         0001-01-01T00:00:00Z
+    bytes       S32         0
+    md5sum      STR         32
 END
 
Index: branches/eam_branches/20090820/dbconfig/pstamp.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/pstamp.md	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/pstamp.md	(revision 25766)
@@ -24,4 +24,5 @@
     name        STR         64      # UNIQUE
     reqType     STR         16
+    label       STR         64
     outProduct  STR         64
     uri         STR         255
@@ -38,3 +39,4 @@
     exp_id      S64         0
     outputBase  STR         255
+    options     S64         64
 END
Index: branches/eam_branches/20090820/dbconfig/publish.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/publish.md	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/publish.md	(revision 25766)
@@ -1,23 +1,25 @@
 # Tables for publishing data to a science client
 
-publishClient   METADATA 
-    client_id   S64         0       # Primary Key AUTO_INCREMENT
-    product     STR	    64
-    stage	STR	    64
-    workdir     STR	    255
-    comment     STR         255
+publishClient    METADATA 
+    client_id    S64         0       # Primary Key AUTO_INCREMENT
+    product      STR         64
+    stage        STR         64
+    workdir      STR         255
+    comment      STR         255
+END              
+                 
+publishRun       METADATA
+    pub_id       S64         0       # Primary Key AUTO_INCREMENT
+    client_id    S64         0
+    stage_id     S64         0
+    label        STR         64
+    state        STR         64
+END              
+                 
+publishDone      METADATA
+    pub_id       S64         0       # Primary Key
+    path_base    STR         255
+    hostname     STR         64
+    dtime_script F32         0.0
+    fault        S16         0
 END
-
-publishRun	METADATA
-    pub_id      S64         0       # Primary Key AUTO_INCREMENT
-    client_id   S64         0
-    stage_id    S64         0
-    label       STR         64
-    state       STR         64
-END
-
-publishDone	METADATA
-    pub_id      S64         0       # Primary Key
-    path_base	STR	    255
-    fault	S16	    0
-END
Index: branches/eam_branches/20090820/dbconfig/raw.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/raw.md	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/raw.md	(revision 25766)
@@ -136,3 +136,6 @@
     epoch       UTC         0001-01-01T00:00:00Z
     magicked    S64         0
+    bytes       S32         0
+    md5sum      STR         32
+    burntool_state  S16     0
 END
Index: branches/eam_branches/20090820/dbconfig/rc.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/rc.md	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/rc.md	(revision 25766)
@@ -1,7 +1,11 @@
-rcDSProduct METADATA
-    prod_id     S64        0       # Primary Key
-    name        STR        64
-    dbname      STR        64
-    dbhost      STR        64
+rcDestination METADATA
+    dest_id     S64         0       # Primary Key
+    name        STR         64
+    status_uri  STR         255
+    comment     STR         255
+    last_fileset STR        255
+    dbname      STR         64
+    dbhost      STR         64
+    state       STR         64      # Key
 END
 
@@ -9,5 +13,5 @@
     fs_id       S64        0       # Primary Key
     dist_id     S64        0       # fkey(dist_id) ref distRun(dist_id)
-    prod_id     S64        0       # fkey(prod_id) ref rcDSProduct(prod_id)
+    dest_id     S64        0       # fkey(dest_id) ref rcDestination(dest_id)
     name        STR        255
     state       STR        64
@@ -15,13 +19,4 @@
 END
 
-rcDestination METADATA
-    dest_id     S64         0       # Primary Key
-    prod_id     S64         0       # fkey(prod_id) ref rcDSProduct(prod_id)
-    name        STR         64
-    status_uri  STR         255
-    comment     STR         255
-    last_fileset STR        255
-    state       STR         64      # Key
-END
 
 rcInterest METADATA
Index: branches/eam_branches/20090820/dbconfig/summitcopy.md
===================================================================
--- branches/eam_branches/20090820/dbconfig/summitcopy.md	(revision 25206)
+++ branches/eam_branches/20090820/dbconfig/summitcopy.md	(revision 25766)
@@ -57,4 +57,6 @@
     epoch       UTC         0001-01-01T00:00:00Z
     hostname    STR         64
+    bytes       S32         0
+    md5sum      STR         32
 END
 
Index: branches/eam_branches/20090820/extsrc/gpcsw/Make.Common.fixed
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/Make.Common.fixed	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/Make.Common.fixed	(revision 25766)
@@ -670,6 +670,6 @@
 $(DIR_BIN)/%:	$(DIR_BIN)/%-$(VERSION)
 	@echo "--> Installing link to $(notdir $<) as $(notdir $@)"
-	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || /bin/true
-	@-rm -f $(DIR_BIN)/*.TEXT_FILE_BUSY 2> /dev/null || /bin/true
+	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || true
+	@-rm -f $(DIR_BIN)/*.TEXT_FILE_BUSY 2> /dev/null || true
 	@ln $< $@
 	# @-setuidinst $@
@@ -677,10 +677,10 @@
 $(DIR_BIN)/%-$(VERSION): scripts/%.sh
 	@echo "--> Installing sh script $(notdir $@)"
-	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || /bin/true
+	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || true
 	@$(INSTALL) -m 0555 $< $@ || ( rm -f $@ && exit 1 )
 
 $(DIR_BIN)/%-$(VERSION): $(EXECNAME)
 	@echo "--> Installing program $(notdir $@)"
-	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || /bin/true
+	@-mv $@ $@.$(shell date +%H%M%S).TEXT_FILE_BUSY 2> /dev/null || true
 	@$(INSTSTRIP) -m 0755 $< $@ || ( rm -f $@ && exit 1 )
 	@chmod 0555 $@
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/burnparams.h
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/burnparams.h	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/burnparams.h	(revision 25766)
@@ -55,3 +55,5 @@
 EXTERN int EXPIRE_TRAIL_TIME;	/* Expire trails after this interval */
 
+EXTERN int PERSIST_RETAIN;	/* Retain bad-slope persistence fits */
+
 #endif /* _INCLUDED_burnparams_ */
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.c
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.c	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/burntool.c	(revision 25766)
@@ -100,4 +100,6 @@
    EXPIRE_TRAIL_TIME = 2000;	/* Expire a persist after this [sec] */
 
+   PERSIST_RETAIN = 0;		/* Retain persists with bad slopes? */
+
 /* Parse the args */
    cellxy = -1;
@@ -175,4 +177,8 @@
 	 persistfitsfile = argv[i] + 7;
 
+/* Keep persistence streaks which had a bad slope? */
+      } else if(strncmp(argv[i], "persist=", 8) == 0) {/* persist={t|f} */
+	 PERSIST_RETAIN = argv[i][8] == 'y' || argv[i][8] == '1' || argv[i][8] == 't';
+
 /* Output file for PSF gallery */
       } else if(strncmp(argv[i], "psf=", 4) == 0) {	/* psf=fname */
@@ -286,4 +292,18 @@
 	 CONCAT_FITS = argv[i][10] == 'n' || argv[i][10] == '0' || 
 	    argv[i][10] == 'f';
+
+/* Set the e/ADU for the noise gate that cells must pass */
+      } else if(strncmp(argv[i], "EADU=", 5) == 0) {	/* EADU=e */
+	 if(sscanf(argv[i]+5, "%lf", &MIN_EADU) != 1) {
+	    fprintf(stderr, "\rerror: cannot get e/ADU size from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
+
+/* Set the read noise for the noise gate that cells must pass */
+      } else if(strncmp(argv[i], "RN=", 3) == 0) {	/* EADU=e */
+	 if(sscanf(argv[i]+3, "%d", &MAX_READ_NOISE) != 1) {
+	    fprintf(stderr, "\rerror: cannot get read noise size from `%s'\n", argv[i]);
+	    exit(EXIT_FAILURE);
+	 }
 
 /* Quiet? */
@@ -580,10 +600,11 @@
 
 /* Fix up the streaks (don't bother if table only) */
-	    if(!tableonly) {
+// Why the heck do I get to skip this if table only?  Makes no sense!
+//	    if(!tableonly) {
 	       persist_fix(naxis1-ovrscan1, naxis2-ovrscan2, naxis1, buf, 
 			   OTA+cell);
 /* Tell us about it? */
 	       if(VERBOSE & VERB_NORM) persist_blab(OTA+cell);
-	    }
+//	    }
 	 }
 
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/man/burntool.1
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/man/burntool.1	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/man/burntool.1	(revision 25766)
@@ -53,4 +53,12 @@
 	power laws; downward burns as exponentials.
 	
+	The fit to downward, persistence burns may have an unreasonable "slope"
+	(meaning exponential sign), increasing away from the burn origin.
+	These are discarded unless "persist=t" is invoked.  It is possible
+	for the fit to be fooled by uncataloged stars, so the persistence
+	can be kept in the output file with "persist=t" (although no fit
+	correction is applied) and they will propagate from input to output
+	until they finally achieve a legal fit with negligible amplitude.
+
 	Burntool also identifies really blasted areas which are saturated from
 	top to bottom.  These cannot be fitted, but are carried along for
@@ -231,4 +239,8 @@
                 'in' takes precedence.
 
+	persist={t|f}
+		Retain persistence streaks whose fit slope turned out to be
+		unreasonable.
+
 	out=fname      
 		Output file for burn streaks
@@ -290,4 +302,15 @@
 	expire=N
 		Retire a blasted burn after N seconds
+
+	EADU=x
+		Set the minimum e/ADU for acceptable cell sky noise 
+		(default 0.3).  Should not normally be changed!
+	RN=x
+		Set the maximum read noise for acceptable cell sky noise 
+		(default 20).  Should not normally be changed!
+
+		Any cell whose noise variance in the sky is greater than
+		  sky/EADU+RN*RN  is rejected out of hand, and skipped for
+		further processing.
 
 	quiet={t|f}    
@@ -332,4 +355,5 @@
 BUGS:
 	090224: Still in development
+	090810: Squished a few memory bugs
 
 SEE ALSO:
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/persist_fits.c
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/persist_fits.c	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/persist_fits.c	(revision 25766)
@@ -222,6 +222,14 @@
       for(k=0; k<cell[j].npersist; k++) 
       {
-         if(cell[j].persist[k].fiterr) continue;
-         if(cell[j].persist[k].nfit <= 0) continue;
+	 if(PERSIST_RETAIN) {
+/* Keep fits which have a dubious slope */
+	    if(cell[j].persist[k].fiterr != FIT_SLOPE_ERROR) {
+	       if(cell[j].persist[k].fiterr) continue;
+	       if(cell[j].persist[k].nfit <= 0) continue;
+	    }
+	 } else {
+	    if(cell[j].persist[k].fiterr) continue;
+	    if(cell[j].persist[k].nfit <= 0) continue;
+	 }
          num_areas++;
          num_fits += cell[j].persist[k].nfit;
@@ -232,7 +240,16 @@
       {
 	 if(!cell[j].burn[k].burned) continue;
-	 if(cell[j].burn[k].fiterr && 
-	    cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
-	 if(cell[j].burn[k].nfit <= 0) continue;
+	 if(PERSIST_RETAIN) {
+/* Keep fits which have a dubious slope */
+	    if(cell[j].burn[k].fiterr != FIT_SLOPE_ERROR) {
+	       if(cell[j].burn[k].fiterr && 
+		  cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	       if(cell[j].burn[k].nfit <= 0) continue;
+	    }
+	 } else {
+	    if(cell[j].burn[k].fiterr && 
+	       cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	    if(cell[j].burn[k].nfit <= 0) continue;
+	 }
          num_areas++;
          num_fits += cell[j].burn[k].nfit;
@@ -329,6 +346,14 @@
       for(k=0; k<cell[j].npersist; k++) 
       {
-         if(cell[j].persist[k].fiterr) continue;
-         if(cell[j].persist[k].nfit <= 0) continue;     
+	 if(PERSIST_RETAIN) {
+/* Keep fits which have a dubious slope */
+	    if(cell[j].persist[k].fiterr != FIT_SLOPE_ERROR) {
+	       if(cell[j].persist[k].fiterr) continue;
+	       if(cell[j].persist[k].nfit <= 0) continue;     
+	    }
+	 } else {
+	    if(cell[j].persist[k].fiterr) continue;
+	    if(cell[j].persist[k].nfit <= 0) continue;     
+	 }
 
          result = write_area_row(hu, data, table, row++, &(cell[j].persist[k]));
@@ -340,7 +365,16 @@
       {
 	 if(!cell[j].burn[k].burned) continue;
-	 if(cell[j].burn[k].fiterr && 
-	    cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
-	 if(cell[j].burn[k].nfit <= 0) continue;
+	 if(PERSIST_RETAIN) {
+/* Keep fits which have a dubious slope */
+	    if(cell[j].burn[k].fiterr != FIT_SLOPE_ERROR) {
+	       if(cell[j].burn[k].fiterr && 
+		  cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	       if(cell[j].burn[k].nfit <= 0) continue;
+	    }
+	 } else {
+	    if(cell[j].burn[k].fiterr && 
+	       cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	    if(cell[j].burn[k].nfit <= 0) continue;
+	 }
 
          result = write_area_row(hu, data, table, row++, &(cell[j].burn[k]));
@@ -426,5 +460,12 @@
       for(k=0; k<cell[j].npersist; k++) 
       {
-         if(cell[j].persist[k].fiterr) continue;
+	 if(PERSIST_RETAIN) {
+/* Keep fits which have a dubious slope */
+	    if(cell[j].persist[k].fiterr != FIT_SLOPE_ERROR) {
+	       if(cell[j].persist[k].fiterr) continue;
+	    }
+	 } else {
+	    if(cell[j].persist[k].fiterr) continue;
+	 }
 	 for(i=0; i<cell[j].persist[k].nfit; i++) 
          {
@@ -441,6 +482,14 @@
       {
 	 if(!cell[j].burn[k].burned) continue;
-	 if(cell[j].burn[k].fiterr && 
-	    cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	 if(PERSIST_RETAIN) {
+/* Keep fits which have a dubious slope */
+	    if(cell[j].burn[k].fiterr != FIT_SLOPE_ERROR) {
+	       if(cell[j].burn[k].fiterr && 
+		  cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	    }
+	 } else {
+	    if(cell[j].burn[k].fiterr && 
+	       cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	 }
 
 	 for(i=0; i<cell[j].burn[k].nfit; i++) 
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/persistio.c	(revision 25766)
@@ -51,15 +51,16 @@
 	     &boxbuf[nbox].slope, &boxbuf[nbox].nfit,
 	     &boxbuf[nbox].sxfit, &boxbuf[nbox].exfit);
-      if(boxbuf[nbox].nfit <= 0) continue;
-      boxbuf[nbox].zero = (double *)calloc(boxbuf[nbox].nfit, sizeof(double));
-      boxbuf[nbox].xfit = (int *)calloc(boxbuf[nbox].nfit, sizeof(int));
-      boxbuf[nbox].yfit = (int *)calloc(boxbuf[nbox].nfit, sizeof(int));
-      for(i=0; i<boxbuf[nbox].nfit; i++) {
-	 if(fgets(line, 1024, fp) == NULL) {
-	    fprintf(stderr, "\rerror: short read of burn lines\n");
-	    return(-1);
-	 }
-	 sscanf(line, "%d %d %lf\n", &boxbuf[nbox].xfit[i], 
-		&boxbuf[nbox].yfit[i], &boxbuf[nbox].zero[i]);
+      if(boxbuf[nbox].nfit > 0) {
+	 boxbuf[nbox].zero = (double *)calloc(boxbuf[nbox].nfit, sizeof(double));
+	 boxbuf[nbox].xfit = (int *)calloc(boxbuf[nbox].nfit, sizeof(int));
+	 boxbuf[nbox].yfit = (int *)calloc(boxbuf[nbox].nfit, sizeof(int));
+	 for(i=0; i<boxbuf[nbox].nfit; i++) {
+	    if(fgets(line, 1024, fp) == NULL) {
+	       fprintf(stderr, "\rerror: short read of burn lines\n");
+	       return(-1);
+	    }
+	    sscanf(line, "%d %d %lf\n", &boxbuf[nbox].xfit[i], 
+		   &boxbuf[nbox].yfit[i], &boxbuf[nbox].zero[i]);
+	 }
       }
       boxbuf[nbox].fiterr = 0;
@@ -147,8 +148,10 @@
       for(kp=0; kp<n; kp++) {
 	 k = boxid[kp];
-	 zk = box[k].zero[box[k].nfit/2];
+	 zk = 0.0;
+	 if(box[k].nfit > 0) zk = box[k].zero[box[k].nfit/2];
 	 for(jp=kp+1; jp<n; jp++) {
 	    j = boxid[jp];
-	    zj = box[j].zero[box[j].nfit/2];
+	    zj = 0.0;
+	    if(box[j].nfit > 0) zj = box[j].zero[box[j].nfit/2];
 	    if(ABS(yctr[jp]-yctr[kp]) > DIFFERENT_STREAK) {
 /* Trim back the feebler streak */
@@ -238,6 +241,15 @@
 /* First: patched up persists */
       for(k=0; k<cell[j].npersist; k++) {
-	 if(cell[j].persist[k].fiterr) continue;
-	 if(cell[j].persist[k].nfit <= 0) continue;
+
+	 if(PERSIST_RETAIN) {
+/* Keep fits which have a dubious slope */
+	    if(cell[j].persist[k].fiterr != FIT_SLOPE_ERROR) {
+	       if(cell[j].persist[k].fiterr) continue;
+	       if(cell[j].persist[k].nfit <= 0) continue;
+	    }
+	 } else {
+	    if(cell[j].persist[k].fiterr) continue;
+	    if(cell[j].persist[k].nfit <= 0) continue;
+	 }
 	 fprintf(fp, "%3d %7d  %3d %3d %5d %3d  %3d %3d  %3d %3d  %3d %3d %3d %3d %3d %3d %3d %3d  %1d %1d %9.6f %3d %3d %3d\n",
 		 j, cell[j].persist[k].time, 
@@ -262,7 +274,16 @@
       for(k=0; k<cell[j].nburn; k++) {
 	 if(!cell[j].burn[k].burned) continue;
-	 if(cell[j].burn[k].fiterr && 
-	    cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
-	 if(cell[j].burn[k].nfit <= 0) continue;
+	 if(PERSIST_RETAIN) {
+/* Keep fits which have a dubious slope */
+	    if(cell[j].burn[k].fiterr != FIT_SLOPE_ERROR) {
+	       if(cell[j].burn[k].fiterr && 
+		  cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	       if(cell[j].burn[k].nfit <= 0) continue;
+	    }
+	 } else {
+	    if(cell[j].burn[k].fiterr && 
+	       cell[j].burn[k].fiterr != FIT_TOP_ERROR) continue;
+	    if(cell[j].burn[k].nfit <= 0) continue;
+	 }
 
 	 i = (cell[j].burn[k].ex - cell[j].burn[k].sx + 1) / 2;
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/psfstamp.c
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/psfstamp.c	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/psfstamp.c	(revision 25766)
@@ -256,5 +256,5 @@
    int k, l, cellx, celly, ota_xid, ota_yid, nfwave, nqavg;
    double xota, yota, xfp, yfp, phi;
-   double fwhm[3], q[3], fw[MAXPSFMEDIAN];
+   double fwhm[3], q[5], fw[MAXPSFMEDIAN];
    double m2[MAXPSFMEDIAN], qp[MAXPSFMEDIAN], qc[MAXPSFMEDIAN];
    double qt[MAXPSFMEDIAN], fwavg[MAXPSFMEDIAN];
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/burntool/trailfit.c	(revision 25766)
@@ -226,4 +226,6 @@
 /* FIXME: sanity check fits */
    if(slope >= FIT_MAX_SLOPE || slope < FIT_MIN_SLOPE) {
+      box->slope = slope;
+      box->nfit = 0;
       box->fiterr = FIT_SLOPE_ERROR;
       return(-1);
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/libfh/fh.c
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/libfh/fh.c	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/libfh/fh.c	(revision 25766)
@@ -1039,4 +1039,5 @@
 	 newval[strlen(newval) - 1] = '\0';
 	 fh_set_str(hu, idx, name, newval, comment);
+	 free(newval);
 	 return;
       }
@@ -1519,4 +1520,29 @@
       i++;
    }
+   return FH_SUCCESS;
+}
+
+static void
+pad_header(HeaderUnit hu, int n)
+{
+   int i;
+   double idx = 900000000;
+
+   for (i = 0; i < n; i++)
+   {
+      fh_set_card(hu, idx++, FH_RESERVE);
+   }
+}
+
+fh_result
+fh_copy(HeaderUnit hu, const HeaderUnit source_)
+{
+   fh_result result;
+   int reserve;
+
+   result = fh_merge(hu, source_);
+   if (result != FH_SUCCESS) return result;
+   reserve = fh_get_reserve(source_);
+   if (reserve) pad_header(hu, reserve);
    return FH_SUCCESS;
 }
@@ -1757,4 +1783,21 @@
 }
 
+int
+fh_get_reserve(HeaderUnit hu)
+{
+   HeaderUnitStruct* list = FH_HU(hu);
+
+   if (!list)
+   {
+      log_error("invalid argument to fh_get_reserve()");
+      return -1;
+   }
+
+   if (list->reserve)
+      return list->reserve;
+   else
+      return list->reserve_found;
+}
+
 fh_result
 fh_rewrite(HeaderUnit hu)
Index: branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/libfh/fh.h
===================================================================
--- branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/libfh/fh.h	(revision 25206)
+++ branches/eam_branches/20090820/extsrc/gpcsw/gpcsrc/fits/libfh/fh.h	(revision 25766)
@@ -174,4 +174,9 @@
  * is used to create a new FITS header.  NOT for use with fh_rewrite().
  */
+int fh_get_reserve(HeaderUnit hu);
+/*
+ * Get the current setting or the number of reserve cards found in
+ * a header unit.  Returns -1 if hu is invalid.
+ */
 fh_result fh_validate(HeaderUnit hu); /* fh_validate.c; for use by fhtool.c */
 
@@ -386,4 +391,5 @@
 double fh_idx(HeaderUnit hu); /* idx of the last card returned by fh_next */
 fh_result fh_merge(HeaderUnit hu, const HeaderUnit source); /* source unchanged */
+fh_result fh_copy(HeaderUnit hu, const HeaderUnit source); /* fh_merge+keep reserve */
 
 /* ---------------------------------------------------------
@@ -459,4 +465,3 @@
  */
 
-
 #endif /* _INCLUDED_fh */
Index: branches/eam_branches/20090820/ippMonitor/raw/Login.php
===================================================================
--- branches/eam_branches/20090820/ippMonitor/raw/Login.php	(revision 25206)
+++ branches/eam_branches/20090820/ippMonitor/raw/Login.php	(revision 25766)
@@ -44,5 +44,5 @@
     echo "You are now logged out<br>\n";
     logintext ();
-    loginform ();
+    loginform ("");
     menu_end ();
     exit ();
Index: branches/eam_branches/20090820/ippScripts/Build.PL
===================================================================
--- branches/eam_branches/20090820/ippScripts/Build.PL	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/Build.PL	(revision 25766)
@@ -49,4 +49,5 @@
         scripts/chip_imfile.pl
         scripts/camera_exp.pl
+        scripts/addstar_run.pl
         scripts/fake_imfile.pl
         scripts/warp_overlap.pl
Index: branches/eam_branches/20090820/ippScripts/scripts/addstar_run.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/addstar_run.pl	(revision 25766)
+++ branches/eam_branches/20090820/ippScripts/scripts/addstar_run.pl	(revision 25766)
@@ -0,0 +1,250 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+use Carp;
+
+## report the program and machine
+use Sys::Hostname;
+my $host = hostname();
+print "\n\n";
+print "Starting script $0 on $host\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 PS::IPP::Config 1.01 qw( :standard );
+use File::Temp qw( tempfile );
+
+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 $camtool = can_run('camtool') or (warn "Can't find camtool" and $missing_tools = 1);
+my $addtool = can_run('addtool') or (warn "Can't find addtool" and $missing_tools = 1);
+#my $ppImage = can_run('ppImage') or (warn "Can't find ppImage" and $missing_tools = 1);
+my $ppConfigDump = can_run('ppConfigDump') or (warn "Can't find ppConfigDump" and $missing_tools = 1);
+#my $ppStatsFromMetadata = can_run('ppStatsFromMetadata') or (warn "Can't find ppStatsFromMetadata" and $missing_tools = 1);
+#my $psastro = can_run('psastro') or (warn "Can't find psastro" and $missing_tools = 1);
+my $addstar = can_run('addstar') or (warn "Can't find addstar" and $missing_tools = 1);
+if ($missing_tools) {
+    warn("Can't find required tools.");
+    exit($PS_EXIT_CONFIG_ERROR);
+}
+
+my ( $exp_tag, $add_id, $camera, $outroot, $camroot, $recipe, $dbname, $reduction, $dvodb, $verbose, $no_update,
+     $no_op, $redirect, $save_temps, $run_state);
+GetOptions(
+    'exp_tag=s'          => \$exp_tag, # Exposure identifier
+    'add_id=s'          => \$add_id, # Camtool identifier
+    'recipe=s'          => \$recipe, # Recipe to use
+    'camera|c=s'        => \$camera, # Camera
+    'dbname|d=s'        => \$dbname, # Database name
+    'outroot|w=s'       => \$outroot, # output file base name
+    'camroot|w=s'       => \$camroot, # camera stage root name.
+    'reduction=s'       => \$reduction, # Reduction class
+    'dvodb|w=s'         => \$dvodb,  # output DVO database
+    'run-state=s'       => \$run_state, # 'new' or 'update'
+    'verbose'           => \$verbose,   # Print to stdout
+    'no-update'         => \$no_update, # Update the database?
+    'no-op'             => \$no_op, # Don't do any operations?
+    'redirect-output'   => \$redirect,
+    'save-temps'        => \$save_temps, # Save temporary files?
+    ) or pod2usage( 2 );
+
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage(
+          -msg => "Required options: --exp_tag --add_id --camera --outroot",
+          -exitval => 3,
+          ) unless
+    defined $exp_tag and
+    defined $add_id and
+    defined $outroot and
+    defined $camera;
+
+my $ipprc = PS::IPP::Config->new( $camera ) or my_die( "Unable to set up", $add_id, $PS_EXIT_CONFIG_ERROR ); # IPP configuration
+
+my $logDest = $ipprc->filename("LOG.EXP", $outroot) or &my_die("Missing entry from camera config", $add_id, $PS_EXIT_CONFIG_ERROR);
+
+if (not defined $run_state) { $run_state = 'new'; }
+if ($run_state eq 'update') {
+    $logDest .= '.update';
+}
+
+if ($redirect) {
+    $ipprc->redirect_output($logDest) or my_die( "Unable to redirect output", $add_id, $PS_EXIT_SYS_ERROR );
+    print "\n\n";
+    print "Starting script $0 on $host\n\n";
+    print "COMMAND IS: @ARGV\n\n";
+}
+
+# Recipes to use based on reduction class
+$reduction = 'DEFAULT' unless defined $reduction;
+
+my $recipe_addstar = $ipprc->reduction($reduction, 'ADDSTAR'); # Recipe to use
+&my_die("Unrecognised ADDSTAR recipe", $add_id, $PS_EXIT_CONFIG_ERROR) unless defined $recipe_addstar;
+
+#my $recipe_psastro = $ipprc->reduction($reduction, 'PSASTRO'); # Recipe to use
+#&my_die("Unrecognised PSASTRO recipe", $cam_id, $PS_EXIT_CONFIG_ERROR) unless defined $recipe_psastro;
+
+my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
+
+my $cmdflags;
+
+# Get list of component files
+my $files;                      # Array of component files
+{
+    my $command = "$addtool -pendingexp -add_id $add_id"; # Command to run
+    $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 addtool: $error_code", $add_id, $error_code);
+    }
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", $add_id, $PS_EXIT_PROG_ERROR);
+    
+    # extract the metadata for the files into a hash list
+    $files = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", $add_id, $PS_EXIT_PROG_ERROR);   
+}
+
+my $chipObjectsExist = 0;
+
+# Output products
+$ipprc->outroot_prepare($outroot);
+
+# the camera configurations should define the psastro output to be a single file (MEF), regardless of the inputs
+my $fpaObjects = $ipprc->filename("PSASTRO.OUTPUT",     $camroot) or &my_die("Missing entry from camera config", $add_id, $PS_EXIT_CONFIG_ERROR);
+my $traceDest  = $ipprc->filename("TRACE.EXP",          $outroot) or &my_die("Missing entry from camera config", $add_id, $PS_EXIT_CONFIG_ERROR);
+
+if ($run_state eq 'update') {
+    $traceDest .= '.update';
+}
+
+# convert supplied DVO database name to UNIX filename
+my $dvodbReal;
+if (defined $dvodb) {
+    $dvodbReal = $ipprc->dvo_catdir( $dvodb ); # catdir for DVO
+    $dvodbReal = $ipprc->convert_filename_absolute( $dvodbReal );
+}
+
+my $dtime_addstar = 0;
+
+unless ($no_op) {
+    if (defined $dvodbReal and ($run_state eq 'new')) {
+	## XXX the camera analysis can either save the full set of
+	## detections, or just the image metadata, in the dvodb
+	
+	## get the addstar recipe for this camera and CAMERA reduction
+	my $command = "$ppConfigDump -camera $camera -recipe ADDSTAR $recipe_addstar -dump-recipe ADDSTAR -";
+	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 ppConfigDump: $error_code", $add_id, $PS_EXIT_SYS_ERROR);
+	}
+	my $recipeData = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", $add_id, $PS_EXIT_SYS_ERROR);
+	
+	## allow the dvodb to save only images, or the full detection set
+	my $imagesOnly = metadataLookupBool($recipeData, 'IMAGES.ONLY');
+	
+	# XXX this construct requires the user to have a valid .ptolemyrc
+	# XXX which in turn points at ippconfig/dvo.site
+	# require a defined output dvo database to run addstar (ie, refuse to use the .ptolemyrc default)
+	# XXX this needs to be converted to addstar_client...
+
+	my $camdir = $ipprc->dvo_cameradir(); # Camera directory for addstar
+	$command  = "$addstar -D CAMERA $camdir -update";
+	$command .= " -image" if $imagesOnly;
+	$command .= " -D CATDIR $dvodbReal";
+	
+	my $realFile = $ipprc->file_resolve($fpaObjects);
+	$command .= " $realFile";
+	
+	my $mjd_addstar_start = DateTime->now->mjd;   # MJD of starting script
+	
+	( $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 addstar: $error_code", $add_id, $error_code);
+	}
+	$dtime_addstar = 86400.0*(DateTime->now->mjd - $mjd_addstar_start);   # MJD of starting script
+    }
+}
+
+
+# This needs to be updated when addtool is written. BROKEN
+my $fpaCommand = "$addtool -add_id $add_id";
+if ($run_state eq 'new') {
+    $fpaCommand .= " -addprocessedexp";
+    $fpaCommand .= " -path_base $outroot";
+    $fpaCommand .= " $cmdflags";
+    $fpaCommand .= " -dtime_addstar $dtime_addstar";
+} else {
+    $fpaCommand .= " -updaterun -state full";
+}
+$fpaCommand .= " -dbname $dbname" if defined $dbname;
+
+# Add the result into the database
+unless ($no_update) {
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $fpaCommand, verbose => $verbose);
+    unless ($success) {
+        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+        warn("Unable to add result to database: $error_code\n");
+        exit($error_code);
+    }
+} else {
+    print "skipping command: $fpaCommand\n";
+}
+
+
+sub my_die
+{
+    my $msg = shift; # Warning message on die
+    my $add_id = shift; # Camtool identifier
+    my $exit_code = shift; # Exit code to add
+
+    $exit_code = $PS_EXIT_PROG_ERROR unless defined $exit_code;
+
+    carp($msg);
+    if (defined $add_id and not $no_update) {
+# This needs to be updated when addtool is written. BROKEN
+        my $command = "$addtool -add_id $add_id";
+        if ($run_state eq 'new') {
+            $command .= " -addprocessedexp";
+            $command .= " -uri UNKNOWN";
+            $command .= " -fault $exit_code";
+            $command .= " -path_base $outroot";
+            $command .= " -path_base $outroot" if defined $outroot;
+            $command .= (" -dtime_script " . ((DateTime->now->mjd - $mjd_start) * 86400));
+        } else {
+            $command .= " -updateprocessedexp";
+            $command .= " -fault $exit_code";
+        }
+        $command .= " -dbname $dbname" if defined $dbname;
+        system ($command);
+    }
+    exit $exit_code;
+}
+
+
+END {
+    my $status = $?;
+    system("sync") == 0
+        or die "failed to execute sync: $!" ;
+    $? = $status;
+}
+
+__END__
Index: branches/eam_branches/20090820/ippScripts/scripts/camera_exp.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/camera_exp.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/camera_exp.pl	(revision 25766)
@@ -93,6 +93,6 @@
 &my_die("Unrecognised JPEG recipe", $cam_id, $PS_EXIT_CONFIG_ERROR) unless defined $recipe2;
 
-my $recipe_addstar = $ipprc->reduction($reduction, 'ADDSTAR'); # Recipe to use
-&my_die("Unrecognised ADDSTAR recipe", $cam_id, $PS_EXIT_CONFIG_ERROR) unless defined $recipe_addstar;
+#my $recipe_addstar = $ipprc->reduction($reduction, 'ADDSTAR'); # Recipe to use
+#&my_die("Unrecognised ADDSTAR recipe", $cam_id, $PS_EXIT_CONFIG_ERROR) unless defined $recipe_addstar;
 
 my $recipe_psastro = $ipprc->reduction($reduction, 'PSASTRO'); # Recipe to use
@@ -205,5 +205,5 @@
 }
 
-my $dtime_addstar = 0;
+#my $dtime_addstar = 0;
 
 unless ($no_op) {
@@ -297,47 +297,47 @@
 
         # run addstar on the output fpaObjects (if a DVO database is defined)
-        if (defined $dvodbReal and ($run_state eq 'new')) {
-
-            ## XXX the camera analysis can either save the full set of
-            ## detections, or just the image metadata, in the dvodb
-
-            ## get the addstar recipe for this camera and CAMERA reduction
-            $command = "$ppConfigDump -camera $camera -recipe ADDSTAR $recipe_addstar -dump-recipe ADDSTAR -";
-            ( $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 ppConfigDump: $error_code", $cam_id, $PS_EXIT_SYS_ERROR);
-            }
-            my $recipeData = $mdcParser->parse(join "", @$stdout_buf) or
-                &my_die("Unable to parse metadata config doc", $cam_id, $PS_EXIT_SYS_ERROR);
-
-            ## allow the dvodb to save only images, or the full detection set
-            my $imagesOnly = metadataLookupBool($recipeData, 'IMAGES.ONLY');
-
-            # XXX this construct requires the user to have a valid .ptolemyrc
-            # XXX which in turn points at ippconfig/dvo.site
-            # require a defined output dvo database to run addstar (ie, refuse to use the .ptolemyrc default)
-            # XXX this needs to be converted to addstar_client...
-
-            my $camdir = $ipprc->dvo_cameradir(); # Camera directory for addstar
-            my $command;
-            $command  = "$addstar -D CAMERA $camdir -update";
-            $command .= " -image" if $imagesOnly;
-            $command .= " -D CATDIR $dvodbReal";
-
-            my $realFile = $ipprc->file_resolve($fpaObjects);
-            $command .= " $realFile";
-
-            my $mjd_addstar_start = DateTime->now->mjd;   # MJD of starting script
-
-            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 addstar: $error_code", $cam_id, $error_code);
-            }
-            $dtime_addstar = 86400.0*(DateTime->now->mjd - $mjd_addstar_start);   # MJD of starting script
-        }
+#         if (defined $dvodbReal and ($run_state eq 'new')) {
+
+#             ## XXX the camera analysis can either save the full set of
+#             ## detections, or just the image metadata, in the dvodb
+
+#             ## get the addstar recipe for this camera and CAMERA reduction
+#             $command = "$ppConfigDump -camera $camera -recipe ADDSTAR $recipe_addstar -dump-recipe ADDSTAR -";
+#             ( $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 ppConfigDump: $error_code", $cam_id, $PS_EXIT_SYS_ERROR);
+#             }
+#             my $recipeData = $mdcParser->parse(join "", @$stdout_buf) or
+#                 &my_die("Unable to parse metadata config doc", $cam_id, $PS_EXIT_SYS_ERROR);
+
+#             ## allow the dvodb to save only images, or the full detection set
+#             my $imagesOnly = metadataLookupBool($recipeData, 'IMAGES.ONLY');
+
+#             # XXX this construct requires the user to have a valid .ptolemyrc
+#             # XXX which in turn points at ippconfig/dvo.site
+#             # require a defined output dvo database to run addstar (ie, refuse to use the .ptolemyrc default)
+#             # XXX this needs to be converted to addstar_client...
+
+#             my $camdir = $ipprc->dvo_cameradir(); # Camera directory for addstar
+#             my $command;
+#             $command  = "$addstar -D CAMERA $camdir -update";
+#             $command .= " -image" if $imagesOnly;
+#             $command .= " -D CATDIR $dvodbReal";
+
+#             my $realFile = $ipprc->file_resolve($fpaObjects);
+#             $command .= " $realFile";
+
+#             my $mjd_addstar_start = DateTime->now->mjd;   # MJD of starting script
+
+#             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 addstar: $error_code", $cam_id, $error_code);
+#             }
+#             $dtime_addstar = 86400.0*(DateTime->now->mjd - $mjd_addstar_start);   # MJD of starting script
+#         }
     }
 }
@@ -353,5 +353,5 @@
     $fpaCommand .= " -hostname $host" if defined $host;
     $fpaCommand .= " -dtime_script $dtime_script";
-    $fpaCommand .= " -dtime_addstar $dtime_addstar";
+#    $fpaCommand .= " -dtime_addstar $dtime_addstar";
 } else {
     $fpaCommand .= " -updaterun -state full";
Index: branches/eam_branches/20090820/ippScripts/scripts/chip_imfile.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/chip_imfile.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/chip_imfile.pl	(revision 25766)
@@ -19,4 +19,5 @@
 use IPC::Cmd 0.36 qw( can_run run );
 use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::List qw( parse_md_list );
 use PS::IPP::Config 1.01 qw( :standard );
 use File::Temp qw( tempfile );
@@ -143,7 +144,142 @@
     ## XXX make the feature more general?
     my $useDeburnedImage = metadataLookupBool($recipeData, 'USE.DEBURNED.IMAGE');
-    if ($useDeburnedImage && $deburned) {
-        $uri =~ s/fits$/burn.fits/;
-        &my_die("Couldn't find deburned input file: $uri\n", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($uri);
+
+    if ($useDeburnedImage) {
+	my $useBestBurntool  = metadataLookupBool($recipeData, 'USE.BEST.BURNTOOL');
+
+	## Check that we have required programs:
+#	print STDERR "Inside burntool loop!\n";
+	my $regtool  = can_run('regtool') or &my_die ("Can't find regtool", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+	my $funpack  = can_run('funpack') or &my_die ("Can't find funpack", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+	my $burntool = can_run('burntool') or &my_die ("Can't find burntool", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+	
+        ## Check the current burntool processing version:
+        my $regtool_state_cmd = "$regtool -processedimfile -exp_id $exp_id -class_id $class_id -limit 1";
+        if (defined($dbname)) {
+            $regtool_state_cmd .= " -dbname $dbname";
+        }
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $regtool_state_cmd, verbose => $verbose);
+
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform regtool: $error_code", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+        }
+
+        my $regData = $mdcParser->parse(join "", @$stdout_buf) or
+            &my_die("Unable to parse regtool metadata", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+        my $regData2 = parse_md_list($regData);
+
+        my $burntoolState = 999;
+        foreach my $regEntry (@$regData2) {
+#           print "$regEntry->{exp_id} $regEntry->{burntool_state}\n";
+
+            if ($regEntry->{exp_id} == $exp_id) {
+                $burntoolState = $regEntry->{burntool_state};
+            }
+        }
+        if ($burntoolState == 999) {
+            &my_die("Unable to find burntool_state in metadata", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+        }
+	if ($burntoolState == 32767) {
+	    $burntoolState = 0;
+	}
+
+        ## Read camera config to get the current good burntool state :
+        ## XXX This is extremely slow. Any better way to do this?
+        my $camera_config_cmd = "$ppConfigDump -camera $camera -dump-camera -";
+        ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $camera_config_cmd, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform ppConfigDump: $error_code", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+        }
+
+        my $camData = $mdcParser->parse(join "", @$stdout_buf) or
+            &my_die("Unable to parse ppConfigDump metadata", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+
+        my $burntoolStateGood;
+        foreach my $camEntry (@$camData) {
+            if ($camEntry->{name} eq "BURNTOOL.STATE.GOOD") {
+                $burntoolStateGood = $camEntry->{value};
+            }
+        }
+
+	if (abs($burntoolState) != $burntoolStateGood) {
+	    if ($useBestBurntool) {
+		&my_die("Image burntool version does not match current accepted version.", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+	    }
+	    else {
+		warn ("Image burntool version does not match current accepted version. Continuing as requested.");
+		# Internally pretend that we're at a good version.
+		if ($burntoolState < -10) {
+		    $burntoolState = -1 * $burntoolStateGood;
+		}
+		elsif ($burntoolState > 10) {
+		    $burntoolState = $burntoolStateGood;
+		}
+		elsif ($burntoolState == 0) {
+		    # You've told me to use a deburned image, and that you don't care if it's the most recent. The database has told me
+		    # that burntool has never been run on this image. We'll hope the database is wrong, but I don't really trust that.
+		    warn ("burntool_state suggests no table will be found. This will likely crash.");
+		    $burntoolState = -1 * $burntoolStateGood;
+		}
+		else {
+		    &my_die("No valid burntool table will be found.", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+		}
+	    }
+	}
+
+        ## We now know that we have an image that has been burntooled.
+        my ($tempFile, $tempName) = tempfile( "/tmp/chip.$exp_id.$class_id.deburned.XXXX",
+                                              UNLINK => !$save_temps, SUFFIX => '.fits' );
+
+        # get the UNIX version of the (possible) neb: or path: filename
+        my $uriReal = $ipprc->file_resolve( $uri );
+
+        # funpack into the temp file.
+        my $funpack_cmd = "$funpack -S $uriReal > $tempName";
+        ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $funpack_cmd, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform funpack: $error_code", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+        }
+
+        ## Construct commands to apply the pre-calculated burntool trailfits to the pixel data.
+        my ($burntoolTable_uri, $burntoolTable_uriReal);
+        my $burntool_cmd = "$burntool ";
+
+        if ($burntoolState == -1 * $burntoolStateGood) {   # Burntool information stored in an external table.
+            $burntoolTable_uri = $uri;
+            $burntoolTable_uri =~ s/fits$/burn.tbl/;
+            $burntoolTable_uriReal = $ipprc->file_resolve( $burntoolTable_uri );
+            unless ($ipprc->file_exists($burntoolTable_uri)) {
+                &my_die("Couldn't find burntool table: $burntoolTable_uri",$exp_id,$chip_id,$class_id, $PS_EXIT_SYS_ERROR);
+            }
+
+            $burntool_cmd .= "$tempName in=${burntoolTable_uriReal} apply=t";
+        }
+        elsif ($burntoolState == $burntoolStateGood) { # Burntool information stored in a header table.
+            $burntool_cmd .= "$tempName apply=t";
+        }
+        else {
+            &my_die("Image data not properly burntooled, impossible state", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+        }
+
+        ## Run burntool to change the pixels of tempfile, and repoint $uri to that file.
+        ($success, $error_code, $full_buf, $stdout_buf, $stderr_buf) =
+            run(command => $burntool_cmd, verbose => $verbose);
+        unless ($success) {
+            $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+            &my_die("Unable to perform burntool: $error_code", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+        }
+
+        $uri = $tempName;
+        unless ($ipprc->file_exists($uri)) {
+            &my_die("Couldn't find deburned input file: $uri\n", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+        }
+
+#       print STDERR "$uri $uriReal $tempName $burntoolTable_uri $burntoolTable_uriReal $burntool_cmd $save_temps\n";
+#       exit(100);
     }
 
@@ -152,48 +288,48 @@
     if ($tiltystreakApply) {
 
-	my $tiltystreakByClass = metadataLookupMD($recipeData, 'TILTYSTREAK.BY.CLASS');
-	my $tiltystreakClassApply = metadataLookupBool($tiltystreakByClass, "APPLY.$class_id");
-	if ($tiltystreakClassApply) {
-
-	    my $tiltystreakClassOptions = metadataLookupStr($tiltystreakByClass, "OPTIONS.$class_id");
-	    if ($tiltystreakClassOptions eq "none") {
-		$tiltystreakClassOptions = "";
-	    }
-
-	    my ($success, $error_code, $full_buf, $stdout_buf, $stderr_buf);
-
-	    # XXX make these optional (must be built by psbuild as well...)
-	    my $funpack = can_run('funpack') or &my_die ("Can't find funpack", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
-	    my $tiltystreak = can_run('tiltystreak') or &my_die ("Can't find tiltystreak", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
-
-	    # create an temporary output file:
-	    my ($tempFile, $tempName) = tempfile( "/tmp/chip.$exp_id.$class_id.tmp.XXXX", UNLINK => !$save_temps );
-
-	    print "uri: $uri\n";
-
-	    # get the UNIX version of the (possible) neb: or path: filename
-	    my $uriReal = $ipprc->file_resolve( $uri );
-
-	    print "uriReal: $uriReal\n";
-
-	    # unpack the data (is a NOP if not compressed)
-	    $command = "$funpack -S $uriReal > $tempName";
-	    ( $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 funpack: $error_code", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
-	    }
-
-	    # run tiltystreak
-	    $command = "$tiltystreak $tempName $tiltystreakClassOptions";
-	    ( $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 tiltystreak: $error_code", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
-	    }
-
-	    # supply the output file as the new input file
-	    $uri = $tempName;
-	}
+        my $tiltystreakByClass = metadataLookupMD($recipeData, 'TILTYSTREAK.BY.CLASS');
+        my $tiltystreakClassApply = metadataLookupBool($tiltystreakByClass, "APPLY.$class_id");
+        if ($tiltystreakClassApply) {
+
+            my $tiltystreakClassOptions = metadataLookupStr($tiltystreakByClass, "OPTIONS.$class_id");
+            if ($tiltystreakClassOptions eq "none") {
+                $tiltystreakClassOptions = "";
+            }
+
+            my ($success, $error_code, $full_buf, $stdout_buf, $stderr_buf);
+
+            # XXX make these optional (must be built by psbuild as well...)
+            my $funpack = can_run('funpack') or &my_die ("Can't find funpack", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+            my $tiltystreak = can_run('tiltystreak') or &my_die ("Can't find tiltystreak", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+
+            # create an temporary output file:
+            my ($tempFile, $tempName) = tempfile( "/tmp/chip.$exp_id.$class_id.tmp.XXXX", UNLINK => !$save_temps );
+
+            print "uri: $uri\n";
+
+            # get the UNIX version of the (possible) neb: or path: filename
+            my $uriReal = $ipprc->file_resolve( $uri );
+
+            print "uriReal: $uriReal\n";
+
+            # unpack the data (is a NOP if not compressed)
+            $command = "$funpack -S $uriReal > $tempName";
+            ( $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 funpack: $error_code", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+            }
+
+            # run tiltystreak
+            $command = "$tiltystreak $tempName $tiltystreakClassOptions";
+            ( $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 tiltystreak: $error_code", $exp_id, $chip_id, $class_id, $PS_EXIT_SYS_ERROR);
+            }
+
+            # supply the output file as the new input file
+            $uri = $tempName;
+        }
     }
 
@@ -253,21 +389,5 @@
         }
         chomp $cmdflags;
-        if (($camera ne "GPC1") or ($class_id ne "XY27") or ($exp_id < 53171)) {
-            ($quality) = $cmdflags =~ /-quality (\d+)/; # Quality flag
-        } else {
-            # hack to kick ota 27 out of subsequent analysis by setting quality flag to a non-zero value
-            my ($before, $after) = split " -quality ", $cmdflags;
-
-            # get the current value
-            ($quality) = $after =~ /^(\d+)/;
-            $after = substr($after, length($quality));
-
-            # replace it if it is zero
-            $quality = 42 if !$quality;
-
-            # rebuild the cmdflags
-            $cmdflags = $before . " -quality $quality";
-            $cmdflags .= " $after" if $after;
-        }
+        ($quality) = $cmdflags =~ /-quality (\d+)/; # Quality flag
     }
 
Index: branches/eam_branches/20090820/ippScripts/scripts/dist_component.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/dist_component.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/dist_component.pl	(revision 25766)
@@ -164,4 +164,8 @@
             or ($file_rule =~ /.JPEG2/));
 
+    if ($stage eq "diff") {
+        next if $file_rule =~ /CONV/;
+    }
+
     my $file_name = $file->{name};
     my $base = basename($file_name);
Index: branches/eam_branches/20090820/ippScripts/scripts/dist_make_fileset.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/dist_make_fileset.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/dist_make_fileset.pl	(revision 25766)
@@ -39,5 +39,6 @@
 
 # Parse the command-line arguments
-my ($dist_id, $dist_dir, $target_id, $stage, $stage_id, $prod_id, $product_name, $ds_dbhost, $ds_dbname);
+my ($dist_id, $dist_dir, $target_id, $stage, $stage_id, $dest_id, $product_name, $ds_dbhost, $ds_dbname);
+my ($label, $filter);
 my ($dbname, $save_temps, $verbose, $no_update, $logfile);
 
@@ -48,6 +49,8 @@
            'stage=s'        => \$stage,      # raw, chip, camera, fake, warp, stack, or diff
            'stage_id=s'     => \$stage_id,   # exp_id, chip_id, etc.
-           'prod_id=s'      => \$prod_id,    # id for the product
+           'dest_id=s'      => \$dest_id,    # id for the product
            'product_name=s' => \$product_name,  # location of the data store directory for this product
+           'label=s'       => \$label,
+           'filter=s'      => \$filter,
            'ds_dbhost=s'    => \$ds_dbhost,  # database host for the datastore database
            'ds_dbname=s'    => \$ds_dbname,  # database name for the datastore database
@@ -60,5 +63,5 @@
 
 pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
-pod2usage( -msg => "Required options: --dist_id --dist_dir --target_id --stage --stage_id --prod_id --ds_dbhost --ds_dbname",
+pod2usage( -msg => "Required options: --dist_id --dist_dir --target_id --stage --stage_id --label --filter --dest_id --ds_dbhost --ds_dbname",
            -exitval => 3) unless
     defined $dist_id and
@@ -67,5 +70,7 @@
     defined $stage and
     defined $stage_id and
-    defined $prod_id and
+    defined $label and
+    defined $filter and
+    defined $dest_id and
     defined $product_name and
     defined $ds_dbhost and
@@ -79,7 +84,8 @@
 my $fs_tag = get_fileset_tag($ipprc, $stage, $stage_id, $dbname);
 
-&my_die("failed to lookup fileset tag", $dist_id, $prod_id, $PS_EXIT_UNKNOWN_ERROR) if !$fs_tag;
-
-my $fileset_name = "$fs_tag.$stage.$stage_id.$dist_id.$prod_id";
+&my_die("failed to lookup fileset tag", $dist_id, $dest_id, $PS_EXIT_UNKNOWN_ERROR) if !defined $fs_tag;
+
+my $fileset_name = $fs_tag ? "$fs_tag." : "";
+$fileset_name .= "$stage.$stage_id.$dist_id.$dest_id";
 
 print "$fileset_name\n";
@@ -89,5 +95,5 @@
 my $dbinfo_file = "dbinfo.$stage.$stage_id.mdc";
 if (! -e "$dist_dir/$dbinfo_file" ) {
-    &my_die("dbinfo file for dist run $dbinfo_file not found", $dist_id, $prod_id, $PS_EXIT_UNKNOWN_ERROR);
+    &my_die("dbinfo file for dist run $dbinfo_file not found", $dist_id, $dest_id, $PS_EXIT_UNKNOWN_ERROR);
 }
 print "dbinfo file $dbinfo_file exists\n" if $verbose;
@@ -96,5 +102,5 @@
 my $dirinfo_file = "dirinfo.$stage.$stage_id.mdc";
 if (! -e "$dist_dir/$dirinfo_file" ) {
-    &my_die("dirinfo file for dist run $dirinfo_file not found", $dist_id, $prod_id, $PS_EXIT_UNKNOWN_ERROR);
+    &my_die("dirinfo file for dist run $dirinfo_file not found", $dist_id, $dest_id, $PS_EXIT_UNKNOWN_ERROR);
 }
 print "dirinfo file $dirinfo_file exists\n" if $verbose;
@@ -116,9 +122,9 @@
     unless ($success) {
         $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        &my_die("Unable to perform $command error_code: $error_code", $dist_id, $prod_id, $error_code);
+        &my_die("Unable to perform $command error_code: $error_code", $dist_id, $dest_id, $error_code);
     }
 
     my $metadata = $mdcParser->parse (join "", @$stdout_buf) or
-        &my_die("Unable to parse metadata config doc", $dist_id, $prod_id, $PS_EXIT_PROG_ERROR);
+        &my_die("Unable to parse metadata config doc", $dist_id, $dest_id, $PS_EXIT_PROG_ERROR);
 
     $components = parse_md_list($metadata);
@@ -146,6 +152,5 @@
 
 {
-    # XXX: need to chose an appropriate file set type
-    my $command = "$dsreg --add $fileset_name --product $product_name --type notset --list $listFileName";
+    my $command = "$dsreg --add $fileset_name --product $product_name --type IPP-DIST --list $listFileName";
 
     # the data store will refer to the distribution bundle via symlinks back to distRun.outdir
@@ -153,18 +158,21 @@
 
     # set the product specific columns in product list
-    $command .= " --ps0 $target_id --ps1 $stage --ps2 $stage_id --ps3 $fs_tag";
-
-    $command .= " --dbname $ds_dbname";    # XXX: notyet --dbhost $ds_dbhost
-
-    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 $command error_code: $error_code", $dist_id, $prod_id, $error_code);
+    my $prod_col_3 = $fs_tag ? $fs_tag : "$stage.$stage_id";
+
+    $command .= " --ps0 $target_id --ps1 $stage --ps2 $stage_id --ps3 $prod_col_3";
+    $command .= " --ps4 $label --ps5 $filter";
+
+    $command .= " --dbname $ds_dbname --dbhost $ds_dbhost";
+
+    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 $command error_code: $error_code", $dist_id, $dest_id, $error_code);
     }
 }
 
 {
-    my $command = "$disttool -addfileset -dist_id $dist_id -prod_id $prod_id -name $fileset_name";
+    my $command = "$disttool -addfileset -dist_id $dist_id -dest_id $dest_id -name $fileset_name";
     $command .= " -dbname $dbname" if $dbname;
 
@@ -175,5 +183,5 @@
         # We need to have revertfileset check whether the fileset exists and do dsreg -del if it does
         $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-        &my_die("Unable to perform $command error_code: $error_code", $dist_id, $prod_id, $error_code);
+        &my_die("Unable to perform $command error_code: $error_code", $dist_id, $dest_id, $error_code);
     }
 }
@@ -211,8 +219,6 @@
     my $dbname = shift;
 
-    if ($stage eq 'stack') {
-        return "stack.$stage_id";
-    } elsif ($stage eq 'diff') {
-        return "diff.$stage_id";
+    if (($stage eq 'stack') or ($stage eq 'diff')) {
+        return "";
     }
 
@@ -248,5 +254,5 @@
     my $tag = $ref->{exp_name};
 
-    return $tag;
+    return "$tag";
 }
 
@@ -254,11 +260,11 @@
     my $msg = shift;
     my $dist_id = shift;
-    my $prod_id = shift;
+    my $dest_id = shift;
     my $fault = shift;
 
-    # TODO: disttool -adddsfileset -prod_id $prod_id -dist_id $dist_id -fault $fault
+    # TODO: disttool -adddsfileset -dest_id $dest_id -dist_id $dist_id -fault $fault
     print STDERR "$msg\n";
 
-    my $command = "$disttool -addfileset -dist_id $dist_id -prod_id $prod_id -fault $fault";
+    my $command = "$disttool -addfileset -dist_id $dist_id -dest_id $dest_id -fault $fault";
     $command .= " -dbname $dbname" if $dbname;
 
Index: branches/eam_branches/20090820/ippScripts/scripts/ipp_cleanup.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/ipp_cleanup.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/ipp_cleanup.pl	(revision 25766)
@@ -60,8 +60,8 @@
 
 
-my %stages = ( chip => 1, camera => 1, fake => 1, warp => 1, stack => 1, diff  => 1,
-	       detrend.process.imfile => 1, detrend.process.exp => 1, detrend.stack.imfile => 1,
-	       detrend.normstat.imfile => 1, detrend.norm.imfile => 1, detrend.norm.exp => 1,
-	       detrend.resid.imfile => 1, detrend.resid.exp => 1 );
+my %stages = ( "chip" => 1, "camera" => 1, "fake" => 1, "warp" => 1, "stack" => 1, "diff"  => 1,
+	       "detrend.process.imfile" => 1, "detrend.process.exp" => 1, "detrend.stack.imfile" => 1,
+	       "detrend.normstat.imfile" => 1, "detrend.norm.imfile" => 1, "detrend.norm.exp" => 1,
+	       "detrend.resid.imfile" => 1, "detrend.resid.exp" => 1 );
 unless ($stages{$stage}) {
     die "unknown stage $stage for ipp_cleanup.pl\n";
@@ -119,13 +119,24 @@
         # don't clean up unless the data needed to update is available
         # modes goto_purged and goto_scrubbed will remove files even if the config is non-existent
+	# goto_scrubbed now requires the config file to not exist.
         if ($mode eq "goto_cleaned") {
             my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base, $class_id);
-	    print STDERR "CHIP: CONFIG_FILE : $config_file\n";
-            if (!$config_file or ! -e $config_file) {
+
+#            if (!$config_file or ! -e $config_file) {
+	    unless ($ipprc->file_exists($config_file)) {
                 print STDERR "skipping cleanup for chipRun $stage_id $class_id "
-                    . " because config file is missing\n";
+                    . " because config file ($config_file) is missing\n";
                 $status = 0;
             }
         }
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base, $class_id);
+
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping scrubbed for chipRun $stage_id $class_id "
+		    . " because config file ($config_file) is present\n";
+		$status = 0;
+	    }
+	}
 
         if ($status) {
@@ -134,7 +145,7 @@
 
             # delete the temporary image datafiles
-            addFilename (\@files, "PPIMAGE.OUTPUT", $path_base, $class_id);
-            addFilename (\@files, "PPIMAGE.OUTPUT.MASK", $path_base, $class_id);
-            addFilename (\@files, "PPIMAGE.OUTPUT.VARIANCE", $path_base, $class_id);
+#            addFilename (\@files, "PPIMAGE.OUTPUT", $path_base, $class_id);
+#            addFilename (\@files, "PPIMAGE.OUTPUT.MASK", $path_base, $class_id);
+#            addFilename (\@files, "PPIMAGE.OUTPUT.VARIANCE", $path_base, $class_id);
             addFilename (\@files, "PPIMAGE.CHIP", $path_base, $class_id);
             addFilename (\@files, "PPIMAGE.CHIP.MASK", $path_base, $class_id);
@@ -144,9 +155,9 @@
                 addFilename (\@files, "PPIMAGE.OUTPUT.FPA1", $path_base, $class_id);
                 addFilename (\@files, "PPIMAGE.OUTPUT.FPA2", $path_base, $class_id);
-                addFilename (\@files, "PPIMAGE.BIN1", $path_base, $class_id);
-                addFilename (\@files, "PPIMAGE.BIN2", $path_base, $class_id);
+                addFilename (\@files, "PPIMAGE.BIN1", $path_base, $class_id);          # clean?
+                addFilename (\@files, "PPIMAGE.BIN2", $path_base, $class_id);          # clean?
                 addFilename (\@files, "PPIMAGE.JPEG1", $path_base, $class_id);
                 addFilename (\@files, "PPIMAGE.JPEG2", $path_base, $class_id);
-                addFilename (\@files, "PPIMAGE.STATS", $path_base, $class_id);
+                addFilename (\@files, "PPIMAGE.STATS", $path_base, $class_id);         #clean?
                 addFilename (\@files, "PPIMAGE.CONFIG", $path_base, $class_id);
             }
@@ -160,7 +171,12 @@
             if ($mode eq "goto_purged") {
                 $command .= " -topurgedimfile";
-            } else {
+            }
+	    elsif ($mode eq "goto_cleaned") {
                 $command .= " -tocleanedimfile";
             }
+	    elsif ($mode eq "goto_scrubbed") {
+		$command .= " -toscrubbedimfile";
+	    }
+
             $command .= " -dbname $dbname" if defined $dbname;
 
@@ -218,16 +234,25 @@
     my $status = 1;
     # don't clean up unless the data needed to update is available
+    # goto_scrubbed now requires the config file to not be present
     if ($mode eq "goto_cleaned") {
         my $config_file = $ipprc->filename("PSASTRO.CONFIG", $path_base);
-
-        if (!$config_file or ! -e $config_file) {
+	
+	unless ($ipprc->file_exists($config_file)) {
             print STDERR "skipping cleanup for camRun $stage_id because config file is missing\n";
             $status = 0;
         }
+    }
+    elsif ($mode eq "goto_scrubbed") {
+	my $config_file = $ipprc->filename("PSASTRO.CONFIG", $path_base);
+
+	if ($ipprc->file_exists($config_file)) {
+	    print STDERR "skipping cleanup for camRun $stage_id because config file ($config_file) is present\n";
+	    $status = 0;
+	}
     }
     if ($status) {
         my @files = ();
         # delete the temporary image datafiles
-        addFilename (\@files, "PSASTRO.OUTPUT", $path_base);
+#        addFilename (\@files, "PSASTRO.OUTPUT", $path_base);
         if ($mode eq "goto_purged") {
             # additional files to remove for 'purge' mode
@@ -246,5 +271,5 @@
 	}
         if ($mode eq "goto_scrubbed") {
-            $command = "$camtool -updaterun -cam_id $stage_id -set_state cleaned";
+            $command = "$camtool -updaterun -cam_id $stage_id -set_state scrubbed";
 	}
         if ($mode eq "goto_purged") {
@@ -305,5 +330,5 @@
             my $config_file = $ipprc->filename("PSWARP.CONFIG", $path_base, $skycell_id);
 
-            if (!$config_file or ! -e $config_file) {
+	    unless ($ipprc->file_exists($config_file)) {
                 print STDERR "skipping cleanup for warpRun $stage_id $skycell_id" .
                     " because config file is missing\n";
@@ -311,24 +336,36 @@
             }
         }
-        if ($status) {
-            # delete the temporary image datafiles
-            addFilename(\@files, "PSWARP.OUTPUT", $path_base, $skycell_id );
-            addFilename(\@files, "PSWARP.OUTPUT.MASK", $path_base, $skycell_id);
-            addFilename(\@files, "PSWARP.OUTPUT.VARIANCE", $path_base, $skycell_id);
-            addFilename(\@files, "PSWARP.OUTPUT.SOURCES", $path_base, $skycell_id);
-
-            if ($mode eq "goto_purged") {
-                # additional files to remove for 'purge' mode
-                addFilename(\@files, "PSWARP.BIN1", $path_base, $skycell_id );
-                addFilename(\@files, "PSWARP.BIN2", $path_base, $skycell_id );
-                addFilename(\@files, "SKYCELL.STATS", $path_base, $skycell_id );
-                # addFilename(\@files, "PSPHOT.PSF.SKY.SAVE", $path_base);
-
-                # XXX: do we want to delete these?
-                # addFilename(\@files, "TRACE.EXP", $path_base, $skycell_id);
-                # addFilename(\@files, "PSWARP.CONFIG", $path_base, $skycell_id);
-            }
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PSWARP.CONFIG", $path_base, $skycell_id);
+
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping scrubbed for warpRun $stage_id $skycell_id" .
+		    " because config file is present\n";
+		$status = 0;
+	    }
+	}
+	if ($status) {
+	    if ($skyfile->{quality} != 8007) {
+		my @files = ();
+		
+		# delete the temporary image datafiles
+		addFilename(\@files, "PSWARP.OUTPUT", $path_base, $skycell_id );
+		addFilename(\@files, "PSWARP.OUTPUT.MASK", $path_base, $skycell_id);
+		addFilename(\@files, "PSWARP.OUTPUT.VARIANCE", $path_base, $skycell_id);
+#            addFilename(\@files, "PSWARP.OUTPUT.SOURCES", $path_base, $skycell_id);
+		if ($mode eq "goto_purged") {
+		    # additional files to remove for 'purge' mode
+		    addFilename(\@files, "PSWARP.BIN1", $path_base, $skycell_id );
+		    addFilename(\@files, "PSWARP.BIN2", $path_base, $skycell_id );
+		    addFilename(\@files, "SKYCELL.STATS", $path_base, $skycell_id );
+		    # addFilename(\@files, "PSPHOT.PSF.SKY.SAVE", $path_base);
+		    
+		    # XXX: do we want to delete these?
+		    # addFilename(\@files, "TRACE.EXP", $path_base, $skycell_id);
+		    # addFilename(\@files, "PSWARP.CONFIG", $path_base, $skycell_id);
+		}
             # actual command to delete the files
-            $status = &delete_files (\@files);
+		$status = &delete_files (\@files);
+	    }
         }
 
@@ -337,7 +374,11 @@
             if ($mode eq "goto_purged") {
                 $command .= " -topurgedskyfile";
-            } else {
+            } 
+	    elsif ($mode eq "goto_cleaned") {
                 $command .= " -tocleanedskyfile";
             }
+	    elsif ($mode eq "goto_scrubbed") {
+		$command .= " -toscrubbedskyfile";
+	    }
             $command .= " -dbname $dbname" if defined $dbname;
 
@@ -395,15 +436,22 @@
 	if ($mode eq "goto_cleaned") {
 	    my $config_file = $ipprc->filename("PPSTACK.CONFIG", $path_base, $skycell_id);
-	    print STDERR "MY CONFIG FILE = $config_file\n";
-	    printf(STDERR "BOOLS: %d %d %d %s\n",!$config_file, ! -e $config_file, -e $config_file,$config_file);
-	    $config_file =~ s%^file://%%;
-	    if (!$config_file or ! -e $config_file) {
+
+	    unless ($ipprc->file_exists($config_file)) {
 		print STDERR "skipping cleanup for stackRun $stage_id $skycell_id" .
 		    " because config file is missing\n";
 		$status = 0;
 	    }
-	    $config_file = 'file://' . $config_file;
+	}
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPSTACK.CONFIG", $path_base, $skycell_id);
+
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping scrubbed for stackRun $stage_id $skycell_id" .
+		    " because config file is present\n";
+		$status = 0;
+	    }
 	}
 	if ($status) {
+	    my @files = ();
 	    # delete the temporary image datafiles
 	    addFilename(\@files, "PPSTACK.OUTPUT", $path_base, $skycell_id);
@@ -428,6 +476,10 @@
 	    if ($mode eq "goto_purged") {
 		$command .= " -updaterun -state purged";
-	    } else {
+	    } 
+	    elsif ($mode eq "goto_cleaned") {
 		$command .= " -updaterun -state cleaned";
+	    }
+	    elsif ($mode eq "goto_scrubbed") {
+		$command .= " -updaterun -state scrubbed";
 	    }
 	    $command .= " -dbname $dbname" if defined $dbname;
@@ -485,15 +537,22 @@
 	if ($mode eq "goto_cleaned") {
 	    my $config_file = $ipprc->filename("PPSUB.CONFIG", $path_base, $skycell_id);
-	    print STDERR "MY CONFIG FILE = $config_file\n";
-	    printf(STDERR "BOOLS: %d %d %d %s\n",!$config_file, ! -e $config_file, -e $config_file,$config_file);
-	    $config_file =~ s%^file://%%;
-	    if (!$config_file or ! -e $config_file) {
+
+	    unless ($ipprc->file_exists($config_file)) {
 		print STDERR "skipping cleanup for diffRun $stage_id $skycell_id" .
 		    " because config file ($config_file) is missing\n";
 		$status = 0;
 	    }
-	    $config_file = 'file://' . $config_file;
+	}
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPSUB.CONFIG", $path_base, $skycell_id);
+
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping scrubbed for diffRun $stage_id $skycell_id" .
+		    " because config file ($config_file) is present\n";
+		$status = 0;
+	    }
 	}
 	if ($status) {
+	    my @files = ();
 	    # delete the temporary image datafiles
 	    addFilename(\@files, "PPSUB.OUTPUT", $path_base, $skycell_id);
@@ -504,4 +563,5 @@
 	    addFilename(\@files, "PPSUB.INVERSE.MASK", $path_base, $skycell_id);
 	    addFilename(\@files, "PPSUB.INVERSE.VARIANCE", $path_base, $skycell_id);
+
 	    addFilename(\@files, "PPSUB.INPUT.CONV", $path_base, $skycell_id);
 	    addFilename(\@files, "PPSUB.INPUT.CONV.MASK", $path_base, $skycell_id);
@@ -523,16 +583,21 @@
 		
 	    }
-	    print STDERR "MY FILES: @files\n";
+#	    print STDERR "MY FILES: @files\n";
 	    $status = &delete_files(\@files);
 	}
-	print STDERR "MY STATUS: $status\n";
+#	print STDERR "MY STATUS: $status\n";
 	if ($status) {
 	    my $command = "$difftool -diff_id $stage_id";
-#	    my $command = "$difftool -diff_id $stage_id -skycell_id $skycell_id";
+
 	    if ($mode eq "goto_purged") {
 		$command .= " -updaterun -state purged";
-	    } else {
+	    }
+	    elsif ($mode eq "goto_cleaned") {
 		$command .= " -updaterun -state cleaned";
 	    }
+	    elsif ($mode eq "goto_scrubbed") {
+		$command .= " -updaterun -state scrubbed";
+	    }
+
 	    $command .= " -dbname $dbname" if defined $dbname;
 	    
@@ -545,5 +610,5 @@
 	} else {
 	    my $command = "$difftool -updaterun -diff_id $stage_id -state $error_state";
-#	    my $command = "$difftool -updaterun -diff_id $stage_id -skycell_id $skycell_id -state $error_state";
+
 	    $command .= " -dbname $dbname" if defined $dbname;
 	    
@@ -560,7 +625,1208 @@
 }
 if ($stage eq 'fake') {
-    die "ipp_cleanup.pl -stage fake not yet implemented. Probably will just mark database cleaned.\n";
+    print STDERR "This does not seem to work at present, as no files exist. Terminating quietly.\n";
+    exit(0);
+    die "--stage_id required for stage fake\n" if !$stage_id;
+    ### select the imfiles for this entry
+
+    # this stage uses 'chiptool'
+    my $faketool = can_run('faketool') or die "Can't find faketool";
+
+    # Get list of component imfiles
+    # XXX may need a different my_die for each stage
+    my $imfiles;                      # Array of component files
+    my $command = "$faketool -pendingcleanupimfile -fake_id $stage_id"; # Command to run
+    $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 faketool: $error_code", "fake", $stage_id, $error_code);
+    }
+
+    # if there are no fakeProcessedImfiles (@$stdout_buf == 0), the reset the state to 'new'
+    if (@$stdout_buf == 0)  {
+	my $command = "$faketool -fake_id $stage_id -updaterun -set_state new";
+	$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 faketool: $error_code", "fake", $stage_id, $error_code);
+	}
+	exit 0;
+    }
+
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", "fake", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    # extract the metadata for the files into a hash list
+    $imfiles = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", "fake", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    # loop over all of the imfiles, determine the path_base and class_id for each
+    foreach my $imfile (@$imfiles) {
+        my $class_id = $imfile->{class_id};
+        my $path_base = $imfile->{path_base};
+        my $status = 1;
+
+        # don't clean up unless the data needed to update is available
+        # modes goto_purged and goto_scrubbed will remove files even if the config is non-existent
+	# goto_scrubbed now requires the config file to not exist.
+        if ($mode eq "goto_cleaned") {
+            my $config_file = $ipprc->filename("PPSIM.CONFIG", $path_base, $class_id);
+
+	    unless ($ipprc->file_exists($config_file)) {
+                print STDERR "skipping cleanup for fakeRun $stage_id $class_id "
+                    . " because config file is missing\n";
+                $status = 0;
+            }
+        }
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPSIM.CONFIG", $path_base, $class_id);
+
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping scrubbed for fakeRun $stage_id $class_id "
+		    . " because config file is present\n";
+		$status = 0;
+	    }
+	}
+
+        if ($status) {
+            # array of actual filenames to delete
+            my @files = ();
+
+            # delete the temporary image datafiles
+            addFilename (\@files, "PPSIM.OUTPUT.MEF", $path_base, $class_id);
+            addFilename (\@files, "PPSIM.OUTPUT.SPL", $path_base, $class_id);
+            addFilename (\@files, "PPSIM.FAKE.CHIP", $path_base, $class_id);
+            addFilename (\@files, "PPSIM.FORCE.CHIP", $path_base, $class_id);
+            if ($mode eq "goto_purged") {
+                # additional files to remove for 'purge' mode
+		addFilename (\@files, "PPSIM.SOURCES", $path_base, $class_id);
+		addFilename (\@files, "PPSIM.FAKE.SOURCES", $path_base, $class_id);
+		addFilename (\@files, "PPSIM.FORCE.SOURCES", $path_base, $class_id);
+            }
+
+            # actual command to delete the files
+            $status = &delete_files (\@files);
+        }
+
+        if ($status)  {
+            my $command = "$faketool -fake_id $stage_id -class_id $class_id";
+            if ($mode eq "goto_purged") {
+                $command .= " -topurgedimfile";
+            }
+	    elsif ($mode eq "goto_cleaned") {
+                $command .= " -tocleanedimfile";
+            }
+	    elsif ($mode eq "goto_scrubbed") {
+		$command .= " -toscrubbedimfile";
+	    }
+
+            $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 faketool: $error_code", "fake", $stage_id, $error_code);
+            }
+        } else {
+
+	    # if an error happens for one chip, the chipRun will stay in goto_*, but the chips will go to error_* (matching the goto_*)
+	    my $command = "$faketool -updateprocessedimfile -fake_id $stage_id -class_id $class_id -set_state $error_state";
+	    $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 faketool: $error_code", "fake", $stage_id, $error_code);
+            }
+        }
+    }
+    exit 0;
+
 } 
-# fake : faketool : -pendingcleanupimfile (loop over imfiles)
+# Detrend stages
+if ($stage eq "detrend.process.imfile") {
+
+    die "--stage_id required for stage detrend.process.imfile\n" if !$stage_id;
+    ### select the imfiles for this entry
+
+    # this stage uses 'dettool'
+    my $dettool = can_run('dettool') or die "Can't find chiptool";
+
+    # Get list of component imfiles
+    # XXX may need a different my_die for each stage
+    my $imfiles;                      # Array of component files
+    my $command = "$dettool -pendingcleanup_processedimfile -det_id $stage_id"; # Command to run
+    $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 dettool: $error_code", "detrend.process.imfile", $stage_id, $error_code);
+    }
+
+    # if there are no detProcessedImfiles (@$stdout_buf == 0), the reset the state to 'new'
+    if (@$stdout_buf == 0)  {
+	exit 0; # Silently exit if there's nothing to do.  I don't know how we'd ever get here, but let's be safe.
+    }
+
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    # extract the metadata for the files into a hash list
+    $imfiles = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    # loop over all of the imfiles, determine the path_base and class_id for each
+    foreach my $imfile (@$imfiles) {
+	my $exp_id   = $imfile->{exp_id};
+        my $class_id = $imfile->{class_id};
+        my $path_base = $imfile->{path_base};
+        my $status = 1;
+
+        # don't clean up unless the data needed to update is available
+        # modes goto_purged and goto_scrubbed will remove files even if the config is non-existent
+	# goto_scrubbed now requires the config file to not exist.
+	
+	# Possibly not the correct config file, but simtest doesn't leave any around to check.
+        if ($mode eq "goto_cleaned") {
+            my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base, $class_id);
+
+	    unless ($ipprc->file_exists($config_file)) {
+                print STDERR "skipping cleanup for detrend.process.imfile $stage_id $class_id "
+                    . " because config file is missing\n";
+                $status = 0;
+            }
+        }
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base, $class_id);
+
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping scrubbed for detrend.process.imfile $stage_id $class_id "
+		    . " because config file is present\n";
+		$status = 0;
+	    }
+	}
+
+        if ($status) {
+            # array of actual filenames to delete
+            my @files = ();
+
+            # delete the temporary image datafiles
+            addFilename (\@files, "PPIMAGE.OUTPUT", $path_base, $class_id);
+            addFilename (\@files, "PPIMAGE.OUTPUT.MASK", $path_base, $class_id);
+            addFilename (\@files, "PPIMAGE.OUTPUT.VARIANCE", $path_base, $class_id);
+            if ($mode eq "goto_purged") {
+                # additional files to remove for 'purge' mode
+		addFilename (\@files, "PPIMAGE.BIN1", $path_base, $class_id);
+		addFilename (\@files, "PPIMAGE.BIN2", $path_base, $class_id);
+                addFilename (\@files, "PPIMAGE.STATS", $path_base, $class_id);
+            }
+
+            # actual command to delete the files
+            $status = &delete_files (\@files);
+        }
+
+        if ($status)  {
+            my $command = "$dettool -det_id $stage_id -exp_id $exp_id -class_id $class_id -updateprocessedimfile";
+            if ($mode eq "goto_purged") {
+                $command .= " -data_state purged";
+            }
+	    elsif ($mode eq "goto_cleaned") {
+                $command .= " -data_state cleaned";
+            }
+	    elsif ($mode eq "goto_scrubbed") {
+		$command .= " -data_state scrubbed";
+	    }
+
+            $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+            }
+
+        } else {
+
+	    # if an error happens for one chip, the chipRun will stay in goto_*, but the chips will go to error_* (matching the goto_*)
+	    my $command = "$dettool -updateprocessedimfile -det_id $stage_id -exp_id $exp_id -class_id $class_id -data_state $error_state";
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+            }
+        }
+    }
+
+    # Check to see if we can mark the whole detRunSummary object as cleaned.
+
+    $command = "$dettool -pendingcleanup_detrunsummary -det_id $stage_id"; 
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $command, verbose => $verbose);
+    unless ($success) {
+	$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	&my_die("Unable to perform dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+    }
+    if (@$stdout_buf != 0) {
+	$metadata = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	my $exps = parse_md_list($metadata) or
+	    &my_die("Unable to parse metadata list", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	
+	foreach my $exp (@$exps) {
+	    my $iteration = $exp->{iteration};
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+	    }
+	}
+    }
+    
+    exit 0;
+}
+if ($stage eq "detrend.process.exp") {
+    die "--stage_id required for stage $stage\n" if !$stage_id;
+    # this stage uses 'dettool'
+    my $dettool = can_run('dettool') or die "Can't find dettool";
+
+    # Get list of component imfiles
+    # XXX may need a different my_die for each stage
+    my $exps;                      # Array of component files
+    my $command = "$dettool -pendingcleanup_processedexp -det_id $stage_id"; # Command to run
+    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+    }
+    
+    if (@$stdout_buf == 0) {
+	exit 0; #silently abort. I need to fix this for propers
+    }
+
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    $exps = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+
+    foreach my $exp (@$exps) {
+	my $path_base = $exp->{path_base};
+	my $exp_id    = $exp->{exp_id};
+
+	my $status = 1;
+	# don't clean up unless the data needed to update is available
+	# goto_scrubbed now requires the config file to not be present
+	if ($mode eq "goto_cleaned") {
+	    my $config_file = $ipprc->filename("PSIMAGE.CONFIG", $path_base);
+	    
+	    unless ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping cleanup for $stage $stage_id because config file is missing\n";
+		$status = 0;
+	    }
+	}
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PSIMAGE.CONFIG", $path_base);
+	    
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping cleanup for $stage $stage_id because config file ($config_file) is present\n";
+		$status = 0;
+	    }
+	}
+	if ($status) {
+	    my @files = ();
+	    # delete the temporary image datafiles
+	    # I can't find anything to put here
+	    if ($mode eq "goto_purged") {
+		# additional files to remove for 'purge' mode
+		addFilename (\@files, "PPIMAGE.JPEG1", $path_base);
+		addFilename (\@files, "PPIMAGE.JPEG2", $path_base);
+	    }
+	    # actual command to delete the files
+	    $status = &delete_files (\@files);
+	}
+	
+	if ($status)  {
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updateprocessedexp -det_id $stage_id -exp_id $exp_id -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updateprocessedexp -det_id $stage_id -exp_id $exp_id -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updateprocessedexp -det_id $stage_id -exp_id $exp_id -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	} else {
+	    # since 'camera' has only a single imfile, we can just update the run
+	    my $command = "$dettool -updateprocessedexp -det_id $stage_id -exp_id $exp_id -data_state $error_state";
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	    exit $PS_EXIT_UNKNOWN_ERROR;
+	}
+    }
+    # Check to see if we can mark the whole detRunSummary object as cleaned.
+
+    $command = "$dettool -pendingcleanup_detrunsummary -det_id $stage_id"; 
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $command, verbose => $verbose);
+    unless ($success) {
+	$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	&my_die("Unable to perform dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+    }
+    if (@$stdout_buf != 0) {
+	$metadata = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	$exps = parse_md_list($metadata) or
+	    &my_die("Unable to parse metadata list", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	
+	foreach my $exp (@$exps) {
+	    my $iteration = $exp->{iteration};
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+	    }
+	}
+    }
+
+    exit 0;
+}
+if ($stage eq "detrend.stack.imfile") {
+    
+    die "--stage_id required for stage $stage\n" if !$stage_id;
+
+    # this stage uses 'dettool'
+    my $dettool = can_run('dettool') or die "Can't find dettool";
+
+    # Get list of component imfiles
+    my $stacks;                  # Array reference of component files
+    my $command = "$dettool -pendingcleanup_stacked -det_id $stage_id"; # Command to run
+    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+    }
+    my $metadata = $mdcParser->parse(join "", @{ $stdout_buf }) or 
+	&my_die("Unable to parse metadata config doc", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    $stacks = parse_md_list($metadata) or 
+	&my_die("Unable to parse metadata list", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+    
+    my @files = ();
+    foreach my $stack (@{ $stacks }) {
+	# detStackedImfile does not have a path_base column.  This is inconvenient, as it means we need to calculate it.
+	my $path_base = $stack->{uri};
+	my $iteration = $stack->{iteration};
+	my $class_id  = $stack->{class_id};
+
+	$path_base =~ s/\.fits$//; # That should do it?
+
+	my $status = 1;
+
+# 	if ($mode eq "goto_cleaned") {
+# 	    my $config_file = $ipprc->filename("PPMERGE.CONFIG", $path_base, $stage_id);
+
+# 	    $config_file =~ s%^file://%%;
+# 	    if (!$config_file or ! -e $config_file) {
+# 		print STDERR "skipping cleanup for $stage $stage_id $path_base" .
+# 		    " because config file is missing\n";
+# 		$status = 0;
+# 	    }
+# 	    $config_file = 'file://' . $config_file;
+# 	}
+# 	elsif ($mode eq "goto_scrubbed") {
+# 	    my $config_file = $ipprc->filename("PPMERGE.CONFIG", $path_base, $stage_id);
+# 	    $config_file =~ s%^file://%%;
+# 	    if ($config_file and -e $config_file) {
+# 		print STDERR "skipping scrubbed for $stage $stage_id $path_base" .
+# 		    " because config file is present\n";
+# 		$status = 0;
+# 	    }
+# 	}
+
+	if ($status) {
+	    my @files = ();
+	    # delete the temporary image datafiles
+	    # There's no convenient way to get the detrend type, so I'm queueing all of them for deletion.
+	    # I understand that they all point to the same filename right now, but that may not be true in
+	    # the future.
+	    addFilename(\@files, "PPMERGE.OUTPUT.MASK", $path_base, $stage_id);
+	    addFilename(\@files, "PPMERGE.OUTPUT.BIAS", $path_base, $stage_id);
+	    addFilename(\@files, "PPMERGE.OUTPUT.DARK", $path_base, $stage_id);
+	    addFilename(\@files, "PPMERGE.OUTPUT.SHUTTER", $path_base, $stage_id);
+	    addFilename(\@files, "PPMERGE.OUTPUT.FLAT", $path_base, $stage_id);
+	    addFilename(\@files, "PPMERGE.OUTPUT.FRINGE", $path_base, $stage_id);
+	    
+
+	    addFilename(\@files, "PPMERGE.OUTPUT.SIGMA", $path_base, $stage_id);
+	    addFilename(\@files, "PPMERGE.OUTPUT.COUNT", $path_base, $stage_id);
+
+	    if ($mode eq "goto_purged") {
+		# additional files to remove for 'purge' mode
+#		addFilename(\@files, "PPMERGE.OUTPUT", $path_base, $stage_id);
+	    }
+
+	    $status = &delete_files(\@files);
+	}
+
+	if ($status) {
+	    my $command = "$dettool -det_id $stage_id -iteration $iteration -class_id $class_id";
+	    if ($mode eq "goto_purged") {
+		$command .= " -updatestacked -data_state purged";
+	    } 
+	    elsif ($mode eq "goto_cleaned") {
+		$command .= " -updatestacked -data_state cleaned";
+	    }
+	    elsif ($mode eq "goto_scrubbed") {
+		$command .= " -updatestacked -data_state scrubbed";
+	    }
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	} else {
+	    my $command = "$dettool -updatestacked  -det_id $stage_id -iteration $iteration -class_id $class_id -data_state $error_state";
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	    exit $PS_EXIT_UNKNOWN_ERROR;
+	}
+    }
+    # Check to see if we can mark the whole detRunSummary object as cleaned.
+
+    $command = "$dettool -pendingcleanup_detrunsummary -det_id $stage_id"; 
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $command, verbose => $verbose);
+    unless ($success) {
+	$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	&my_die("Unable to perform dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+    }
+    if (@$stdout_buf != 0) {
+	$metadata = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	my $exps = parse_md_list($metadata) or
+	    &my_die("Unable to parse metadata list", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	
+	foreach my $exp (@$exps) {
+	    my $iteration = $exp->{iteration};
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+	    }
+	}
+    }
+    exit 0;
+}
+if ($stage eq "detrend.normstat.imfile") {
+    print STDERR "I'm not convinced there's anything to clean up from stage $stage\n";
+    die "--stage_id required for stage $stage\n" if !$stage_id;
+    # this stage uses 'camtool'
+    my $dettool = can_run('dettool') or die "Can't find dettool";
+
+    my $command = "$dettool -pendingcleanup_normalizedstat -det_id $stage_id"; # Command to run
+    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+    }
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    my $exps = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    foreach my $exp (@$exps) {
+#	my $path_base = $exp->{path_base};
+	my $iteration = $exp->{iteration};
+	my $class_id  = $exp->{class_id};
+
+	my $status = 1;
+	if ($status)  {
+	    my $command = "$dettool -updatenormalizedstat -det_id $stage_id -iteration $iteration -class_id $class_id";
+	    if ($mode eq "goto_cleaned") {
+		$command .= " -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command .= " -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command .= " -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	} else {
+	    my $command = "$dettool -updatenormalizedstat -det_id $stage_id -iteration $iteration -class_id $class_id -data_state $error_state";
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	    exit $PS_EXIT_UNKNOWN_ERROR;
+	}
+    }
+    # Check to see if we can mark the whole detRunSummary object as cleaned.
+
+    $command = "$dettool -pendingcleanup_detrunsummary -det_id $stage_id"; 
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $command, verbose => $verbose);
+    unless ($success) {
+	$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	&my_die("Unable to perform dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+    }
+    if (@$stdout_buf != 0) {
+	$metadata = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	$exps = parse_md_list($metadata) or
+	    &my_die("Unable to parse metadata list", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	
+	foreach my $exp (@$exps) {
+	    my $iteration = $exp->{iteration};
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+	    }
+	}
+    }
+
+    exit 0;
+
+}
+if ($stage eq "detrend.norm.imfile") {
+    die "--stage_id required for stage $stage\n" if !$stage_id;
+    # this stage uses 'dettool'
+    my $dettool = can_run('dettool') or die "Can't find dettool";
+
+    # Get list of component imfiles
+    # XXX may need a different my_die for each stage
+    my $exps;                      # Array of component files
+    my $command = "$dettool -pendingcleanup_normalizedimfile -det_id $stage_id"; # Command to run
+    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+    }
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    $exps = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    foreach my $exp (@$exps) {
+	my $path_base = $exp->{path_base};
+	my $iteration = $exp->{iteration};
+	my $class_id  = $exp->{class_id};
+
+	my $status = 1;
+	# don't clean up unless the data needed to update is available
+	# goto_scrubbed now requires the config file to not be present
+	if ($mode eq "goto_cleaned") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base);
+	    
+	    unless ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping cleanup for $stage $stage_id because config file is missing\n";
+		$status = 0;
+	    }
+	}
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base);
+	    
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping cleanup for $stage $stage_id because config file ($config_file) is present\n";
+		$status = 0;
+	    }
+	}
+	if ($status) {
+	    my @files = ();
+
+	    if ($mode eq "goto_purged") {
+		# additional files to remove for 'purge' mode
+		addFilename (\@files, "PPIMAGE.OUTPUT.FPA1", $path_base);
+		addFilename (\@files, "PPIMAGE.OUTPUT.FPA2", $path_base);
+
+		addFilename (\@files, "PPIMAGE.OUTPUT", $path_base);
+		addFilename (\@files, "PPIMAGE.STATS", $path_base);
+	    }
+	    # actual command to delete the files
+	    $status = &delete_files (\@files);
+	}
+	
+	if ($status)  {
+	    my $command = "$dettool -updatenormalizedimfile -det_id $stage_id -iteration $iteration -class_id $class_id";
+	    if ($mode eq "goto_cleaned") {
+		$command .= " -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command .= " -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command .= " -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	} else {
+	    my $command = "$dettool -updatenormalizedimfile -det_id $stage_id -iteration $iteration -class_id $class_id -data_state $error_state";
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	    exit $PS_EXIT_UNKNOWN_ERROR;
+	}
+    }
+    # Check to see if we can mark the whole detRunSummary object as cleaned.
+
+    $command = "$dettool -pendingcleanup_detrunsummary -det_id $stage_id"; 
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $command, verbose => $verbose);
+    unless ($success) {
+	$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	&my_die("Unable to perform dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+    }
+    if (@$stdout_buf != 0) {
+	$metadata = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	$exps = parse_md_list($metadata) or
+	    &my_die("Unable to parse metadata list", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	
+	foreach my $exp (@$exps) {
+	    my $iteration = $exp->{iteration};
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+	    }
+	}
+    }
+
+    exit 0;
+}
+if ($stage eq "detrend.norm.exp") {
+    die "--stage_id required for stage $stage\n" if !$stage_id;
+    # this stage uses 'dettool'
+    my $dettool = can_run('dettool') or die "Can't find dettool";
+
+    # Get list of component imfiles
+    # XXX may need a different my_die for each stage
+    my $exps;                      # Array of component files
+    my $command = "$dettool -pendingcleanup_normalizedexp -det_id $stage_id"; # Command to run
+    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+    }
+
+    if (@$stdout_buf == 0) {
+	exit 0;
+    }
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    $exps = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    foreach my $exp (@$exps) {
+	my $exp_id = $exp->{exp_id};
+	my $iteration = $exp->{iteration};
+	my $path_base = $exp->{path_base};
+
+	my $status = 1;
+	# don't clean up unless the data needed to update is available
+	# goto_scrubbed now requires the config file to not be present
+	if ($mode eq "goto_cleaned") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base);
+	    
+	    unless ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping cleanup for $stage $stage_id because config file is missing\n";
+		$status = 0;
+	    }
+	}
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base);
+	    
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping cleanup for $stage $stage_id because config file ($config_file) is present\n";
+		$status = 0;
+	    }
+	}
+	if ($status) {
+	    my @files = ();
+	    # delete the temporary image datafiles
+	    if ($mode eq "goto_purged") {
+		# additional files to remove for 'purge' mode
+		addFilename (\@files, "PPIMAGE.JPEG1", $path_base);
+		addFilename (\@files, "PPIMAGE.JPEG2", $path_base);
+	    }
+	    # actual command to delete the files
+	    $status = &delete_files (\@files);
+	}
+	
+	if ($status)  {
+	    my $command = "$dettool -updatenormalizedexp -det_id $stage_id -iteration $iteration";
+	    if ($mode eq "goto_cleaned") {
+		$command .= " -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command .= " -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command .= " -data_state purged";
+	    }
+	    $command .= " -dbname $dbname" if defined $dbname;
+	    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+		run(command => $command, verbose => $verbose);
+	    unless ($success) {
+		print STDERR " residexp had an issue setting the state:? $success $error_code\n";
+		$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+		&my_die("Unable to perform dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	} else {
+	    my $command = "$dettool -updatenormalizedexp -det_id $stage_id -exp_id $exp_id -iteration $iteration -data_state $error_state";
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	    exit $PS_EXIT_UNKNOWN_ERROR;
+	}
+    }
+    # Check to see if we can mark the whole detRunSummary object as cleaned.
+
+    $command = "$dettool -pendingcleanup_detrunsummary -det_id $stage_id"; 
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $command, verbose => $verbose);
+    unless ($success) {
+	$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	&my_die("Unable to perform dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+    }
+    if (@$stdout_buf != 0) {
+	$metadata = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	$exps = parse_md_list($metadata) or
+	    &my_die("Unable to parse metadata list", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	
+	foreach my $exp (@$exps) {
+	    my $iteration = $exp->{iteration};
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+	    }
+	}
+    }
+    exit 0;
+}
+if ($stage eq "detrend.resid.imfile") {
+
+    die "--stage_id required for stage $stage\n" if !$stage_id;
+    ### select the imfiles for this entry
+
+    # this stage uses 'dettool'
+    my $dettool = can_run('dettool') or die "Can't find dettool";
+
+    # Get list of component imfiles
+    # XXX may need a different my_die for each stage
+    my $imfiles;                      # Array of component files
+    my $command = "$dettool -pendingcleanup_residimfile -det_id $stage_id"; # Command to run
+    $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 dettool: $error_code", "detrend.process.imfile", $stage_id, $error_code);
+    }
+
+    if (@$stdout_buf == 0) {
+	exit 0;
+    }
+
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    # extract the metadata for the files into a hash list
+    $imfiles = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    # loop over all of the imfiles, determine the path_base and class_id for each
+    foreach my $imfile (@$imfiles) {
+        my $class_id = $imfile->{class_id};
+	my $iteration = $imfile->{iteration};
+	my $exp_id = $imfile->{exp_id};
+        my $path_base = $imfile->{path_base};
+        my $status = 1;
+
+        # don't clean up unless the data needed to update is available
+        # modes goto_purged and goto_scrubbed will remove files even if the config is non-existent
+	# goto_scrubbed now requires the config file to not exist.
+	
+	# Possibly not the correct config file, but simtest doesn't leave any around to check.
+        if ($mode eq "goto_cleaned") {
+            my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base, $class_id);
+
+	    unless ($ipprc->file_exists($config_file)) {
+                print STDERR "skipping cleanup for $stage $stage_id $class_id "
+                    . " because config file is missing\n";
+                $status = 0;
+            }
+        }
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base, $class_id);
+
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping scrubbed for $stage $stage_id $class_id "
+		    . " because config file is present\n";
+		$status = 0;
+	    }
+	}
+
+        if ($status) {
+            # array of actual filenames to delete
+            my @files = ();
+
+            # delete the temporary image datafiles
+            addFilename (\@files, "PPIMAGE.OUTPUT", $path_base, $class_id);
+            if ($mode eq "goto_purged") {
+                # additional files to remove for 'purge' mode
+		addFilename (\@files, "PPIMAGE.BIN1", $path_base, $class_id);
+		addFilename (\@files, "PPIMAGE.BIN2", $path_base, $class_id);
+                addFilename (\@files, "PPIMAGE.STATS", $path_base, $class_id);
+            }
+
+            # actual command to delete the files
+            $status = &delete_files (\@files);
+        }
+
+        if ($status)  {
+            my $command = "$dettool -updateresidimfile -det_id $stage_id -exp_id $exp_id -iteration $iteration -class_id $class_id";
+            if ($mode eq "goto_purged") {
+                $command .= " -data_state purged";
+            }
+	    elsif ($mode eq "goto_cleaned") {
+                $command .= " -data_state cleaned";
+            }
+	    elsif ($mode eq "goto_scrubbed") {
+		$command .= " -data_state scrubbed";
+	    }
+
+            $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+            }
+        } else {
+	    my $command = "$dettool -updateresidimfile -det_id $stage_id -exp_id $exp_id -iteration $iteration -class_id $class_id -data_state $error_state";
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+            }
+        }
+    }
+    # Check to see if we can mark the whole detRunSummary object as cleaned.
+
+    $command = "$dettool -pendingcleanup_detrunsummary -det_id $stage_id"; 
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $command, verbose => $verbose);
+    unless ($success) {
+	$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	&my_die("Unable to perform dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+    }
+    if (@$stdout_buf != 0) {
+	$metadata = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	my $exps = parse_md_list($metadata) or
+	    &my_die("Unable to parse metadata list", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	
+	foreach my $exp (@$exps) {
+	    my $iteration = $exp->{iteration};
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+	    }
+	}
+    }
+
+    exit 0;
+}
+if ($stage eq "detrend.resid.exp") {
+    die "--stage_id required for stage $stage\n" if !$stage_id;
+    # this stage uses 'camtool'
+    my $dettool = can_run('dettool') or die "Can't find dettool";
+
+    # Get list of component imfiles
+    # XXX may need a different my_die for each stage
+    my $exps;                      # Array of component files
+    my $command = "$dettool -pendingcleanup_residexp -det_id $stage_id"; # Command to run
+    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+    }
+    # This is a hack to bomb out until I can diagnose why pantasks wants to keep running this
+    if (@$stdout_buf == 0) {
+	exit 0;
+    }
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    $exps = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", "$stage", $stage_id, $PS_EXIT_PROG_ERROR);
+
+    foreach my $exp (@$exps) {
+	my $exp_id = $exp->{exp_id};
+	my $iteration = $exp->{iteration};
+	my $path_base = $exp->{path_base};
+#	my $class_id  = $exp->{class_id} 
+	my $status = 1;
+	# don't clean up unless the data needed to update is available
+	# goto_scrubbed now requires the config file to not be present
+	if ($mode eq "goto_cleaned") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base);
+	    
+	    unless ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping cleanup for $stage $stage_id because config file is missing\n";
+		$status = 0;
+	    }
+	}
+	elsif ($mode eq "goto_scrubbed") {
+	    my $config_file = $ipprc->filename("PPIMAGE.CONFIG", $path_base);
+	    
+	    if ($ipprc->file_exists($config_file)) {
+		print STDERR "skipping cleanup for $stage $stage_id because config file ($config_file) is present\n";
+		$status = 0;
+	    }
+	}
+	if ($status) {
+	    my @files = ();
+	    # delete the temporary image datafiles
+	    if ($mode eq "goto_purged") {
+		# additional files to remove for 'purge' mode
+                addFilename (\@files, "PPIMAGE.JPEG1", $path_base);#, $class_id);
+                addFilename (\@files, "PPIMAGE.JPEG2", $path_base);#, $class_id);
+	    }
+	    # actual command to delete the files
+	    $status = &delete_files (\@files);
+	}
+	
+	if ($status)  {
+	    my $command = "$dettool -updateresidexp -det_id $stage_id -exp_id $exp_id -iteration $iteration";
+	    if ($mode eq "goto_cleaned") {
+		$command .= " -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command .= " -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command .= " -data_state purged";
+	    }
+	    $command .= " -dbname $dbname" if defined $dbname;
+	    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+		run(command => $command, verbose => $verbose);
+	    unless ($success) {
+		print STDERR " residexp had an issue setting the state:? $success $error_code\n";
+		$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+		&my_die("Unable to perform dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	} else {
+	    my $command = "$dettool -updateresidexp -det_id $stage_id -exp_id $exp_id -iteration $iteration -data_state $error_state";
+	    $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 dettool: $error_code", "$stage", $stage_id, $error_code);
+	    }
+	    exit $PS_EXIT_UNKNOWN_ERROR;
+	}
+    }
+    # Check to see if we can mark the whole detRunSummary object as cleaned.
+
+    $command = "$dettool -pendingcleanup_detrunsummary -det_id $stage_id"; 
+    $command .= " -dbname $dbname" if defined $dbname;
+    ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) = run(command => $command, verbose => $verbose);
+    unless ($success) {
+	$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	&my_die("Unable to perform dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+    }
+    if (@$stdout_buf != 0) {
+	$metadata = $mdcParser->parse(join "", @$stdout_buf) or
+	    &my_die("Unable to parse metadata config doc", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	$exps = parse_md_list($metadata) or
+	    &my_die("Unable to parse metadata list", "$stage (detRunSummary)", $stage_id, $PS_EXIT_PROG_ERROR);
+	
+	foreach my $exp (@$exps) {
+	    my $iteration = $exp->{iteration};
+	    my $command;
+	    if ($mode eq "goto_cleaned") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state cleaned";
+	    }
+	    if ($mode eq "goto_scrubbed") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state scrubbed";
+	    }
+	    if ($mode eq "goto_purged") {
+		$command = "$dettool -updatedetrunsummary -det_id $stage_id -iteration $iteration -data_state purged";
+	    }
+	    $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 dettool: $error_code", "$stage (detRunSummary)", $stage_id, $error_code);
+	    }
+	}
+    }
+    exit 0;
+}
+
 
 die "ipp_cleanup.pl -stage $stage not yet implemented\n";
@@ -569,10 +1835,37 @@
 {
     my $files = shift; # reference to a list of files to unlink
+#     my $test_verbose = 1;
+    
+#     if ($test_verbose == 1) {
+# 	open(TMPLOG,">>/tmp/czw.cleanup.log");
+# 	flock(TMPLOG,2);
+#     }
 
     # this script is, of course, very dangerous.
     foreach my $file (@$files) {
-        print STDERR "unlinking $file\n";
+        print STDERR "unlinking $stage $stage_id $file";
+	unless ($ipprc->file_exists($file)) {
+	    print STDERR "\t File not found\n";
+	}
+	else {
+	    print STDERR "\n";
+	}
+
+# 	if ($test_verbose == 1) {
+# 	    print TMPLOG "$stage $stage_id $file";
+	    
+# 	    else {
+# 		print TMPLOG "\n";
+# 	    }
+# 	}
+
         $ipprc->file_delete($file);
     }
+
+#     if ($test_verbose == 1) {
+# 	flock(TMPLOG,8);
+# 	close(TMPLOG);
+#     }
+
     return 1;
 }
Index: branches/eam_branches/20090820/ippScripts/scripts/ipp_image_path.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/ipp_image_path.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/ipp_image_path.pl	(revision 25766)
@@ -108,7 +108,7 @@
             # remove the leading "file://" if present
             $path =~ s/^file\:\/\///;
+            $nfiles++;
+            print "$path\n";
         }
-        $nfiles++;
-        print "$path\n";
     }
     if (!$nfiles) {
Index: branches/eam_branches/20090820/ippScripts/scripts/magic_destreak_revert.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/magic_destreak_revert.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/magic_destreak_revert.pl	(revision 25766)
@@ -191,7 +191,7 @@
 }
 
-revert_files($image, $mask, $weight, $sources, $astrom, $bimage, $bmask, $bweight, $bsources, $bastrom);
-
-if ($stage eq "diff") {
+revert_files($replace, $image, $mask, $weight, $sources, $astrom, $bimage, $bmask, $bweight, $bsources, $bastrom);
+
+if ($stage eq "diff" and $inverse) {
     my $name = "PPSUB.INVERSE";
     $image  = $ipprc->filename($name, $path_base);
@@ -203,10 +203,10 @@
     $bweight = $ipprc->filename("$name.VARIANCE", $backup_path_base);
     $bsources = $ipprc->filename("$name.SOURCES", $backup_path_base);
-    revert_files($image, $mask, $weight, $sources, undef, $bimage, $bmask, $bweight, $bsources, undef);
+    revert_files($replace, $image, $mask, $weight, $sources, undef, $bimage, $bmask, $bweight, $bsources, undef);
 }
 
 # now revert the row in the database
 {
-    my $command = "$magicdstool -revertdestreakedfile";
+    my $command = "$magicdstool -revertdestreakedfile -i_am_sure";
     $command   .= " -magic_ds_id $magic_ds_id";
     $command   .= " -component $component";
@@ -231,4 +231,7 @@
 
 sub revert_files {
+    my $replace = shift;
+    return if !$replace;
+
     my $image = shift;
     my $mask = shift;
Index: branches/eam_branches/20090820/ippScripts/scripts/publish_file.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/publish_file.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/publish_file.pl	(revision 25766)
@@ -39,6 +39,6 @@
 
 # Parse the command-line arguments
-my ( $pub_id, $camera, $stage, $stage_id, $format, $product, $workdir );
-my ( $dbname, $verbose, $no_update, $save_temps, $redirect );
+my ( $pub_id, $camera, $stage, $stage_id, $fileset, $format, $product, $workdir );
+my ( $dbname, $verbose, $no_update, $no_op, $save_temps, $redirect );
 
 GetOptions(
@@ -48,8 +48,10 @@
     'stage_id=s'        => \$stage_id,    # Stage identifier
     'product=s'         => \$product,     # Datastore product name
+    'fileset=s'         => \$fileset,     # Fileset name
     'workdir=s'         => \$workdir,     # Working directory
     'dbname=s'          => \$dbname,    # Database name
     'verbose'           => \$verbose,   # Print to stdout
     'no-update'         => \$no_update, # Don't update the database?
+    'no-op'             => \$no_op, # Don't do any operations
     'save-temps'        => \$save_temps, # Save temporary files?
     'redirect-output'   => \$redirect,   # Redirect output to log file?
@@ -77,23 +79,9 @@
 my $mdcParser = PS::IPP::Metadata::Config->new;
 
-
-# Retrieve file name of interest
-my %files;                      # Input filenames
-my %zp;                         # Zero points
-my %exp_id;                     # Exposure identifiers
-my %exp_name;                   # Exposure names
-my %direction;                  # Direction of subtraction
-{
-    my $command;                # Command to run
-
-    if ($stage eq 'diff') {
-        $command =  "difftool -diffskyfile -diff_id $stage_id";
-    } elsif ($stage eq 'camera') {
-        $command =  "camtool -processedexp -cam_id $stage_id";
-    } else {
-        &my_die( "Unrecognised stage: $stage", $pub_id, $PS_EXIT_CONFIG_ERROR );
-    }
+my ($dsFile, $dsFileName) = tempfile("/tmp/publish.$pub_id.ds.XXXX", UNLINK => !$save_temps );
+
+if ($stage eq 'camera') {
+    my $command =  "camtool -processedexp -cam_id $stage_id";
     $command .= " -dbname $dbname" if defined $dbname;
-
     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
         run(command => $command, verbose => $verbose);
@@ -106,4 +94,31 @@
         &my_die("Unable to parse metadata list", $pub_id, $PS_EXIT_PROG_ERROR);
 
+    &my_die("More than one entry for cam_id $stage_id", $pub_id, $PS_EXIT_PROG_ERROR) if scalar @$components > 1;
+
+    my $comp = $$components[0]; # Component of interest
+    my $path_base = $comp->{path_base}; # Base name for file
+    my $file = $ipprc->filename( "PSASTRO.OUTPUT", $path_base );
+    $file = $ipprc->file_resolve($file);
+    my $cam_id = $comp->{cam_id};
+    my $name = "cam_$cam_id";
+    print $dsFile "$file|||$product|$name|\n";
+} elsif ($stage eq 'diff') {
+    my $command =  "difftool -diffskyfile -diff_id $stage_id";
+    $command .= " -dbname $dbname" if defined $dbname;
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    &my_die( "Unable to retrieve filename", $pub_id, $PS_EXIT_SYS_ERROR) unless $success;
+
+    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config", $pub_id, $PS_EXIT_PROG_ERROR);
+
+    my $components = parse_md_list($metadata) or
+        &my_die("Unable to parse metadata list", $pub_id, $PS_EXIT_PROG_ERROR);
+
+    my ($mopsPositiveFile, $mopsPositiveFileName) = tempfile("/tmp/publish.$pub_id.mops.pos.XXXX", UNLINK => !$save_temps ) if $product eq 'IPP-MOPS';
+    my ($mopsNegativeFile, $mopsNegativeFileName) = tempfile("/tmp/publish.$pub_id.mops.neg.XXXX", UNLINK => !$save_temps ) if $product eq 'IPP-MOPS';
+
+    my %positive;               # Data for positive diff detections
+    my %negative;               # Data for negative diff detections
     foreach my $comp ( @$components ) {
         my $path_base = $comp->{path_base}; # Base name for file
@@ -112,69 +127,78 @@
         (carp "Bad zpt_obs or exp_time for component" and next) if not defined $comp->{zpt_obs} or not defined $comp->{exp_time};
         my $zp = $comp->{zpt_obs} + 2.5 * log($comp->{exp_time}) / log(10);
-
-        if ($stage eq 'diff') {
-            my $skycell_id = $comp->{skycell_id};
-
-            # Positive direction
-            $files{"$skycell_id.pos"} = $ipprc->filename( "PPSUB.OUTPUT.SOURCES", $path_base );
-            $zp{"$skycell_id.pos"} = $zp;
-            $exp_id{"$skycell_id.pos"} = $comp->{exp_id_1};
-            $exp_name{"$skycell_id.pos"} = $comp->{exp_name_1};
-            $direction{"$skycell_id.pos"} = 1;
-
-            # Negative direction
-            if (defined $comp->{bothways} and $comp->{bothways}) {
-                $files{"$skycell_id.neg"} = $ipprc->filename( "PPSUB.INVERSE.SOURCES", $path_base );
-                $zp{"$skycell_id.neg"} = $zp;
-                $exp_id{"$skycell_id.neg"} = $comp->{exp_id_2};
-                $direction{"$skycell_id.neg"} = 0;
-                $exp_name{"$skycell_id.neg"} = $comp->{exp_name_2};
+        my $astrom = sqrt($comp->{sigma_ra_1}**2 + $comp->{sigma_dec_1}**2);
+
+        my $skycell_id = $comp->{skycell_id};
+        my $filename = $ipprc->filename( "PPSUB.OUTPUT.SOURCES", $path_base );
+        $filename = $ipprc->file_resolve($filename);
+
+        my $data = { zp => $zp,
+                     zp_err => $comp->{zpt_stdev},
+                     astrom => sqrt($comp->{sigma_ra_1}**2 + $comp->{sigma_dec_1}**2),
+                     exp_name => $comp->{exp_name_1},
+                     exp_id => $comp->{exp_id_1},
+                     chip_id => $comp->{chip_id_1},
+                     cam_id => $comp->{cam_id_1},
+                     fake_id => $comp->{fake_id_1},
+                     warp_id => $comp->{warp1},
+                     diff_id => $comp->{diff_id},
+                     direction => 1,
+        };
+
+        diff_check(\%positive, $data, "positive");
+
+        if ($product eq 'IPP-MOPS') {
+            print $mopsPositiveFile "$filename\n";
+        } else {
+            print $dsFile "$filename|||$product|${skycell_id}.pos|\n";
+        }
+
+        # Negative direction
+        if (defined $comp->{bothways} and $comp->{bothways}) {
+            my $filename = $ipprc->filename( "PPSUB.INVERSE.SOURCES", $path_base );
+            $filename = $ipprc->file_resolve($filename);
+
+            my $data = { zp => $zp,
+                         zp_err => $comp->{zpt_stdev},
+                         astrom => sqrt($comp->{sigma_ra_2}**2 + $comp->{sigma_dec_2}**2),
+                         exp_name => $comp->{exp_name_2},
+                         exp_id => $comp->{exp_id_2},
+                         chip_id => $comp->{chip_id_2},
+                         cam_id => $comp->{cam_id_2},
+                         fake_id => $comp->{fake_id_2},
+                         warp_id => $comp->{warp2},
+                         diff_id => $comp->{diff_id},
+                         direction => 0,
+            };
+
+            diff_check(\%negative, $data, "negative");
+
+            if ($product eq 'IPP-MOPS') {
+                print $mopsNegativeFile "$filename\n";
+            } else {
+                print $dsFile "$filename|||$product|${skycell_id}.neg|\n";
             }
-
-        } elsif ($stage eq 'camera') {
-            my $cam_id = $comp->{cam_id};
-            $files{$cam_id} = $ipprc->filename( "PSASTRO.OUTPUT", $path_base );
-            $zp{$cam_id} = $zp;
-            $exp_id{$cam_id} = $comp->{exp_id};
-            $exp_name{$cam_id} = $comp->{exp_name};
-            $direction{$cam_id} = 1;
         }
     }
-}
-
-# Prepare for data store input
-my ($listFile, $listFileName) = tempfile("/tmp/publish.$pub_id.list.XXXX", UNLINK => !$save_temps );
-
-# Process each file
-foreach my $comp ( keys %files ) {
-    my $file = $ipprc->file_resolve( $files{$comp} ) or
-        &my_die("Unable to resolve file $files{$comp}", $pub_id, $PS_EXIT_SYS_ERROR);
-    my_die("Unable to find file $file", $pub_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $file );
-
-    my $zp = $zp{$comp};
-    my $exp_id = $exp_id{$comp};
-    my $exp_name = $exp_name{$comp};
-    my $direction = $direction{$comp};
-    if ($product eq "IPP-MOPS") {
-        my $outuri = "$outroot.$comp.fits";
-        my $out = $ipprc->file_resolve( $outuri, 'create' ) or
-            &my_die( "Unable to resolve output file $outuri", $pub_id, $PS_EXIT_SYS_ERROR);
-
-        my $command = "$ppMops $file $zp $exp_id $exp_name $direction $out";
-        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-            run(command => $command, verbose => $verbose);
-        &my_die( "Unable to translate $file", $pub_id, $PS_EXIT_SYS_ERROR) unless $success;
-        &my_die( "Unable to find translated file $out", $pub_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $out );
-        $file = $out;
+
+    close $mopsPositiveFile;
+    close $mopsNegativeFile;
+
+    if ($product eq 'IPP-MOPS') {
+        if (scalar keys %positive > 0) {
+            my $output = mops_combine(\%positive, "$outroot.pos.mops", $mopsPositiveFileName);
+            print $dsFile "$output|||$product|positive|\n";
+        }
+        if (scalar keys %negative > 0) {
+            my $output = mops_combine(\%negative, "$outroot.neg.mops", $mopsNegativeFileName);
+            print $dsFile "$output|||$product|negative|\n";
+        }
     }
-
-    # format: filename|filesize|md5sum|filetype|
-    # note: since we omit filesize and md5sum, dsreg will calculate them
-    print $listFile "$file|||$product|$comp|\n";
-}
-
+}
+
+close $dsFile;
 
 unless ($no_update) {
-    my $command = "$dsreg --add $stage.$stage_id --copy --abspath --product $product --type $product --list $listFileName";
+    my $command = "$dsreg --add $stage.$stage_id --copy --abspath --product $product --type $product --list $dsFileName";
 
     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
@@ -185,4 +209,7 @@
 unless ($no_update) {
     my $command = "$pubtool -add -pub_id $pub_id -path_base $outroot";
+    $command .= (" -dtime_script " . ((DateTime->now->mjd - $mjd_start) * 86400));
+    $command .= " -hostname $host" if defined $host;
+
     $command .= " -dbname $dbname" if defined $dbname;
 
@@ -195,4 +222,73 @@
 
 ### Pau.
+
+# Check inputs for a diff
+sub diff_check
+{
+    my $data = shift;           # Data hash
+    my $comp = shift;           # Component data
+    my $name = shift;           # Name of component
+
+    $data->{zp} = $comp->{zp} unless defined $data->{zp};
+    $data->{zp_err} = $comp->{zp_err} unless defined $data->{zp_err};
+    $data->{astrom} = $comp->{astrom} unless defined $data->{astrom};
+    $data->{exp_name} = $comp->{exp_name} unless defined $data->{exp_name};
+    $data->{exp_id} = $comp->{exp_id} unless defined $data->{exp_id};
+    $data->{chip_id} = $comp->{chip_id} unless defined $data->{chip_id};
+    $data->{cam_id} = $comp->{cam_id} unless defined $data->{cam_id};
+    $data->{fake_id} = $comp->{fake_id} unless defined $data->{fake_id};
+    $data->{warp_id} = $comp->{warp_id} unless defined $data->{warp_id};
+    $data->{diff_id} = $comp->{diff_id} unless defined $data->{diff_id};
+    $data->{direction} = $comp->{direction} unless defined $data->{direction};
+
+    &my_die("zp value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{zp} and $comp->{zp} != $data->{zp};
+    &my_die("zp_err value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{zp_err} and $comp->{zp_err} != $data->{zp_err};
+    &my_die("astrom value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{astrom} and $comp->{astrom} != $data->{astrom};
+    &my_die("exp_name value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{exp_name} and $comp->{exp_name} ne $data->{exp_name};
+    &my_die("exp_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{exp_id} and $comp->{exp_id} != $data->{exp_id};
+    &my_die("chip_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{chip_id} and $comp->{chip_id} != $data->{chip_id};
+    &my_die("cam_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{cam_id} and $comp->{cam_id} != $data->{cam_id};
+    &my_die("fake_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{fake_id} and $comp->{fake_id} != $data->{fake_id};
+    &my_die("warp_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{warp_id} and $comp->{warp_id} != $data->{warp_id};
+    &my_die("diff_id value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{diff_id} and $comp->{diff_id} != $data->{diff_id};
+    &my_die("direction value for $name doesn't match", $pub_id, $PS_EXIT_SYS_ERROR) if defined $data->{direction} and $comp->{direction} != $data->{direction};
+
+    return 1;
+}
+
+# Combine multiple files for MOPS
+sub mops_combine
+{
+    my $data = shift;           # Data
+    my $output = shift;         # Output name
+    my $input = shift;          # Input name
+
+    $output = $ipprc->file_resolve( $output, 'create' ) or
+        &my_die( "Unable to resolve output file $output", $pub_id, $PS_EXIT_SYS_ERROR);
+
+    my $command = "$ppMops $input $output";
+    $command .= " -exp_name " . $data->{exp_name} if defined $data->{exp_name};
+    $command .= " -exp_id " . $data->{exp_id} if defined $data->{exp_id};
+    $command .= " -chip_id " . $data->{chip_id} if defined $data->{chip_id};
+    $command .= " -cam_id " . $data->{cam_id} if defined $data->{cam_id};
+    $command .= " -fake_id " . $data->{fake_id} if defined $data->{fake_id};
+    $command .= " -warp_id " . $data->{warp_id} if defined $data->{warp_id};
+    $command .= " -diff_id " . $data->{diff_id} if defined $data->{diff_id};
+    $command .= " -inverse" if defined $data->{direction} and $data->{direction} == 0;
+    $command .= " -zp " . $data->{zp} if defined $data->{zp};
+    $command .= " -zp_error " . $data->{zp_err} if defined $data->{zp_err};
+    $command .= " -astrom_rms " . $data->{astrom} if defined $data->{astrom};
+
+    unless ($no_op) {
+        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+            run(command => $command, verbose => $verbose);
+        &my_die( "Unable to translate", $pub_id, $PS_EXIT_SYS_ERROR) unless $success;
+        &my_die( "Unable to find translated file $output", $pub_id, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists( $output );
+    } else {
+        print "Not running: $command\n";
+    }
+
+    return $output;
+}
 
 
@@ -210,4 +306,6 @@
         $command .= " -pub_id $pub_id";
         $command .= " -path_base $outroot";
+        $command .= (" -dtime_script " . ((DateTime->now->mjd - $mjd_start) * 86400));
+        $command .= " -hostname $host" if defined $host;
         $command .= " -fault $fault";
         $command .= " -dbname $dbname" if defined $dbname;
Index: branches/eam_branches/20090820/ippScripts/scripts/rcserver_checkstatus.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/rcserver_checkstatus.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/rcserver_checkstatus.pl	(revision 25766)
@@ -40,10 +40,9 @@
 
 # Parse the command-line arguments
-my ($dest_id, $prod_id, $status_uri, $last_fileset, $limit);
+my ($dest_id, $status_uri, $last_fileset, $limit);
 my ($dbname, $save_temps, $verbose, $no_update, $logfile);
 
 GetOptions(
            'dest_id=s'      => \$dest_id,    # destination identifier
-           'prod_id=s'      => \$prod_id,    # product identifier
            'status_uri=s'   => \$status_uri, # uri for the desination's status data store product
            'last_fileset=s' => \$last_fileset, # name of last fileset seen on this datastore
Index: branches/eam_branches/20090820/ippScripts/scripts/register_imfile.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/register_imfile.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/register_imfile.pl	(revision 25766)
@@ -33,6 +33,7 @@
 my $ppStats = can_run( 'ppStats' ) or (warn "Can't find ppStats" and $missing_tools = 1);
 my $ppStatsFromMetadata = can_run( 'ppStatsFromMetadata' ) or (warn "Can't find ppStatsFromMetadata" and $missing_tools = 1);
-
-my ($cache, $exp_id, $tmp_class_id, $tmp_exp_name, $uri, $dbname, $verbose, $no_update, $no_op, $logfile);
+my $ppConfigDump = can_run( 'ppConfigDump' ) or (warn "Can't find ppConfigDump" and $missing_tools = 1);
+
+my ($cache, $exp_id, $tmp_class_id, $tmp_exp_name, $uri, $bytes, $md5sum, $dbname, $verbose, $no_update, $no_op, $logfile);
 GetOptions(
     'caches'           => \$cache,
@@ -41,4 +42,6 @@
     'tmp_exp_name|n=s' => \$tmp_exp_name,
     'uri|u=s'          => \$uri,
+    'bytes=s'          => \$bytes,
+    'md5sum=s'         => \$md5sum,
     'dbname|d=s'       => \$dbname,    # Database name
     'verbose'          => \$verbose,   # Print to stdout
@@ -106,4 +109,45 @@
     chomp $out2;
     $cmdflags = $out2;
+
+    # Manually parse the burntool_state entry.
+    my $burntoolState = 0;
+    my $isGPC1 = 0;
+    my $burntoolStateGood = 0;
+    foreach my $line (split /\n/, $out1) {
+	if ($line =~ /FPA.BURNTOOL.APPLIED/) {
+	    $line =~ s/^\s+//;
+	    $burntoolState = (split /\s+/, $line)[2];
+	}
+	if ($line =~ /FPA.CAMERA/) {
+	    $line =~ s/^\s+//;
+	    if ((split /\s+/, $line)[2] eq 'GPC1') {
+		$isGPC1 = 1;
+	    }
+	}
+    }
+    if ($isGPC1 != 1) {
+	$burntoolState = 0; # If it's not GPC1, you shouldn't have run burntool.
+    }
+    elsif (($isGPC1 == 1) && ($burntoolState == 1)) {
+	my $ppConfigDump_cmd = "$ppConfigDump -camera GPC1 -dump-camera -";
+	my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+	    IPC::Cmd::run(command => $ppConfigDump_cmd, verbose => $verbose);
+	unless ($success) {
+	    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+	    warn ("Unable to perform ppConfigDump");
+	    exit($error_code);
+	}
+
+	# This is ugly, but doing a full parse for one entry is a bit wasteful.
+	foreach my $line (split /\n/, (join "", @$stdout_buf)) {
+	    if ($line =~ /BURNTOOL.STATE.GOOD/) {
+		$line =~ s/^\s+//;
+		$burntoolStateGood = (split /\s+/, $line)[2];
+		last;
+	    }
+	}
+	$burntoolState = $burntoolStateGood; # Positive because this has the header table.
+    }
+    $cmdflags .= " -burntool_state $burntoolState ";
 }
 
@@ -123,4 +167,6 @@
 $command .= " -tmp_class_id $tmp_class_id"; # the original class_id supplied by the user, replace by ppStats CLASS.ID
 $command .= " -uri $uri ";
+$command .= " -bytes $bytes" if $bytes;
+$command .= " -md5sum $md5sum" if $md5sum and ($md5sum ne 'NULL');
 $command .= " -hostname $host" if defined $host;
 $command .= " -dbname $dbname" if defined $dbname;
Index: branches/eam_branches/20090820/ippScripts/scripts/stack_skycell.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/stack_skycell.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/stack_skycell.pl	(revision 25766)
@@ -65,4 +65,6 @@
 
 my $ipprc = PS::IPP::Config->new() or my_die( "Unable to set up", $stack_id, $PS_EXIT_CONFIG_ERROR ); # IPP configuration
+$| = 1;
+print "I've set up: $stack_id\n";
 
 # XXX camera is not known here; cannot use filerules...
@@ -107,4 +109,6 @@
 &my_die("Stack list contains less than two elements", $stack_id, $PS_EXIT_SYS_ERROR) unless
     scalar @$files >= 2;
+
+print "I've loaded my inputs: $stack_id\n";
 
 # Parse the list of input files to get the tesselation, skycell identifiers and camera
@@ -137,4 +141,6 @@
 $ipprc->define_camera($camera);
 
+print "I've configured everything: $stack_id\n";
+
 # Recipes to use based on reduction class
 $reduction = 'DEFAULT' unless defined $reduction;
@@ -146,4 +152,19 @@
 }
 
+my $recipe;
+{
+    my $command = "$ppConfigDump -camera $camera -recipe PPSTACK $recipe_ppStack -dump-recipe PPSTACK -";
+    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 ppConfigDump: $error_code", $stack_id, $error_code);
+    }
+    $recipe = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", $stack_id, $PS_EXIT_PROG_ERROR);
+}
+my $convolve = metadataLookupBool($recipe, 'CONVOLVE'); # Convolve inputs?
+
+
 # Generate MDC file with the inputs
 my $tess_base = basename($tess_id);
@@ -160,5 +181,5 @@
     my $mask = $ipprc->filename( "PSWARP.OUTPUT.MASK", $file->{path_base} ); # Mask name
     my $weight = $ipprc->filename( "PSWARP.OUTPUT.VARIANCE", $file->{path_base} ); # Weight name
-    my $psf = $ipprc->filename( "PSPHOT.PSF.SKY.SAVE", $file->{path_base} ); # PSF name
+    my $psf = $convolve ? $ipprc->filename( "PSPHOT.PSF.SKY.SAVE", $file->{path_base} ) : undef; # PSF name
     my $sources = $ipprc->filename("PSWARP.OUTPUT.SOURCES", $file->{path_base}); # Sources name
 
@@ -166,5 +187,5 @@
     &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) unless $ipprc->file_exists( $psf );
+    &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 );
 
@@ -172,12 +193,11 @@
     print $listFile "\tMASK\tSTR\t" . $mask . "\n";
     print $listFile "\tVARIANCE\tSTR\t" . $weight . "\n";
-    print $listFile "\tPSF\tSTR\t" . $psf . "\n";
+    print $listFile "\tPSF\tSTR\t" . $psf . "\n" if $convolve;
     print $listFile "\tSOURCES\tSTR\t" . $sources . "\n";
 
-    ### XXX NEED TO UPDATE THESE appropriately
-    print $listFile "\tWEIGHTING\tF32\t" . 1.0 . "\n";
-
     print $listFile "END\n\n";
 }
+
+print "I've checked everything: $stack_id\n";
 
 # Get the output filenames
@@ -200,4 +220,5 @@
 
 my $cmdflags;
+
 
 # Perform stacking
@@ -266,4 +287,5 @@
     }
 
+    print "I've stacked $listName: $stack_id\n";
 }
 
@@ -298,4 +320,6 @@
 }
 
+print "I've updated teh database: $stack_id\n";
+
 
 my $my_die_called = 0;
@@ -340,20 +364,11 @@
 
     print "Ensuring temporary images are deleted.\n";
-    my $command = "$ppConfigDump -camera $camera -recipe PPSTACK $recipe_ppStack -dump-recipe PPSTACK -";
-    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 ppConfigDump: $error_code", $stack_id, $error_code);
-    }
-    my $md = $mdcParser->parse(join "", @$stdout_buf) or
-        &my_die("Unable to parse metadata config doc", $stack_id, $PS_EXIT_PROG_ERROR);
-
-    my $temp_delete = metadataLookupBool($md, 'TEMP.DELETE'); # Delete temporary files?
+
+    my $temp_delete = defined($recipe) and metadataLookupBool($recipe, 'TEMP.DELETE'); # Delete temp files?
     if ($temp_delete) {
-        my $temp_dir = metadataLookupStr($md, 'TEMP.DIR'); # Directory with temporary files
-        my $temp_image = metadataLookupStr($md, 'TEMP.IMAGE'); # Suffix for image
-        my $temp_mask = metadataLookupStr($md, 'TEMP.MASK'); # Suffix for mask
-        my $temp_weight = metadataLookupStr($md, 'TEMP.VARIANCE'); # Suffix for weight
+        my $temp_dir = metadataLookupStr($recipe, 'TEMP.DIR'); # Directory with temporary files
+        my $temp_image = metadataLookupStr($recipe, 'TEMP.IMAGE'); # Suffix for image
+        my $temp_mask = metadataLookupStr($recipe, 'TEMP.MASK'); # Suffix for mask
+        my $temp_weight = metadataLookupStr($recipe, 'TEMP.VARIANCE'); # Suffix for weight
         my $temp_root = basename($outroot); # Root name for temporary files
 
@@ -372,4 +387,5 @@
 }
 
+print "I've reached the end of processing with a code of $?: $stack_id\n";
 
 END {
Index: branches/eam_branches/20090820/ippScripts/scripts/summit_copy.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/summit_copy.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/summit_copy.pl	(revision 25766)
@@ -12,4 +12,5 @@
 use Sys::Hostname;
 
+use Digest::MD5::File qw( file_md5_hex );
 use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
 use Pod::Usage qw( pod2usage );
@@ -21,5 +22,5 @@
 
 # Parse the command-line arguments
-my ( $uri, $filename, $compress, $bytes, $md5, $nebulous, $exp_name, $inst, $telescope, $class, $class_id, $end_stage, $workdir,
+my ( $uri, $filename, $compress, $bytes, $md5, $nebulous, $exp_name, $inst, $telescope, $class, $class_id, 
      $dbname, $verbose, $no_update, $no_op, $timeout, $copies );
 GetOptions(
@@ -35,6 +36,4 @@
        'class=s'        => \$class,     # Class level
        'class_id=s'     => \$class_id,  # Class identifier
-       'end_stage=s'    => \$end_stage, # end of processing
-       'workdir=s'      => \$workdir,   # workdir
        'dbname=s'       => \$dbname,    # Database name
        'verbose'        => \$verbose,   # Print to stdout
@@ -62,8 +61,12 @@
 my $pztool = can_run('pztool')
     or (warn "Can't find pztool" and $missing_tools = 1);
+my $neblocate = can_run('neb-locate')
+    or (warn "Can't find neb-locate" and $missing_tools = 1);
 if ($missing_tools) {
     warn("Can't find required tools.");
     exit($PS_EXIT_CONFIG_ERROR);
 }
+
+my $ipprc = PS::IPP::Config->new();
 
 # dsget command
@@ -97,4 +100,11 @@
 }
 
+#
+# Find all instances of the new file and make sure they have the
+# same checksum and size.
+# if so pass the results to pztool to the results in pzDownloadImfile.
+# uncomment this to turn on
+my ($new_bytes, $new_md5) = check_instances($filename, $nebulous, $compress);
+
 # command to update database
 $command  = "$pztool -copydone";
@@ -106,8 +116,10 @@
 $command .= " -class_id $class_id";
 $command .= " -uri $filename";
-# $command .= " -workdir $workdir";
 $command .= " -hostname $host";
-# $command .= " -end_stage $end_stage" if defined $end_stage;
 $command .= " -dbname $dbname" if defined $dbname;
+
+# XXX: TODO: see above. Don't do this until pztool and the DB have
+# been updated
+$command .= " -md5sum $new_md5 -bytes $new_bytes";
 
 # update the database
@@ -122,4 +134,86 @@
 } else {
     print "skipping command: $command\n";
+}
+
+sub get_file_params
+{
+    my $filename = shift;
+
+    my $size = -s $filename;
+    my $md5 = file_md5_hex($filename);
+
+    return ($size, $md5);
+}
+
+sub check_instances {
+    my $filename = shift;
+    my $nebulous = shift;
+    my $compress = shift;
+
+    my @instances;
+    if ($nebulous) {
+        my $command = "$neblocate --path --all $filename";
+        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 neb-locate: $error_code",
+                $exp_name,
+                $inst,
+                $telescope,
+                $class,
+                $class_id,
+                $uri,
+                $error_code
+            );
+        }
+        @instances = split "\n", join "", @$stdout_buf;
+    } else {
+        if (!defined $ipprc) {
+            # we don't usually need this so defer instantaiating it
+            $ipprc = PS::IPP::Config->new();
+        }
+        my $resolved = $ipprc->file_resolve($filename);
+        if ($resolved) {
+            $instances[0] = $resolved;
+        }
+    }
+    if (! scalar @instances) {
+        my_die("no instances",
+                    $exp_name,
+                    $inst,
+                    $telescope,
+                    $class,
+                    $class_id,
+                    $uri,
+                    $PS_EXIT_UNKNOWN_ERROR
+            );
+    }
+
+    my ($new_bytes, $new_md5) = get_file_params($instances[0]);
+        
+    for (my $i = 1; $i < scalar @instances; $i++) {
+        my ($b, $m) = get_file_params($instances[$i]);
+        my $error = "";
+        if ($b ne $new_bytes) {
+            $error = "size of $instances[$i] does not match $instances[0]";
+        } elsif ($m ne $new_md5) {
+            $error = "md5sum of $instances[$i] does not match $instances[0]";
+        }
+        if ($error) {
+            my_die($error,
+                    $exp_name,
+                    $inst,
+                    $telescope,
+                    $class,
+                    $class_id,
+                    $uri,
+                    $PS_EXIT_DATA_ERROR
+            );
+        }
+    }
+
+    return ($new_bytes, $new_md5);
+    
 }
 
Index: branches/eam_branches/20090820/ippScripts/scripts/warp_skycell.pl
===================================================================
--- branches/eam_branches/20090820/ippScripts/scripts/warp_skycell.pl	(revision 25206)
+++ branches/eam_branches/20090820/ippScripts/scripts/warp_skycell.pl	(revision 25766)
@@ -183,4 +183,18 @@
 close $astromFile;
 
+# We need the recipe to determine if we care whether the PSF is generated or not
+my $recipe;
+{
+    my $command = "$ppConfigDump -camera $camera -dump-recipe PSWARP -recipe PSWARP $recipe_pswarp -";
+    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 ppConfigDump: $error_code", $warp_id, $skycell_id, $tess_dir, $PS_EXIT_SYS_ERROR);
+    }
+    $recipe = $mdcParser->parse(join "", @$stdout_buf) or
+        &my_die("Unable to parse metadata config doc", $warp_id, $skycell_id, $tess_dir, $PS_EXIT_SYS_ERROR);
+}
+
 
 # Run pswarp
@@ -201,5 +215,4 @@
     $command .= " -F SOURCE.PLOT.APRESID SOURCE.PLOT.SKY.APRESID";
     $command .= " -recipe PSWARP $recipe_pswarp";
-    $command .= " -psf";        # Turn on PSF determination
     $command .= " -tracedest $traceDest -log $logDest";
     $command .= " -threads $threads" if defined $threads;
@@ -253,5 +266,5 @@
             &my_die("Couldn't find expected output file: $outputWeight", $warp_id, $skycell_id, $tess_dir, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($outputWeight);
             &my_die("Couldn't find expected output file: $outputSources", $warp_id, $skycell_id, $tess_dir, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($outputSources);
-            &my_die("Couldn't find expected output file: $outputPSF", $warp_id, $skycell_id, $tess_dir, $PS_EXIT_SYS_ERROR) unless $ipprc->file_exists($outputPSF);
+            &my_die("Couldn't find expected output file: $outputPSF", $warp_id, $skycell_id, $tess_dir, $PS_EXIT_SYS_ERROR) if metadataLookupBool($recipe, 'PSF') and not $ipprc->file_exists($outputPSF);
         }
 
Index: branches/eam_branches/20090820/ippTasks/Makefile.am
===================================================================
--- branches/eam_branches/20090820/ippTasks/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/Makefile.am	(revision 25766)
@@ -13,7 +13,9 @@
 	chip.pro \
 	camera.pro \
+	addstar.pro \
 	fake.pro \
 	warp.pro \
 	magic.pro \
+	destreak.pro \
 	diff.pro \
 	stack.pro \
@@ -25,5 +27,6 @@
 	pstamp.pro \
 	receive.pro \
-	publish.pro
+	publish.pro \
+	science.cleanup.pro
 
 other_files = \
Index: branches/eam_branches/20090820/ippTasks/addstar.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/addstar.pro	(revision 25766)
+++ branches/eam_branches/20090820/ippTasks/addstar.pro	(revision 25766)
@@ -0,0 +1,233 @@
+## addstar.pro : globals and support macros : -*- sh -*-
+## this file contains the tasks for running the addstar analysis stage
+## these tasks use the book addPendingExp
+
+# test for required global variables
+check.globals
+
+book init addPendingExp
+
+macro addstar.status
+  book listbook addPendingExp
+end
+
+macro addstar.reset
+  book init addPendingExp
+end
+
+macro addstar.on
+  task addstar.exp.load
+    active true
+  end
+  task addstar.exp.run
+    active true
+  end
+  task addstar.revert
+    active true
+  end
+end
+
+macro addstar.off
+  task addstar.exp.load
+    active false
+  end
+  task addstar.exp.run
+    active false
+  end
+  task addstar.revert
+    active false
+  end
+end
+
+# this variable will cycle through the known database names
+$addstar_DB = 0
+$addstar_revert_DB = 0
+
+# select images ready for addstar analysis
+# new entries are added to addPendingExp
+# skip already-present entries
+task	       addstar.exp.load
+  host         local
+
+  periods      -poll $LOADPOLL
+  periods      -exec $LOADEXEC
+  periods      -timeout 30
+  npending     1
+
+  stdout NULL
+  stderr $LOGDIR/addstar.exp.log
+
+  task.exec
+    if ($LABEL:n == 0) break
+    $run = addtool -pendingexp
+    if ($DB:n == 0)
+      option DEFAULT
+    else
+      # save the DB name for the exit tasks
+      option $DB:$addstar_DB
+      $run = $run -dbname $DB:$addstar_DB
+      $addstar_DB ++
+      if ($addstar_DB >= $DB:n) set addstar_DB = 0
+    end
+    add_poll_args run
+    add_poll_labels run
+    command $run
+  end
+
+  # success
+  task.exit    0
+    # convert 'stdout' to book format
+    ipptool2book stdout addPendingExp -key add_id -uniq -setword dbname $options:0 -setword pantaskState INIT
+    if ($VERBOSE > 2)
+      book listbook addPendingExp
+    end
+
+    # delete existing entries in the appropriate pantaskStates
+    process_cleanup addPendingExp
+  end
+
+  # default exit status
+  task.exit    default
+    showcommand failure
+  end
+
+  task.exit    crash
+    showcommand crash
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
+
+# run the addstar script on pending exposures
+task	       addstar.exp.run
+  periods      -poll $RUNPOLL
+  periods      -exec $RUNEXEC
+  periods      -timeout 10
+
+  task.exec
+    book npages addPendingExp -var N
+    if ($N == 0) break
+    if ($NETWORK == 0) break
+    
+    # look for new images in addPendingExp (pantaskState == INIT)
+    book getpage addPendingExp 0 -var pageName -key pantaskState INIT
+    if ("$pageName" == "NULL") break
+
+    book setword addPendingExp $pageName pantaskState RUN
+    book getword addPendingExp $pageName camera -var CAMERA
+    book getword addPendingExp $pageName exp_tag -var EXP_TAG
+    book getword addPendingExp $pageName add_id -var ADD_ID
+    book getword addPendingExp $pageName cam_id -var CAM_ID
+    book getword addPendingExp $pageName workdir -var WORKDIR_TEMPLATE
+    book getword addPendingExp $pageName dvodb  -var DVODB
+    book getword addPendingExp $pageName dbname -var DBNAME
+    book getword addPendingExp $pageName reduction -var REDUCTION
+    book getword addPendingExp $pageName state -var RUN_STATE
+
+    # specify choice of remote host based on camera and chip (class_id)
+    set.host.for.camera $CAMERA FPA
+
+    # set the WORKDIR variable
+    set.workdir.by.camera $CAMERA FPA $WORKDIR_TEMPLATE $default_host WORKDIR
+
+    # notes on how this works:
+    # -- raw workdir examples:
+    # file://data/@HOST@.0/gpc1/20080130
+    # neb:///@HOST@-vol0/gpc1/20080130 (need to supply volname?, or are we re-defining this each time?)
+    # -- out workdir examples:
+    # file://data/ipp004.0/gpc1/20080130
+    # neb:///ipp004-vol0/gpc1/20080130
+
+    ## generate outroot specific to this exposure (& chip)
+    sprintf outroot "%s/%s/%s.add.%s" $WORKDIR $EXP_TAG $EXP_TAG $ADD_ID
+    sprintf camroot "%s/%s/%s.cm.%s" $WORKDIR $EXP_TAG $EXP_TAG $CAM_ID
+
+    stdout $LOGDIR/addstar.exp.log
+    stderr $LOGDIR/addstar.exp.log
+
+    $run = addstar_run.pl --exp_tag $EXP_TAG --add_id $ADD_ID --camera $CAMERA --outroot $outroot --camroot $camroot --redirect-output --run-state $RUN_STATE
+    if ("$REDUCTION" != "NULL")
+      $run = $run --reduction $REDUCTION
+    end
+    if ("$DVODB" != "NULL")
+      $run = $run --dvodb $DVODB
+    end
+    add_standard_args run
+
+    # save the pageName for future reference below
+    options $pageName
+
+    # create the command line
+    if ($VERBOSE > 1)
+      echo command $run
+    end
+    command $run
+  end
+
+  # success
+  task.exit default
+    process_exit addPendingExp $options:0 $JOB_STATUS
+  end
+
+  # locked list
+  task.exit    crash
+    showcommand crash
+    echo "hostname: $JOB_HOSTNAME"
+    book setword addPendingExp $options:0 pantaskState CRASH
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+    book setword addPendingExp $options:0 pantaskState TIMEOUT
+  end
+end
+
+task addstar.revert
+  host         local
+
+  periods      -poll 5.0
+  periods      -exec 60.0
+  periods      -timeout 120.0
+  npending     1
+
+  stdout NULL
+  stderr $LOGDIR/revert.log
+
+  task.exec
+    if ($LABEL:n == 0) break
+    $run = addtool -revertprocessedexp
+    if ($DB:n == 0)
+      option DEFAULT
+    else
+      # save the DB name for the exit tasks
+      option $DB:$addstar_revert_DB
+      $run = $run -dbname $DB:$addstar_revert_DB
+      $addstar_revert_DB ++
+      if ($addstar_revert_DB >= $DB:n) set addstar_revert_DB = 0
+    end
+    add_poll_labels run
+    command $run
+  end
+
+  # success
+  task.exit    0
+  end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+  end
+
+  task.exit    crash
+    showcommand crash
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
Index: branches/eam_branches/20090820/ippTasks/camera.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/camera.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/camera.pro	(revision 25766)
@@ -23,4 +23,7 @@
     active true
   end
+  task camera.revert
+    active true
+  end
 end
 
@@ -30,4 +33,7 @@
   end
   task camera.exp.run
+    active false
+  end
+  task camera.revert
     active false
   end
Index: branches/eam_branches/20090820/ippTasks/chip.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/chip.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/chip.pro	(revision 25766)
@@ -26,4 +26,7 @@
     active true
   end
+  task chip.revert
+    active true
+  end
 end
 
@@ -36,4 +39,7 @@
   end
   task chip.advanceexp
+    active false
+  end
+  task chip.revert
     active false
   end
Index: branches/eam_branches/20090820/ippTasks/destreak.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/destreak.pro	(revision 25766)
+++ branches/eam_branches/20090820/ippTasks/destreak.pro	(revision 25766)
@@ -0,0 +1,490 @@
+## destreak.pro : support for the streak removal : -*- sh -*-
+
+# test for required global variables
+check.globals
+
+$LOGSUBDIR = $LOGDIR/destreak
+mkdir $LOGSUBDIR
+
+### Initialise the books containing the tasks to do
+book init magicToDS
+book init magicDSToRevert
+
+### indexes into Database lists
+$magicToDS_DB = 0
+$magicDSAdvance_DB = 0
+$magicDSToRevert_DB = 0
+$magicDSCompletedRevert_DB = 0
+
+#list of stages
+$DS_STAGE:n = 0
+list DS_STAGE -add "raw"
+list DS_STAGE -add "chip"
+list DS_STAGE -add "camera"
+list DS_STAGE -add "warp"
+list DS_STAGE -add "diff"
+
+$magicDSStage = 0
+$magicDSRevertStage = 0
+
+### Check status of tasks
+macro magic.status
+    book listbook magicToDS
+    book listbook magicDSToRevert
+end
+
+### Reset tasks
+macro magic.reset
+    book init magicToDS
+    book init magicDSToRevert
+end
+
+### Turn tasks on
+macro destreak.on
+    # destreak and revert should not run at the same time
+    destreak.revert.off
+
+    task destreak.load
+        active true
+    end
+    task destreak.run
+        active true
+    end
+    task destreak.advance
+        active true
+    end
+end
+
+macro destreak.revert.on
+    # destreak and revert should not run at the same time
+    destreak.off
+
+    task destreak.revert.load
+        active true
+    end
+    task destreak.revert.run
+        active true
+    end
+    task destreak.completed.revert
+        active true
+    end
+end
+
+### Turn tasks off
+macro destreak.off
+    task destreak.load
+        active false
+    end
+    task destreak.run
+        active false
+    end
+    task destreak.advance
+        active false
+    end
+end
+
+macro destreak.revert.off
+    task destreak.revert.load
+        active false
+    end
+    task destreak.revert.run
+        active false
+    end
+    task destreak.completed.revert
+        active false
+    end
+end
+
+macro destreak.status
+    echo magicToDS
+    book listbook magicToDS
+    echo ""
+    echo magicDSToRevert
+    book listbook magicDSToRevert
+end
+
+task	       destreak.load
+  host         local
+
+  periods      -poll $LOADPOLL
+  # this query can take a long time (XXX: the long time should be fixed now)
+  periods      -exec 10
+  periods      -timeout 120
+  npending     1
+
+#  stdout NULL
+#  stderr $LOGSUBDIR/destreak.load.log
+
+  task.exec
+    $run = magicdstool -todestreak -limit 120 -stage $DS_STAGE:$magicDSStage
+    $magicDSStage ++
+    if ($magicDSStage >= $DS_STAGE:n) set magicDSStage = 0
+
+    if ($DB:n == 0)
+      option DEFAULT
+    else
+      # save the DB name for the exit tasks
+      option $DB:$magicToDS_DB
+      $run = $run -dbname $DB:$magicToDS_DB
+
+      # only bump database number after we have gone through all of the stages
+      if ($magicDSStage == 0)
+          $magicToDS_DB ++
+          if ($magicToDS_DB >= $DB:n) set magicToDS_DB = 0
+      end
+    end
+    add_poll_args run
+    add_poll_labels run
+    command $run
+  end
+
+  # success
+  task.exit    0
+    # convert 'stdout' to book format
+    ipptool2book stdout magicToDS -key magic_ds_id:component -uniq -setword dbname $options:0 -setword pantaskState INIT
+    if ($VERBOSE > 2)
+      book listbook magicToDS
+    end
+
+    # delete existing entries in the appropriate pantaskStates
+    process_cleanup magicToDS
+  end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+  end
+
+  task.exit    crash
+    showcommand crash
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
+
+task	       destreak.run
+  periods      -poll $RUNPOLL
+  periods      -exec $RUNEXEC
+  periods      -timeout 60
+
+  task.exec
+    stdout $LOGSUBDIR/destreak.run.log
+    stderr $LOGSUBDIR/destreak.run.log
+    book npages magicToDS -var N
+    if ($N == 0) break
+    if ($NETWORK == 0) break
+    
+    # look for new images (pantaskState == INIT)
+    book getpage magicToDS 0 -var pageName -key pantaskState INIT
+    if ("$pageName" == "NULL") break
+
+    book setword magicToDS $pageName pantaskState RUN
+    book getword magicToDS $pageName exp_id -var EXP_ID
+    book getword magicToDS $pageName magic_ds_id -var MAGIC_DS_ID
+    book getword magicToDS $pageName camera -var CAMERA
+    book getword magicToDS $pageName streaks_uri -var STREAKS
+    book getword magicToDS $pageName inv_streaks_uri -var INV_STREAKS
+    book getword magicToDS $pageName stage -var STAGE
+    book getword magicToDS $pageName stage_id -var STAGE_ID
+    book getword magicToDS $pageName component -var COMPONENT
+    book getword magicToDS $pageName uri -var URI
+    book getword magicToDS $pageName path_base -var PATH_BASE
+    book getword magicToDS $pageName cam_path_base -var CAM_PATH_BASE
+    book getword magicToDS $pageName outroot -var OUTROOT
+    book getword magicToDS $pageName recoveryroot -var RECROOT
+    book getword magicToDS $pageName re_place -var REPLACE
+    book getword magicToDS $pageName dbname -var DBNAME
+
+    sprintf logfile "%s/%s.mds.%s.%s.%s.log" $OUTROOT $EXP_ID $MAGIC_DS_ID $STAGE_ID $COMPONENT
+
+    substr $COMPONENT 0 3 COMP_HEAD
+    if ("$COMP_HEAD" == "sky")
+        set.host.for.skycell $COMPONENT
+    else 
+        # assume component is a class_id, if not we will default to anyhost
+        set.host.for.camera $CAMERA $COMPONENT
+    end
+
+    # TODO: do not add recoveryroot or replace if they are null or zero
+
+    $run = magic_destreak.pl --magic_ds_id $MAGIC_DS_ID --camera $CAMERA --streaks $STREAKS --inv_streaks $INV_STREAKS --stage $STAGE --stage_id $STAGE_ID --component $COMPONENT --uri $URI --path_base $PATH_BASE --cam_path_base $CAM_PATH_BASE --outroot $OUTROOT --logfile $logfile --recoveryroot $RECROOT --replace $REPLACE
+
+    add_standard_args run
+
+    # save the pageName for future reference below
+    options $pageName
+
+    # create the command line
+    if ($VERBOSE > 1)
+      echo command $run
+    end
+    command $run
+  end
+
+  # default exit status
+  task.exit    0
+    process_exit magicToDS $options:0 $JOB_STATUS
+   end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+    process_exit magicToDS $options:0 $JOB_STATUS
+  end
+
+  task.exit    crash
+    showcommand crash
+    book setword magicToDS $options:0 pantaskState CRASH
+  end
+
+  # operation timed out?
+  task.exit    timeout
+    showcommand timeout
+    book setword magicToDS $options:0 pantaskState TIMEOUT
+  end
+end
+
+task	       destreak.advance
+    # task to finish processing for magicDSRuns 
+  host         local
+
+  periods      -poll $LOADPOLL
+  #periods      -exec $LOADEXEC
+  periods      -exec 30
+  periods      -timeout 20
+  npending     1
+
+#  stdout NULL
+#  stderr $LOGSUBDIR/destreak.advance.log
+
+  task.exec
+    $run = magicdstool -advancerun 
+    if ($DB:n != 0)
+
+      $run = $run -dbname $DB:$magicDSAdvance_DB
+
+      $magicDSAdvance_DB ++
+      if ($magicDSAdvance_DB >= $DB:n) set magicDSAdvance_DB = 0
+    end
+    add_poll_args run
+    add_poll_labels run
+    command $run
+  end
+
+  # success
+  task.exit    0
+  end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+  end
+
+  task.exit    crash
+    showcommand crash
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
+
+task	       destreak.revert.load
+  host         local
+
+  periods      -poll $LOADPOLL
+  periods      -exec $LOADEXEC
+  periods      -timeout 20
+  npending     1
+  active       false
+
+  stdout NULL
+  stderr $LOGSUBDIR/destreak.revert.log
+
+  task.exec
+    $run = magicdstool -torevert -stage $DS_STAGE:$magicDSRevertStage
+    $magicDSRevertStage ++
+    if ($magicDSRevertStage >= $DS_STAGE:n) set magicDSRevertStage = 0
+
+    if ($DB:n == 0)
+      option DEFAULT
+    else
+
+      # save the DB name for the exit tasks
+      option $DB:$magicDSToRevert_DB
+      $run = $run -dbname $DB:$magicDSToRevert_DB
+
+      # only bump database number after we have gone through all of the stages
+      if ($magicDSRevertStage == 0)
+          $magicDSToRevert_DB ++
+          if ($magicDSToRevert_DB >= $DB:n) set magicDSToRevert_DB = 0
+      end
+    end
+    add_poll_args run
+    add_poll_labels run
+    command $run
+  end
+
+  # success
+  task.exit    0
+    # convert 'stdout' to book format
+    ipptool2book stdout magicDSToRevert -key magic_ds_id:component -uniq -setword dbname $options:0 -setword pantaskState INIT
+    if ($VERBOSE > 2)
+      book listbook magicDSToRevert
+    end
+
+    # delete existing entries in the appropriate pantaskStates
+    process_cleanup magicDSToRevert
+  end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+  end
+
+  task.exit    crash
+    showcommand crash
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
+
+task	       destreak.revert.run
+  periods      -poll $RUNPOLL
+  periods      -exec $RUNEXEC
+  periods      -timeout 60
+  active       false
+
+  task.exec
+    stdout $LOGSUBDIR/destreak.revert.run.log
+    stderr $LOGSUBDIR/destreak.revert.run.log
+
+    book npages magicDSToRevert -var N
+    if ($N == 0) break
+    if ($NETWORK == 0) break
+    
+    # look for new images (pantaskState == INIT)
+    book getpage magicDSToRevert 0 -var pageName -key pantaskState INIT
+    if ("$pageName" == "NULL") break
+
+    book setword magicDSToRevert $pageName pantaskState RUN
+    book getword magicDSToRevert $pageName exp_id -var EXP_ID
+    book getword magicDSToRevert $pageName magic_ds_id -var MAGIC_DS_ID
+    book getword magicDSToRevert $pageName camera -var CAMERA
+    book getword magicDSToRevert $pageName stage -var STAGE
+    book getword magicDSToRevert $pageName stage_id -var STAGE_ID
+    book getword magicDSToRevert $pageName component -var COMPONENT
+    book getword magicDSToRevert $pageName path_base -var PATH_BASE
+    book getword magicDSToRevert $pageName cam_path_base -var CAM_PATH_BASE
+    book getword magicDSToRevert $pageName outroot -var OUTROOT
+    book getword magciDSToRevert $pageName bytes -var BYTES
+    book getword magciDSToRevert $pageName md5sum -var md5sum
+#    book getword magicDSToRevert $pageName recoveryroot -var RECROOT
+    book getword magicDSToRevert $pageName re_place -var REPLACE
+    book getword magicDSToRevert $pageName dbname -var DBNAME
+
+    sprintf logfile "%s/%s.mds.revert.%s.%s.%s.log" $OUTROOT $EXP_ID $MAGIC_DS_ID $STAGE_ID $COMPONENT
+
+    substr $COMPONENT 0 3 COMP_HEAD
+    if ("$COMP_HEAD" == "sky")
+        set.host.for.skycell $COMPONENT
+    else 
+        # assume component is a class_id, if not we will default to anyhost
+        set.host.for.camera $CAMERA $COMPONENT
+    end
+
+    $run = magic_destreak_revert.pl --magic_ds_id $MAGIC_DS_ID --camera $CAMERA --stage $STAGE --stage_id $STAGE_ID --component $COMPONENT --path_base $PATH_BASE --cam_path_base $CAM_PATH_BASE --outroot $OUTROOT --logfile $logfile --replace $REPLACE
+
+    add_standard_args run
+
+    # save the pageName for future reference below
+    options $pageName
+
+    # create the command line
+    if ($VERBOSE > 1)
+      echo command $run
+    end
+    command $run
+  end
+
+  # default exit status
+  task.exit    0
+    process_exit magicDSToRevert $options:0 $JOB_STATUS
+   end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+    process_exit magicDSToRevert $options:0 $JOB_STATUS
+  end
+
+  task.exit    crash
+    showcommand crash
+    book setword magicDSToRevert $options:0 pantaskState CRASH
+  end
+
+  # operation timed out?
+  task.exit    timeout
+    showcommand timeout
+    book setword magicDSToRevert $options:0 pantaskState TIMEOUT
+  end
+end
+
+task	       destreak.completed.revert
+    # task to finish processing for magicDSRuns being reverted or restored
+  host         local
+
+  periods      -poll $LOADPOLL
+  #periods      -exec $LOADEXEC
+  periods      -exec 30
+  periods      -timeout 20
+  npending     1
+  active       false
+
+  stdout NULL
+  stderr $LOGSUBDIR/destreak.completed.revert.log
+
+  task.exec
+    $run = magicdstool -completedrevert 
+    if ($DB:n == 0)
+      option DEFAULT
+    else
+      # save the DB name for the exit tasks
+      option $DB:$magicDSCompletedRevert_DB
+
+      $run = $run -dbname $DB:$magicDSCompletedRevert_DB
+
+      $magicDSCompletedRevert_DB ++
+      if ($magicDSCompletedRevert_DB >= $DB:n) set magicDSCompletedRevert_DB = 0
+    end
+    add_poll_args run
+    add_poll_labels run
+    command $run
+  end
+
+  # success
+  task.exit    0
+  end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+  end
+
+  task.exit    crash
+    showcommand crash
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
+
Index: branches/eam_branches/20090820/ippTasks/detrend.cleanup.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/detrend.cleanup.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/detrend.cleanup.pro	(revision 25766)
@@ -234,5 +234,5 @@
     book getword detCleanupProcessedImfile $pageName class_id -var CLASS_ID 
     book getword detCleanupProcessedImfile $pageName camera   -var CAMERA
-    book getword detCleanupProcessedImfile $pageName state    -var CLEANUP_MODE
+    book getword detCleanupProcessedImfile $pageName data_state    -var CLEANUP_MODE
     book getword detCleanupProcessedImfile $pageName dbname   -var DBNAME
 
@@ -244,5 +244,5 @@
 
     # XXX is everything listed here needed?
-    $run = ipp_cleanup.pl --stage detrend.process.imfile --stage_id $DET_ID --exp_id $EXP_ID --class_id $CLASS_ID --camera $CAMERA --mode $CLEANUP_MODE
+    $run = ipp_cleanup.pl --stage detrend.process.imfile --stage_id $DET_ID --camera $CAMERA --mode $CLEANUP_MODE
     add_standard_args run
 
@@ -352,5 +352,5 @@
     book getword detCleanupProcessedExp $pageName exp_id   -var EXP_ID   
     book getword detCleanupProcessedExp $pageName camera -var CAMERA
-    book getword detCleanupProcessedExp $pageName state -var CLEANUP_MODE
+    book getword detCleanupProcessedExp $pageName data_state -var CLEANUP_MODE
     book getword detCleanupProcessedExp $pageName dbname -var DBNAME
 
@@ -362,5 +362,5 @@
 
     # XXX is everything listed here needed?
-    $run = ipp_cleanup.pl --stage detrend.process.exp --stage_id $DET_ID --exp_id $EXP_ID --camera $CAMERA --mode $CLEANUP_MODE
+    $run = ipp_cleanup.pl --stage detrend.process.exp --stage_id $DET_ID --camera $CAMERA --mode $CLEANUP_MODE
     add_standard_args run
 
@@ -470,5 +470,5 @@
     book getword detCleanupStackedImfile $pageName class_id -var CLASS_ID 
     book getword detCleanupStackedImfile $pageName camera -var CAMERA
-    book getword detCleanupStackedImfile $pageName state -var CLEANUP_MODE
+    book getword detCleanupStackedImfile $pageName data_state -var CLEANUP_MODE
     book getword detCleanupStackedImfile $pageName dbname -var DBNAME
 
@@ -480,5 +480,5 @@
 
     # XXX is everything listed here needed?
-    $run = ipp_cleanup.pl --stage detrend.stack.imfile --stage_id $DET_ID --iteration $ITERATION --class_id $CLASS_ID --camera $CAMERA --mode $CLEANUP_MODE
+    $run = ipp_cleanup.pl --stage detrend.stack.imfile --stage_id $DET_ID --camera $CAMERA --mode $CLEANUP_MODE
     add_standard_args run
 
@@ -588,5 +588,5 @@
     book getword detCleanupNormStatImfile $pageName iteration -var ITERATION
     book getword detCleanupNormStatImfile $pageName camera -var CAMERA
-    book getword detCleanupNormStatImfile $pageName state -var CLEANUP_MODE
+    book getword detCleanupNormStatImfile $pageName data_state -var CLEANUP_MODE
     book getword detCleanupNormStatImfile $pageName dbname -var DBNAME
 
@@ -598,5 +598,5 @@
 
     # XXX is everything listed here needed?
-    $run = ipp_cleanup.pl --stage detrend.normstat.imfile --stage_id $DET_ID --iteration $ITERATION --camera $CAMERA --mode $CLEANUP_MODE
+    $run = ipp_cleanup.pl --stage detrend.normstat.imfile --stage_id $DET_ID --camera $CAMERA --mode $CLEANUP_MODE
     add_standard_args run
 
@@ -704,5 +704,5 @@
     book getword detCleanupNormImfile $pageName class_id -var CLASS_ID 
     book getword detCleanupNormImfile $pageName camera -var CAMERA
-    book getword detCleanupNormImfile $pageName state -var CLEANUP_MODE
+    book getword detCleanupNormImfile $pageName data_state -var CLEANUP_MODE
     book getword detCleanupNormImfile $pageName dbname -var DBNAME
 
@@ -714,5 +714,5 @@
 
     # XXX is everything listed here needed?
-    $run = ipp_cleanup.pl --stage detrend.norm.imfile --stage_id $DET_ID --iteration $ITERATION --class_id $CLASS_ID --camera $CAMERA --mode $CLEANUP_MODE
+    $run = ipp_cleanup.pl --stage detrend.norm.imfile --stage_id $DET_ID --camera $CAMERA --mode $CLEANUP_MODE
     add_standard_args run
 
@@ -819,5 +819,5 @@
     book getword detCleanupNormExp $pageName iteration -var ITERATION
     book getword detCleanupNormExp $pageName camera -var CAMERA
-    book getword detCleanupNormExp $pageName state -var CLEANUP_MODE
+    book getword detCleanupNormExp $pageName data_state -var CLEANUP_MODE
     book getword detCleanupNormExp $pageName dbname -var DBNAME
 
@@ -829,5 +829,5 @@
 
     # XXX is everything listed here needed?
-    $run = ipp_cleanup.pl --stage detrend.norm.exp --stage_id $DET_ID --iteration $ITERATION --camera $CAMERA --mode $CLEANUP_MODE
+    $run = ipp_cleanup.pl --stage detrend.norm.exp --stage_id $DET_ID --camera $CAMERA --mode $CLEANUP_MODE
     add_standard_args run
 
@@ -937,5 +937,5 @@
     book getword detCleanupResidImfile $pageName iteration -var ITERATION     
     book getword detCleanupResidImfile $pageName camera -var CAMERA
-    book getword detCleanupResidImfile $pageName state -var CLEANUP_MODE
+    book getword detCleanupResidImfile $pageName data_state -var CLEANUP_MODE
     book getword detCleanupResidImfile $pageName dbname -var DBNAME
 
@@ -947,5 +947,5 @@
 
     # XXX is everything listed here needed?
-    $run = ipp_cleanup.pl --stage detrend.resid.imfile --stage_id $DET_ID --exp_id $EXP_ID --class_id $CLASS_ID --iteration $ITERATION --camera $CAMERA --mode $CLEANUP_MODE
+    $run = ipp_cleanup.pl --stage detrend.resid.imfile --stage_id $DET_ID  --camera $CAMERA --mode $CLEANUP_MODE
     add_standard_args run
 
@@ -1056,5 +1056,5 @@
     book getword detCleanupResidExp $pageName iteration -var ITERATION
     book getword detCleanupResidExp $pageName camera 	-var CAMERA
-    book getword detCleanupResidExp $pageName state  	-var CLEANUP_MODE
+    book getword detCleanupResidExp $pageName data_state  	-var CLEANUP_MODE
     book getword detCleanupResidExp $pageName dbname 	-var DBNAME
 
@@ -1066,5 +1066,5 @@
 
     # XXX is everything listed here needed?
-    $run = ipp_cleanup.pl --stage detrend.resid.exp --stage_id $DET_ID --exp_id $EXP_ID --class_id $CLASS_ID --camera $CAMERA --mode $CLEANUP_MODE
+    $run = ipp_cleanup.pl --stage detrend.resid.exp --stage_id $DET_ID --camera $CAMERA --mode $CLEANUP_MODE
     add_standard_args run
 
Index: branches/eam_branches/20090820/ippTasks/diff.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/diff.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/diff.pro	(revision 25766)
@@ -14,4 +14,5 @@
 ### Database lists
 $diffSkycell_DB = 0
+$diffAdvance_DB = 0
 #$diffCleanup_DB = 0
 
@@ -36,4 +37,7 @@
     active true
   end
+  task diff.advance
+    active true
+  end
 end
 
@@ -44,4 +48,7 @@
   end
   task diff.skycell.run
+    active false
+  end
+  task diff.advance
     active false
   end
@@ -198,4 +205,56 @@
   end
 end
+
+
+# Advance exposures which have completed
+task	       diff.advance
+  host         local
+
+  periods      -poll $LOADPOLL
+#  periods      -exec $LOADEXEC
+  periods      -exec 30
+  periods      -timeout 60
+  npending     1
+
+  stdout NULL
+  stderr $LOGDIR/diff.advance.log
+
+  task.exec
+    if ($LABEL:n == 0) break
+    $run = difftool -advance
+    if ($DB:n == 0)
+      option DEFAULT
+    else
+      # save the DB name for the exit tasks
+      option $DB:$diffAdvance_DB
+      $run = $run -dbname $DB:$diffAdvance_DB
+      $diffAdvance_DB ++
+      if ($diffAdvance_DB >= $DB:n) set diffAdvance_DB = 0
+    end
+    add_poll_args run
+    add_poll_labels run
+    command $run
+  end
+
+  # success
+  task.exit    0
+  end
+
+  # locked list
+  task.exit    default
+    showcommand failure
+  end
+
+  task.exit    crash
+    showcommand crash
+  end
+
+  # operation times out?
+  task.exit    timeout
+    showcommand timeout
+  end
+end
+
+
 
 # # select images ready for diff analysis
Index: branches/eam_branches/20090820/ippTasks/dist.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/dist.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/dist.pro	(revision 25766)
@@ -16,4 +16,17 @@
 $distQueue_DB = 0
 
+### list of stages
+#list of stages
+$DIST_STAGE:n = 0
+list DIST_STAGE -add "raw"
+list DIST_STAGE -add "chip"
+list DIST_STAGE -add "camera"
+list DIST_STAGE -add "fake"
+list DIST_STAGE -add "warp"
+list DIST_STAGE -add "diff"
+list DIST_STAGE -add "stack"
+
+$currentStage = 0
+
 ### Check status of tasks
 macro dist.status
@@ -42,10 +55,6 @@
     active true
   end
-  task dist.queueruns
-#   We aren't ready to run this task yet. It will queue much too much 
-#    active true
-    active false
-  end
-end
+end
+
 macro dist.off
   task dist.process.load
@@ -59,7 +68,4 @@
   end
   task dist.advance.run
-    active false
-  end
-  task dist.queueruns
     active false
   end
@@ -74,9 +80,13 @@
   npending     1
 
-  stdout NULL
-  stderr $LOGDIR/dist.process.log
 
   task.exec
-    $run = disttool -pendingcomponent
+     # stdout NULL
+     # stderr $LOGSUBDIR/dist.process.load.log
+
+    $run = disttool -pendingcomponent -stage $DIST_STAGE:$currentStage
+    $currentStage ++
+    if ($currentStage >= $DIST_STAGE:n) set currentStage = 0
+
     if ($DB:n == 0)
       option DEFAULT
@@ -85,6 +95,11 @@
       option $DB:$distToProcess_DB
       $run = $run -dbname $DB:$distToProcess_DB
-      $distToProcess_DB ++
-      if ($distToProcess_DB >= $DB:n) set distToProcess_DB = 0
+
+      # only increment the database number after we have gone through all of
+      # the stages
+      if ($currentStage == 0)
+          $distToProcess_DB ++
+          if ($distToProcess_DB >= $DB:n) set distToProcess_DB = 0
+      end
     end
     add_poll_args run
@@ -134,9 +149,11 @@
     if ("$pageName" == "NULL") break
 
+#    echo running $pageName
+
     book setword distToProcess $pageName pantaskState RUN
     book getword distToProcess $pageName dist_id -var DIST_ID
     book getword distToProcess $pageName camera -var CAMERA
-    book getword distToProcess $pageName stage -var STAGE
-    book getword distToProcess $pageName stage_id -var STAGE_ID
+    book getword distToProcess $pageName stage -var DIST_STAGE
+    book getword distToProcess $pageName stage_id -var DIST_STAGE_ID
     book getword distToProcess $pageName clean -var CLEAN
     book getword distToProcess $pageName component -var COMPONENT
@@ -159,6 +176,6 @@
         $EXTRA_ARGS = $EXTRA_ARGS --magicked
     end
-    # no_magic is output as integer due to the union in the sql
-    if ($NO_MAGIC)
+    # is this right for stack and fake?
+    if ("$NO_MAGIC" == "T")
         $EXTRA_ARGS = $EXTRA_ARGS --no_magic
     end
@@ -170,5 +187,4 @@
 #    set.workdir.by.camera $CAMERA $MAGIC_ID $WORKDIR_TEMPLATE $default_host WORKDIR
 #    host anyhost
-
 
     substr $COMPONENT 0 3 COMP_HEAD
@@ -180,10 +196,9 @@
     end
 
-
     sprintf logfile "%s/dist.%s.%s.log" $OUTDIR $DIST_ID $COMPONENT
-    stdout $logfile
-    stderr $logfile
-
-    $run = dist_component.pl --dist_id $DIST_ID --camera $CAMERA --stage $STAGE --stage_id $STAGE_ID --component $COMPONENT --path_base $PATH_BASE --chip_path_base $CHIP_PATH_BASE --state $STATE --data_state $DATA_STATE $EXTRA_ARGS --outdir $OUTDIR --logfile $logfile
+#    stdout $logfile
+#    stderr $logfile
+
+    $run = dist_component.pl --dist_id $DIST_ID --camera $CAMERA --stage $DIST_STAGE --stage_id $DIST_STAGE_ID --component $COMPONENT --path_base $PATH_BASE --chip_path_base $CHIP_PATH_BASE --state $STATE --data_state $DATA_STATE $EXTRA_ARGS --outdir $OUTDIR --logfile $logfile
 
     add_standard_args run
@@ -211,5 +226,4 @@
 end
 
-
 task	       dist.advance.load
   host         local
@@ -220,8 +234,7 @@
   npending     1
 
-  stdout NULL
-  stderr $LOGDIR/dist.advance.load.log
-
   task.exec
+  #  stderr $LOGSUBDIR/dist.advance.load.log
+
     $run = disttool -toadvance
     if ($DB:n == 0)
@@ -261,4 +274,5 @@
   end
 end
+
 
 task	       dist.advance.run
@@ -291,6 +305,6 @@
 
     sprintf logfile "%s/dist.advance.%s.log" $OUTDIR $DIST_ID
-    stdout $logfile
-    stderr $logfile
+#    stdout $logfile
+#    stderr $logfile
 
     $run = dist_advancerun.pl --dist_id $DIST_ID --stage $STAGE --stage_id $STAGE_ID --outdir $OUTDIR $EXTRA_ARGS --logfile $logfile
@@ -318,64 +332,2 @@
   end
 end
-
-task	       dist.queueruns
-#  host         local
-
-  periods      -poll $RUNPOLL
-  periods      -exec 30
-  periods      -timeout 45
-  npending     1
-
-  active false
-
-#  stdout $LOGDIR/dist.queuruns
-#  stderr $LOGDIR/dist.queueruns
-
-  task.exec
-    $MYARGS = ""
-    # assume that we need magic unless we are running simtest
-    if ($?SIMTEST_CAMERA != 0)
-        $MYARGS = --no_magic
-    end
-
-    $run = dist_queue_runs.pl $MYARGS --stage_limit 16 --logfile $LOGDIR/dist.queueruns
-
-    if ($DB:n == 0)
-       $DBNAME = DEFAULT
-    else
-      # save the DB name for add_standard_args
-      $DBNAME =  $DB:$distQueue_DB
-      $distQueue_DB ++
-      if ($distQueue_DB >= $DB:n) set distQueue_DB = 0
-    end
-
-    host anyhost
-
-    add_standard_args run
-
-    # create the command line
-    if ($VERBOSE > 1)
-      echo command $run
-    end
-    command $run
-  end
-
-  task.exit     $EXIT_SUCCESS
-    # nothing to do
-  end
-
-  # default exit status
-  task.exit    default
-    showcommand failure
-  end
-
-  # operation timed out?
-  task.exit    timeout
-    showcommand timeout
-  end
-
-  # operation timed out?
-  task.exit    crash
-    showcommand crash
-  end
-end
Index: branches/eam_branches/20090820/ippTasks/fake.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/fake.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/fake.pro	(revision 25766)
@@ -26,4 +26,7 @@
     active true
   end
+  task fake.revert
+    active true
+  end
 end
 
@@ -36,4 +39,7 @@
   end
   task fake.advanceexp
+    active false
+  end
+  task fake.revert
     active false
   end
Index: branches/eam_branches/20090820/ippTasks/ipphosts.mhpcc.config
===================================================================
--- branches/eam_branches/20090820/ippTasks/ipphosts.mhpcc.config	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/ipphosts.mhpcc.config	(revision 25766)
@@ -3,38 +3,51 @@
 ipphosts METADATA
   camera STR skycell
-  count S32  12
-  sky00 STR  ipp024
-  sky01 STR  ipp023
-  sky02 STR  ipp026 
-  sky03 STR  ipp028
-  sky04 STR  ipp029
-  sky05 STR  ipp030
-  sky06 STR  ipp031
-  sky07 STR  ipp032
-  sky08 STR  ipp033
-  sky09 STR  ipp034
-  sky10 STR  ipp035
-  sky11 STR  ipp036
-END
-
-ipphosts METADATA
-  camera STR MEGACAM
-  ccd00 STR po00
-  ccd01 STR po01
-  ccd02 STR po02
-  ccd03 STR po03
-  ccd04 STR po04
-  ccd05 STR po05
-  ccd06 STR po06
-  ccd07 STR po07
-  ccd08 STR po08
-  ccd09 STR po09
-END
-
-ipphosts METADATA
-  camera STR CFH12K
-  ccd00 STR po10
-  ccd01 STR po11
-  ccd02 STR po12
+  count S32  46
+  sky00 STR  ipp006
+  sky01 STR  ipp007
+  sky02 STR  ipp008 
+  sky03 STR  ipp009
+  sky04 STR  ipp010
+  sky05 STR  ipp011
+  sky06 STR  ipp012
+  sky07 STR  ipp013
+  sky08 STR  ipp014
+  sky09 STR  ipp015
+  sky10 STR  ipp016
+  sky11 STR  ipp017
+  sky12 STR  ipp018 
+  sky13 STR  ipp019
+  sky14 STR  ipp020
+  sky15 STR  ipp021
+  sky16 STR  ipp023
+  sky17 STR  ipp024
+  sky18 STR  ipp025
+  sky19 STR  ipp026
+  sky20 STR  ipp027
+  sky21 STR  ipp028
+  sky22 STR  ipp029 
+  sky23 STR  ipp030
+  sky24 STR  ipp031
+  sky25 STR  ipp032
+  sky26 STR  ipp033
+  sky27 STR  ipp034
+  sky28 STR  ipp035
+  sky29 STR  ipp036
+  sky30 STR  ipp038
+  sky31 STR  ipp039
+  sky32 STR  ipp040 
+  sky33 STR  ipp041
+  sky34 STR  ipp042
+  sky35 STR  ipp043
+  sky36 STR  ipp044
+  sky37 STR  ipp045
+  sky38 STR  ipp046
+  sky39 STR  ipp047
+  sky40 STR  ipp048
+  sky41 STR  ipp049
+  sky42 STR  ipp050 
+  sky43 STR  ipp051
+  sky44 STR  ipp052
+  sky45 STR  ipp053
 END
 
@@ -114,6 +127,6 @@
   XY73  STR  ipp015
   XY74  STR  ipp015
-  XY75  STR  ipp053
-  XY76  STR  ipp053
+  XY75  STR  ipp025
+  XY76  STR  ipp025
 END
 
@@ -193,5 +206,5 @@
   ota73  STR  ipp015
   ota74  STR  ipp015
-  ota75  STR  ipp053
-  ota76  STR  ipp053
+  ota75  STR  ipp025
+  ota76  STR  ipp025
 END
Index: branches/eam_branches/20090820/ippTasks/magic.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/magic.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/magic.pro	(revision 25766)
@@ -10,21 +10,8 @@
 book init magicToTree
 book init magicToProcess
-book init magicToDS
-book init magicDSToRevert
 
 ### Database lists
 $magicToTree_DB = 0
 $magicToProcess_DB = 0
-$magicToDS_DB = 0
-$magicDSToRevert_DB = 0
-
-#list of stages
-$STAGE:n = 0
-list STAGE -add "raw"
-list STAGE -add "chip"
-list STAGE -add "camera"
-list STAGE -add "warp"
-list STAGE -add "diff"
-$magicDSRevertStage = 0
 
 ### Check status of tasks
@@ -32,6 +19,4 @@
   book listbook magicToTree
   book listbook magicToProcess
-  book listbook magicToDS
-  book listbook magicDSToRevert
 end
 
@@ -40,6 +25,4 @@
   book init magicToTree
   book init magicToProcess
-  book init magicToDS
-  book init magicDSToRevert
 end
 
@@ -58,20 +41,6 @@
     active true
   end
-  task magic.destreak.load
-    active true
-  end
-  task magic.destreak.run
-    active true
-  end
-end
-
-macro magic.ds.revert.on
-    task magic.ds.revert.load
-        active true
-    end
-    task magic.ds.revert.run
-        active true
-    end
-end
+end
+
 ### Turn tasks off
 macro magic.off
@@ -88,46 +57,5 @@
     active false
   end
-  task magic.destreak.load
-    active false
-  end
-  task magic.destreak.run
-    active false
-  end
-end
-
-macro magic.ds.revert.off
-    task magic.ds.revert.load
-        active false
-    end
-    task magic.ds.revert.run
-        active false
-    end
-end
-macro magic.ds.off
-    task magic.destreak.load
-        active false
-    end
-    task magic.destreak.run
-        active false
-    end
-end
-macro magic.ds.on
-    task magic.destreak.load
-        active true
-    end
-    task magic.destreak.run
-        active true
-    end
-end
-
-macro magic.ds.status
-    echo magicToDS
-    book listbook magicToDS
-    echo ""
-    echo magicDSToRevert
-    book listbook magicDSToRevert
-end
-
-
+end
 
 task	       magic.tree.load
@@ -400,279 +328,2 @@
   end
 end
-
-task	       magic.destreak.load
-  host         local
-
-  periods      -poll $LOADPOLL
-  # this query can take a long time
-  periods      -exec 10
-  periods      -timeout 120
-  npending     1
-
-  stdout NULL
-  stderr $LOGDIR/magic.destreak.log
-
-  task.exec
-    $run = magicdstool -todestreak -limit 120
-    if ($DB:n == 0)
-      option DEFAULT
-    else
-      # save the DB name for the exit tasks
-      option $DB:$magicToDS_DB
-      $run = $run -dbname $DB:$magicToDS_DB
-      $magicToDS_DB ++
-      if ($magicToDS_DB >= $DB:n) set magicToDS_DB = 0
-    end
-    add_poll_args run
-    add_poll_labels run
-    command $run
-  end
-
-  # success
-  task.exit    0
-    # convert 'stdout' to book format
-    ipptool2book stdout magicToDS -key magic_ds_id:component -uniq -setword dbname $options:0 -setword pantaskState INIT
-    if ($VERBOSE > 2)
-      book listbook magicToDS
-    end
-
-    # delete existing entries in the appropriate pantaskStates
-    process_cleanup magicToDS
-  end
-
-  # locked list
-  task.exit    default
-    showcommand failure
-  end
-
-  task.exit    crash
-    showcommand crash
-  end
-
-  # operation times out?
-  task.exit    timeout
-    showcommand timeout
-  end
-end
-
-task	       magic.destreak.run
-  periods      -poll $RUNPOLL
-  periods      -exec $RUNEXEC
-  periods      -timeout 60
-
-  task.exec
-    book npages magicToDS -var N
-    if ($N == 0) break
-    if ($NETWORK == 0) break
-    
-    # look for new images (pantaskState == INIT)
-    book getpage magicToDS 0 -var pageName -key pantaskState INIT
-    if ("$pageName" == "NULL") break
-
-    book setword magicToDS $pageName pantaskState RUN
-    book getword magicToDS $pageName exp_id -var EXP_ID
-    book getword magicToDS $pageName magic_ds_id -var MAGIC_DS_ID
-    book getword magicToDS $pageName camera -var CAMERA
-    book getword magicToDS $pageName streaks_uri -var STREAKS
-    book getword magicToDS $pageName inv_streaks_uri -var INV_STREAKS
-    book getword magicToDS $pageName stage -var STAGE
-    book getword magicToDS $pageName stage_id -var STAGE_ID
-    book getword magicToDS $pageName component -var COMPONENT
-    book getword magicToDS $pageName uri -var URI
-    book getword magicToDS $pageName path_base -var PATH_BASE
-    book getword magicToDS $pageName cam_path_base -var CAM_PATH_BASE
-    book getword magicToDS $pageName outroot -var OUTROOT
-    book getword magicToDS $pageName recoveryroot -var RECROOT
-    book getword magicToDS $pageName re_place -var REPLACE
-    book getword magicToDS $pageName dbname -var DBNAME
-
-    sprintf logfile "%s/%s.mds.%s.%s.%s.log" $OUTROOT $EXP_ID $MAGIC_DS_ID $STAGE_ID $COMPONENT
-
-    substr $COMPONENT 0 3 COMP_HEAD
-    if ("$COMP_HEAD" == "sky")
-        set.host.for.skycell $COMPONENT
-    else 
-        # assume component is a class_id, if not we will default to anyhost
-        set.host.for.camera $CAMERA $COMPONENT
-    end
-
-    # TODO: do not add recoveryroot or replace if they are null or zero
-
-    $run = magic_destreak.pl --magic_ds_id $MAGIC_DS_ID --camera $CAMERA --streaks $STREAKS --inv_streaks $INV_STREAKS --stage $STAGE --stage_id $STAGE_ID --component $COMPONENT --uri $URI --path_base $PATH_BASE --cam_path_base $CAM_PATH_BASE --outroot $OUTROOT --logfile $logfile --recoveryroot $RECROOT --replace $REPLACE
-
-    add_standard_args run
-
-    # save the pageName for future reference below
-    options $pageName
-
-    # create the command line
-    if ($VERBOSE > 1)
-      echo command $run
-    end
-    command $run
-  end
-
-  # default exit status
-  task.exit    0
-    process_exit magicToDS $options:0 $JOB_STATUS
-   end
-
-  # locked list
-  task.exit    default
-    showcommand failure
-    process_exit magicToDS $options:0 $JOB_STATUS
-  end
-
-  task.exit    crash
-    showcommand crash
-    book setword magicToDS $options:0 pantaskState CRASH
-  end
-
-  # operation timed out?
-  task.exit    timeout
-    showcommand timeout
-    book setword magicToDS $options:0 pantaskState TIMEOUT
-  end
-end
-
-task	       magic.ds.revert.load
-  host         local
-
-  periods      -poll $LOADPOLL
-  periods      -exec $LOADEXEC
-  periods      -timeout 20
-  npending     1
-  active       false
-
-  stdout NULL
-  stderr $LOGDIR/magic.ds.revert.log
-
-  task.exec
-    $run = magicdstool -torevert -stage $STAGE:$magicDSRevertStage
-    $magicDSRevertStage ++
-    if ($magicDSRevertStage >= $STAGE:n) set magicDSRevertStage = 0
-
-    if ($DB:n == 0)
-      option DEFAULT
-    else
-
-      # save the DB name for the exit tasks
-      option $DB:$magicDSToRevert_DB
-      $run = $run -dbname $DB:$magicDSToRevert_DB
-
-      # only bump database number after we have gone through all of the stages
-      if ($magicDSRevertStage == 0)
-             $magicDSToRevert_DB ++
-      end
-      if ($magicDSToRevert_DB >= $DB:n) set magicDSToRevert_DB = 0
-    end
-    add_poll_args run
-    add_poll_labels run
-    command $run
-  end
-
-  # success
-  task.exit    0
-    # convert 'stdout' to book format
-    ipptool2book stdout magicDSToRevert -key magic_ds_id:component -uniq -setword dbname $options:0 -setword pantaskState INIT
-    if ($VERBOSE > 2)
-      book listbook magicDSToRevert
-    end
-
-    # delete existing entries in the appropriate pantaskStates
-    process_cleanup magicDSToRevert
-  end
-
-  # locked list
-  task.exit    default
-    showcommand failure
-  end
-
-  task.exit    crash
-    showcommand crash
-  end
-
-  # operation times out?
-  task.exit    timeout
-    showcommand timeout
-  end
-end
-
-task	       magic.ds.revert.run
-  periods      -poll $RUNPOLL
-  periods      -exec $RUNEXEC
-  periods      -timeout 60
-  active       false
-
-  task.exec
-    book npages magicDSToRevert -var N
-    if ($N == 0) break
-    if ($NETWORK == 0) break
-    
-    # look for new images (pantaskState == INIT)
-    book getpage magicDSToRevert 0 -var pageName -key pantaskState INIT
-    if ("$pageName" == "NULL") break
-
-    book setword magicDSToRevert $pageName pantaskState RUN
-    book getword magicDSToRevert $pageName exp_id -var EXP_ID
-    book getword magicDSToRevert $pageName magic_ds_id -var MAGIC_DS_ID
-    book getword magicDSToRevert $pageName camera -var CAMERA
-    book getword magicDSToRevert $pageName stage -var STAGE
-    book getword magicDSToRevert $pageName stage_id -var STAGE_ID
-    book getword magicDSToRevert $pageName component -var COMPONENT
-    book getword magicDSToRevert $pageName path_base -var PATH_BASE
-    book getword magicDSToRevert $pageName cam_path_base -var CAM_PATH_BASE
-    book getword magicDSToRevert $pageName outroot -var OUTROOT
-    book getword magciDSToRevert $pageName bytes -var BYTES
-    book getword magciDSToRevert $pageName md5sum -var md5sum
-#    book getword magicDSToRevert $pageName recoveryroot -var RECROOT
-    book getword magicDSToRevert $pageName re_place -var REPLACE
-    book getword magicDSToRevert $pageName dbname -var DBNAME
-
-    sprintf logfile "%s/%s.mds.revert.%s.%s.%s.log" $OUTROOT $EXP_ID $MAGIC_DS_ID $STAGE_ID $COMPONENT
-
-    substr $COMPONENT 0 3 COMP_HEAD
-    if ("$COMP_HEAD" == "sky")
-        set.host.for.skycell $COMPONENT
-    else 
-        # assume component is a class_id, if not we will default to anyhost
-        set.host.for.camera $CAMERA $COMPONENT
-    end
-
-    $run = magic_destreak_revert.pl --magic_ds_id $MAGIC_DS_ID --camera $CAMERA --stage $STAGE --stage_id $STAGE_ID --component $COMPONENT --path_base $PATH_BASE --cam_path_base $CAM_PATH_BASE --outroot $OUTROOT --logfile $logfile --replace $REPLACE
-
-    add_standard_args run
-
-    # save the pageName for future reference below
-    options $pageName
-
-    # create the command line
-    if ($VERBOSE > 1)
-      echo command $run
-    end
-    command $run
-  end
-
-  # default exit status
-  task.exit    0
-    process_exit magicDSToRevert $options:0 $JOB_STATUS
-   end
-
-  # locked list
-  task.exit    default
-    showcommand failure
-    process_exit magicDSToRevert $options:0 $JOB_STATUS
-  end
-
-  task.exit    crash
-    showcommand crash
-    book setword magicDSToRevert $options:0 pantaskState CRASH
-  end
-
-  # operation timed out?
-  task.exit    timeout
-    showcommand timeout
-    book setword magicDSToRevert $options:0 pantaskState TIMEOUT
-  end
-end
-
Index: branches/eam_branches/20090820/ippTasks/pantasks.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/pantasks.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/pantasks.pro	(revision 25766)
@@ -1,16 +1,20 @@
 ## pantasks.pro : globals and support macros : -*- sh -*-
 
+# globals that may be modified by the user -- only init if not set
+if ($?NEBULOUS == 0)  	  set NEBULOUS = 0
+if ($?NETWORK == 0)   	  set NETWORK = 1
+if ($?PARALLEL == 0)  	  set PARALLEL = 1
+if ($?VERBOSE == 0)   	  set VERBOSE = 1
+if ($?LABEL:n == 0)   	  set LABEL:n = 0
+if ($?POLLLIMIT == 0) 	  set POLLLIMIT = 32
+if ($?KEEP_FAILURES == 0) set KEEP_FAILURES = 0
+
+if ($?LOGDIR == 0) 
+  $LOGDIR = `pwd`
+  $LOGDIR = $LOGDIR/pantasks_logs
+  mkdir $LOGDIR
+end
+
 # globals used to control system behavior : these should be in uppercase
-$NEBULOUS = 0
-$NETWORK = 1
-$PARALLEL = 1
-$VERBOSE = 1
-$LABEL:n = 0
-$POLLLIMIT = 32
-$LOGDIR = `pwd`
-$LOGDIR = $LOGDIR/pantasks_logs
-mkdir $LOGDIR
-$KEEP_FAILURES = 0
-
 $LOADPOLL = 1.0
 $LOADEXEC = 5.0
@@ -32,5 +36,5 @@
 
 # very basic values: set these with init.copy.mhpcc
-$default_host     = anyhost
+$default_host     = any
 $workdir_template = `pwd`
 
@@ -147,4 +151,42 @@
 end
 
+macro save.labels
+  if ($0 != 1)
+    echo "USAGE: save.labels"
+    break
+  end
+  if ($?LABEL:n == 0)
+    echo "no labels defined"
+  end
+  if ($LABEL:n == 0)
+    echo "no labels defined"
+  end
+
+  exec rm -f labels.list
+  local i
+  for i 0 $LABEL:n
+    exec echo $LABEL:$i >> labels.list
+  end
+end
+
+macro load.labels
+  if ($0 != 1)
+    echo "USAGE: load.labels"
+    break
+  end
+
+  file labels.list found
+  if (not($found)) 
+    echo "no saved labels in labels.list"
+    return
+  end
+ 
+  list mylabels -x "cat labels.list"
+  local i
+  for i 0 $mylabels:n
+    add.label $mylabels:$i
+  end
+end
+
 macro init.isp
   list DB -add isp
@@ -213,4 +255,5 @@
   chip.on
   camera.on
+  addstar.on
   fake.on
   warp.on
@@ -225,4 +268,5 @@
   chip.off
   camera.off
+  addstar.off
   fake.off
   warp.off
@@ -242,4 +286,5 @@
   module chip.pro
   module camera.pro
+  module addstar.pro
   module fake.pro
   module warp.pro
Index: branches/eam_branches/20090820/ippTasks/pstamp.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/pstamp.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/pstamp.pro	(revision 25766)
@@ -1,4 +1,8 @@
-
-#$VERBOSE = 3
+# pstamp.pro : Postage Stamp Server tasks
+
+check.globals
+
+$LOGSUBDIR = $LOGDIR/pstamp
+mkdir $LOGSUBDIR
 
 # these variables wil cycle through the known database names
@@ -8,11 +12,13 @@
 $pstampJob_DB = 0
 $pstampFin_DB = 0
+$pstampRev_DB = 0
 
 # set PS_DBSERVER if postage stamp database host is not the same as the value for DBSERVER in site.config
-# warning: no quotes around the two words. it cause it to get passed to pstamptool as one word
-# tricky to debug problem ensues
+# warning: no quotes around the two words. That causes the variable to get passed to pstamptool as one word
+# and a tricky to debug problem ensues
 # example:
-# $PSDBSERVER = -dbserver hostname
-if ($?PSDBSERVER == 0)
+# $PS_DBSERVER = -dbserver hostname
+
+if ($?PS_DBSERVER == 0)
     $PS_DBSERVER = ""
 end
@@ -51,5 +57,9 @@
         active true
     end
-end
+    task pstamp.job.revert
+        active true
+    end
+end
+
 
 macro pstamp.off
@@ -74,4 +84,18 @@
     end
     task pstamp.job.run
+        active false
+    end
+    task pstamp.job.revert
+        active false
+    end
+end
+
+macro pstamp.revert.on
+    task pstamp.job.revert
+        active true
+    end
+end
+macro pstamp.revert.off
+    task pstamp.job.revert
         active false
     end
@@ -87,4 +111,6 @@
 
     task.exec
+        stdout $LOGSUBDIR/pstamp.request.find.log
+        stderr $LOGSUBDIR/pstamp.request.find.log
         if ($DB:n == 0)
             option DEFAULT
@@ -124,4 +150,6 @@
 
     task.exec
+        stdout $LOGSUBDIR/pstamp.request.load.log
+        stderr $LOGSUBDIR/pstamp.request.load.log
         $run = pstamptool -pendingreq
         if ($DB:n == 0)
@@ -134,4 +162,5 @@
         end
         add_poll_args run
+        # add_poll_labels run
         command $run
     end
@@ -166,4 +195,6 @@
 
     task.exec
+        stdout $LOGSUBDIR/pstamp.request.run.log
+        stderr $LOGSUBDIR/pstamp.request.run.log
         book npages pstampRequest -var N
         if ($N == 0) break
@@ -221,13 +252,18 @@
 
     task.exec
+        stdout $LOGSUBDIR/pstamp.finish.load.log
+        stderr $LOGSUBDIR/pstamp.finish.load.log
+        $run = pstamptool  -completedreq
         if ($DB:n == 0)
             option DEFAULT
-            command pstamptool  -completedreq
         else 
             option $DB:$pstampFin_DB
-            command pstamptool  -completedreq -dbname $DB:$pstampFin_DB $PS_DBSERVER
+            $run = $run -dbname $DB:$pstampFin_DB $PS_DBSERVER
             $pstampFin_DB ++
             if ($pstampFin_DB >= $DB:n) set pstampFin_DB = 0
         end
+        add_poll_args run
+        # add_poll_labels run
+        command $run
     end
 
@@ -260,4 +296,6 @@
 
     task.exec
+        stdout $LOGSUBDIR/request.finish.run.log
+        stderr $LOGSUBDIR/request.finish.run.log
         book npages pstampFinish -var N
         if ($N == 0) break
@@ -315,13 +353,18 @@
 
     task.exec
+        stdout $LOGSUBDIR/pstamp.job.load.log
+        stderr $LOGSUBDIR/pstamp.job.load.log
+        $run = pstamptool -pendingjob
         if ($DB:n == 0)
             option DEFAULT
-            command pstamptool -pendingjob -limit 10
         else
             option $DB:$pstampJob_DB
-            command pstamptool -pendingjob -limit 10 -dbname $DB:$pstampJob_DB $PS_DBSERVER
+            $run = $run -dbname $DB:$pstampJob_DB $PS_DBSERVER
             $pstampJob_DB ++
             if ($pstampJob_DB >= $DB:n) set pstampJob_DB = 0
         end
+        add_poll_args run
+        # add_poll_labels run 
+        command $run
     end
 
@@ -338,15 +381,16 @@
     end
 
+    task.exit   crash
+        showcommand crash
+    end
+
+    task.exit   timeout
+        showcommand timeout
+    end
+
     task.exit   default
         showcommand failure
     end
 
-    task.exit   crash
-        showcommand crash
-    end
-
-    task.exit   timeout
-        showcommand timeout
-    end
 end
 
@@ -357,6 +401,12 @@
 
     task.exec
+        stdout $LOGSUBDIR/pstamp.job.run.log
+        stderr $LOGSUBDIR/pstamp.job.run.log
         book npages pstampJob -var N
-        if ($N == 0) break
+        if ($N == 0) 
+            periods -exec $RUNEXEC
+            break
+        end
+        periods -exec 0.05
         
         book getpage pstampJob 0 -var pageName -key pantaskState INIT
@@ -418,2 +468,44 @@
     end
 end
+
+task pstamp.job.revert
+    host        local
+
+    periods     -poll $LOADPOLL
+    periods     -exec 10
+    periods     -timeout 300
+    npending    1
+
+    task.exec
+        stdout $LOGSUBDIR/pstamp.job.revert.log
+        stderr $LOGSUBDIR/pstamp.job.revert.log
+        $run = pstamptool -revertjob -all
+        if ($DB:n == 0)
+            option DEFAULT
+        else 
+            $run = $run $PS_DBSERVER -dbname $DB:$pstampRev_DB
+            $pstampRev_DB ++
+            if ($pstampRev_DB >= $DB:n) set pstampRev_DB = 0
+        end
+        add_poll_args run
+        # add_poll_labels run
+        command $run
+    end
+
+    task.exit $EXIT_SUCCESS
+        # nothing to do
+    end
+
+    task.exit   default
+        showcommand failure
+    end
+
+    task.exit   crash
+        showcommand crash
+    end
+
+    task.exit   timeout
+        showcommand timeout
+    end
+end
+
Index: branches/eam_branches/20090820/ippTasks/rcserver.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/rcserver.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/rcserver.pro	(revision 25766)
@@ -4,5 +4,5 @@
 check.globals
 
-#$LOGSUBDIR = $LOGDIR/rcserver
+$LOGSUBDIR = $LOGDIR/rcserver
 mkdir $LOGSUBDIR
 
@@ -66,5 +66,5 @@
 
   stdout NULL
-  stderr $LOGDIR/rcserver.makefileset.load.log
+  stderr $LOGSUBDIR/rcserver.makefileset.load.log
 
   task.exec
@@ -86,5 +86,5 @@
   task.exit    0
     # convert 'stdout' to book format
-    ipptool2book stdout rcPendingFS -key dist_id:prod_id -uniq -setword dbname $options:0 -setword pantaskState INIT
+    ipptool2book stdout rcPendingFS -key dist_id:dest_id -uniq -setword dbname $options:0 -setword pantaskState INIT
     if ($VERBOSE > 2)
       book listbook rcPendingFS
@@ -129,7 +129,9 @@
     book getword rcPendingFS $pageName stage -var STAGE
     book getword rcPendingFS $pageName stage_id -var STAGE_ID
+    book getword rcPendingFS $pageName label -var LABEL
+    book getword rcPendingFS $pageName filter -var FILTER
     book getword rcPendingFS $pageName dist_dir -var DIST_DIR
 #    book getword rcPendingFS $pageName clean -var CLEAN
-    book getword rcPendingFS $pageName prod_id -var PROD_ID
+    book getword rcPendingFS $pageName dest_id -var DEST_ID
     book getword rcPendingFS $pageName product_name -var PRODUCT_NAME
     book getword rcPendingFS $pageName ds_dbhost -var DS_DBHOST
@@ -141,5 +143,5 @@
     host anyhost
 
-    sprintf logfile "%s/makefs.%s.%s.log" $DIST_DIR $DIST_ID $PROD_ID
+    sprintf logfile "%s/makefs.%s.%s.log" $DIST_DIR $DIST_ID $DEST_ID
     stdout $logfile
     stderr $logfile
@@ -147,5 +149,5 @@
     book setword rcPendingFS $pageName pantaskState RUN
 
-    $run = dist_make_fileset.pl --dist_id $DIST_ID --target_id $TARGET_ID --stage $STAGE --stage_id $STAGE_ID --prod_id $PROD_ID --product_name $PRODUCT_NAME  --ds_dbhost $DS_DBHOST --ds_dbname $DS_DBNAME --dist_dir $DIST_DIR
+    $run = dist_make_fileset.pl --dist_id $DIST_ID --target_id $TARGET_ID --stage $STAGE --stage_id $STAGE_ID --label $LABEL --filter $FILTER --dest_id $DEST_ID --product_name $PRODUCT_NAME  --ds_dbhost $DS_DBHOST --ds_dbname $DS_DBNAME --dist_dir $DIST_DIR
 
     add_standard_args run
@@ -184,5 +186,5 @@
 
   stdout NULL
-  stderr $LOGDIR/rcserver.checkstatus.load.log
+  stderr $LOGSUBDIR/rcserver.checkstatus.load.log
 
   task.exec
@@ -241,9 +243,9 @@
 
     stdout NULL
-    stderr $LOGDIR/rcserver.checkstatus.run.log
+    stderr $LOGSUBDIR/rcserver.checkstatus.run.log
 
     book setword rcPendingDest $pageName pantaskState RUN
     book getword rcPendingDest $pageName dest_id -var DEST_ID
-    book getword rcPendingDest $pageName prod_id -var PROD_ID
+    book getword rcPendingDest $pageName dest_id -var DEST_ID
     book getword rcPendingDest $pageName status_uri -var STATUS_URI
     book getword rcPendingDest $pageName last_fileset -var LAST_FILESET
@@ -252,5 +254,5 @@
     host anyhost
 
-    $run = rcserver_checkstatus.pl --dest_id $DEST_ID --prod_id $PROD_ID --status_uri $STATUS_URI --last_fileset $LAST_FILESET
+    $run = rcserver_checkstatus.pl --dest_id $DEST_ID --dest_id $DEST_ID --status_uri $STATUS_URI --last_fileset $LAST_FILESET
     add_standard_args run
 
Index: branches/eam_branches/20090820/ippTasks/register.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/register.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/register.pro	(revision 25766)
@@ -217,4 +217,6 @@
     book getword regPendingImfile $pageName tmp_class_id -var TMP_CLASS_ID
     book getword regPendingImfile $pageName uri          -var URI
+    book getword regPendingImfile $pageName bytes        -var BYTES
+    book getword regPendingImfile $pageName md5sum       -var MD5SUM
     book getword regPendingImfile $pageName workdir      -var WORKDIR_TEMPLATE
     book getword regPendingImfile $pageName dbname       -var DBNAME
@@ -244,5 +246,5 @@
 
     # XXX register_imfile.pl differs from the standard script : it does not have an 'outroot' argument, and it does not take '--redirect'
-    $run = register_imfile.pl --exp_id $EXP_ID --tmp_class_id $TMP_CLASS_ID --tmp_exp_name $TMP_EXP_NAME --uri $URI --logfile $logfile
+    $run = register_imfile.pl --exp_id $EXP_ID --tmp_class_id $TMP_CLASS_ID --tmp_exp_name $TMP_EXP_NAME --uri $URI --logfile $logfile --bytes $BYTES --md5sum $MD5SUM
     add_standard_args run
 
Index: branches/eam_branches/20090820/ippTasks/simtest.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/simtest.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/simtest.pro	(revision 25766)
@@ -85,7 +85,10 @@
 
       ## XXX this will need to be optional as well 
+      ## we could use the book to find OBSTYPE = OBJECT, get CENTER.RA, CENTER.DEC 
+      ## or else we could have ppSimSequence generate an appropriate skycells call
       file TESS/Images.dat found
       if ($found == 0)
-        exec skycells -mode square -level 8 -scale 0.2 -D CATDIR TESS
+        # this command is approriate only to the dither pattern and camera define in simtest.basic.config
+        exec skycells -mode local -scale 0.2 -center 270.75 -23.70 -size 0.3 0.3 -nx 3 -ny 3 -D CATDIR TESS
       end
     end
Index: branches/eam_branches/20090820/ippTasks/site.mhpcc.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/site.mhpcc.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/site.mhpcc.pro	(revision 25766)
@@ -14,4 +14,5 @@
   controller host add ipp023
   controller host add ipp024
+  controller host add ipp025
   controller host add ipp026
   controller host add ipp028
@@ -39,5 +40,5 @@
   controller host add ipp051
   controller host add ipp052
-  controller host add ipp053
+#  controller host add ipp053
 end
 
@@ -65,5 +66,5 @@
  if ("$1" == "on")
   $NEBULOUS = 1
-  $default_host     = ipp023
+  $default_host     = any
   $workdir_template = neb://@HOST@.0
  else
Index: branches/eam_branches/20090820/ippTasks/summit.copy.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/summit.copy.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/summit.copy.pro	(revision 25766)
@@ -380,6 +380,10 @@
     periods      -poll     0.05
     periods      -timeout  650
-    # trage       16:00 23:59
-    # trage       00:00 04:00
+    trange        -reset
+    # only active in the night (18:00 to 06:00 HST, times are UT):
+    # trange      04:00 16:00
+    # only active in the day (06:00 to 18:00 HST, times are UT):
+    # trange        16:00 23:59
+    # trange        00:00 04:00
 
     task.exec
@@ -449,4 +453,5 @@
         end
         if (("$MD5SUM" != "NULL") && ("$MD5SUM" != "0") && (not($COMPRESS)))
+# && (($YEAR > 2008) || (("$YEAR" = "2007") && ($MONTH > 8))))
             $run = $run --md5 $MD5SUM
         end
Index: branches/eam_branches/20090820/ippTasks/warp.pro
===================================================================
--- branches/eam_branches/20090820/ippTasks/warp.pro	(revision 25206)
+++ branches/eam_branches/20090820/ippTasks/warp.pro	(revision 25766)
@@ -49,4 +49,10 @@
     active true
   end
+  task warp.revert.overlap
+    active true
+  end
+  task warp.revert.warped
+    active true
+  end
 end
 
@@ -66,4 +72,10 @@
   end
   task warp.advancerun
+    active false
+  end
+  task warp.revert.overlap
+    active false
+  end
+  task warp.revert.warped
     active false
   end
Index: branches/eam_branches/20090820/ippTools/configure.ac
===================================================================
--- branches/eam_branches/20090820/ippTools/configure.ac	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/configure.ac	(revision 25766)
@@ -18,5 +18,5 @@
 PKG_CHECK_MODULES([PSLIB], [pslib >= 1.1.0])
 PKG_CHECK_MODULES([PSMODULES], [psmodules >= 1.1.0])
-PKG_CHECK_MODULES([IPPDB], [ippdb >= 1.1.54]) 
+PKG_CHECK_MODULES([IPPDB], [ippdb >= 1.1.55]) 
 
 PXTOOLS_CFLAGS="${PSLIB_CFLAGS=} ${PSMODULES_CFLAGS=} ${IPPDB_CFLAGS=}"
Index: branches/eam_branches/20090820/ippTools/doc/addstar_flow.txt
===================================================================
--- branches/eam_branches/20090820/ippTools/doc/addstar_flow.txt	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/doc/addstar_flow.txt	(revision 25766)
@@ -0,0 +1,34 @@
+### Set up the addRun row during the previous stage
+#>> camtool.c @ addprocessedexpMode(pxConfig *config)
+camtool -cam_id $cam_id -addprocessedexp ...
+
+### Catch that things now need to be added. This should check for magic_status as well, probably.
+#>> add.pro / addtool.c / addtoolConfig.c
+addtool -pendingsmf 
+#addMe METADATA
+#  add_id        S64      5
+#END
+
+### Run the addstar script.
+#>> addstar_run.pl
+addstar_run.pl --add_id $add_id --camera $camera --camroot=$camroot --dvodb $DVODB
+   addtool -pendingsmf -add_id $add_id
+#addMe METADATA
+#  add_id        S64      5
+#  workdir       STR      /path/to/workdir
+#  
+#END
+
+   ppConfigDump -camera $camera -recipe ADDSTAR $recipt_addstar -dump-recipe ADDSTAR -
+   addstar -D CAMERA $camdir -update -D CATDIR $dvodbReal $realFile
+   addtool -add_id $add_id -addprocessedsmf ...
+   addtool -add_id $add_id -updaterun -state full
+
+### Reverting
+#>> addtool.c
+addtool -revertprocessedsmf ...
+
+   
+
+
+
Index: branches/eam_branches/20090820/ippTools/share/Makefile.am
===================================================================
--- branches/eam_branches/20090820/ippTools/share/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/Makefile.am	(revision 25766)
@@ -4,4 +4,8 @@
 
 dist_pkgdata_DATA = \
+     addtool_find_pendingexp.sql \
+     addtool_queue_cam_id.sql \
+     addtool_reset_faulted_runs.sql \
+     addtool_revertprocessedexp.sql \
      camtool_donecleanup.sql \
      camtool_find_chip_id.sql \
@@ -43,4 +47,5 @@
      dettool_normalizedstat.sql \
      dettool_pending.sql \
+     dettool_pendingcleanup_detrunsummary.sql \
      dettool_pendingcleanup_normalizedexp.sql \
      dettool_pendingcleanup_normalizedimfile.sql \
@@ -105,5 +110,13 @@
      disttool_definebyquery_stack.sql \
      disttool_definebyquery_warp.sql \
-     disttool_pendingcomponent.sql \
+     disttool_defineinterest.sql \
+     disttool_listinterests.sql \
+     disttool_pending_camera.sql \
+     disttool_pending_chip.sql \
+     disttool_pending_diff.sql \
+     disttool_pending_fake.sql \
+     disttool_pending_raw.sql \
+     disttool_pending_stack.sql \
+     disttool_pending_warp.sql \
      disttool_pendingfileset.sql \
      disttool_pendingdest.sql \
@@ -111,6 +124,6 @@
      disttool_queuercrun.sql \
      disttool_revertrcrun.sql \
-     disttool_revertrun_update.sql \
-     disttool_revertrun_delete.sql \
+     disttool_revertrun.sql \
+     disttool_revertcomponent.sql \
      disttool_revertfileset.sql \
      disttool_toadvance.sql \
@@ -137,9 +150,9 @@
      flatcorr_dropcamera.sql \
      magictool_addmask.sql \
-     magictool_censor_raw.sql \
-     magictool_censor_chip.sql \
-     magictool_censor_camera.sql \
-     magictool_censor_warp.sql \
-     magictool_censor_diff.sql \
+     magictool_restore_camera.sql \
+     magictool_restore_chip.sql \
+     magictool_restore_diff.sql \
+     magictool_restore_raw.sql \
+     magictool_restore_warp.sql \
      magictool_create_tmp_warpcomplete.sql \
      magictool_definebyquery_insert.sql \
@@ -160,4 +173,5 @@
      magictool_revertnode.sql \
      magicdstool_completed_runs.sql \
+     magicdstool_completedrevert.sql \
      magicdstool_definebyquery_raw.sql \
      magicdstool_definebyquery_chip.sql \
@@ -167,7 +181,11 @@
      magicdstool_getrunids.sql \
      magicdstool_getskycells.sql \
-     magicdstool_todestreak.sql \
+     magicdstool_revertdestreakedfile.sql \
+     magicdstool_todestreak_camera.sql \
+     magicdstool_todestreak_chip.sql \
+     magicdstool_todestreak_diff.sql \
+     magicdstool_todestreak_raw.sql \
+     magicdstool_todestreak_warp.sql \
      magicdstool_toremove.sql \
-     magicdstool_torestore.sql \
      magicdstool_torevert_raw.sql \
      magicdstool_torevert_chip.sql \
@@ -175,8 +193,13 @@
      magicdstool_torevert_warp.sql \
      magicdstool_torevert_diff.sql \
+     pstamptool_completedreq.sql \
      pstamptool_datastore.sql \
+     pstamptool_listjob.sql \
      pstamptool_pendingjob.sql \
      pstamptool_pendingreq.sql \
      pstamptool_project.sql \
+     pstamptool_revertjob.sql \
+     pstamptool_revertreq.sql \
+     pstamptool_revertreq_deletejobs.sql \
      pxadmin_create_tables.sql \
      pxadmin_create_mirror_tables.sql \
Index: branches/eam_branches/20090820/ippTools/share/addtool_find_pendingexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/addtool_find_pendingexp.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/addtool_find_pendingexp.sql	(revision 25766)
@@ -0,0 +1,26 @@
+SELECT
+    addRun.*,
+    rawExp.exp_tag,
+    rawExp.exp_id,
+    rawExp.exp_name,
+    rawExp.camera,
+    rawExp.telescope,
+    rawExp.filelevel
+FROM addRun
+JOIN camRun
+    USING(cam_id)
+JOIN chipRun
+    USING(chip_id)
+JOIN chipProcessedImfile
+    USING(chip_id)
+JOIN rawExp
+    ON chipRun.exp_id = rawExp.exp_id
+LEFT JOIN addProcessedExp
+    USING(add_id)
+LEFT JOIN addMask
+    ON addRun.label = addMask.label
+WHERE
+    camRun.state = 'full'
+    AND ((addRun.state = 'new' AND addProcessedExp.add_id IS NULL) OR addRun.state = 'update')
+    AND addMask.label IS NULL
+
Index: branches/eam_branches/20090820/ippTools/share/addtool_queue_cam_id.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/addtool_queue_cam_id.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/addtool_queue_cam_id.sql	(revision 25766)
@@ -0,0 +1,14 @@
+INSERT INTO addRun
+    SELECT
+        0,              -- add_id
+        cam_id,         -- cam_id
+        '%s',           -- state
+        '%s',           -- workdir
+	'%s',           -- workdir_state
+        '%s',           -- label
+        '%s',           -- dvodb 
+	0               -- magicked
+    FROM camRun
+    WHERE
+        camRun.state = 'full'
+        AND camRun.cam_id = %lld
Index: branches/eam_branches/20090820/ippTools/share/addtool_reset_faulted_runs.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/addtool_reset_faulted_runs.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/addtool_reset_faulted_runs.sql	(revision 25766)
@@ -0,0 +1,8 @@
+UPDATE addRun, addProcessedExp, camRun, chipRun, rawExp
+SET addRun.state = 'new'
+WHERE
+    addRun.add_id = addProcessedExp.add_id
+    AND addRun.cam_id = camRun.cam_id
+    AND camRun.chip_id = chipRun.chip_id
+    AND chipRun.exp_id = rawExp.exp_id
+    AND addProcessedExp.fault != 0
Index: branches/eam_branches/20090820/ippTools/share/addtool_revertprocessedexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/addtool_revertprocessedexp.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/addtool_revertprocessedexp.sql	(revision 25766)
@@ -0,0 +1,8 @@
+DELETE FROM addProcessedExp
+USING addProcessedExp, addRun, camRun, chipRun, rawExp
+WHERE
+    addRun.add_id = addProcessedExp.add_id
+    AND addRun.cam_id = camRun.cam_id
+    AND camRun.chip_id = chipRun.chip_id
+    AND chipRun.exp_id = rawExp.exp_id
+    AND addProcessedExp.fault != 0
Index: branches/eam_branches/20090820/ippTools/share/camtool_pendingcleanupexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/camtool_pendingcleanupexp.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/camtool_pendingcleanupexp.sql	(revision 25766)
@@ -13,4 +13,4 @@
     USING(cam_id)
 WHERE
-    (camRun.state = 'goto_cleaned' OR camRun.state = 'goto_purged')
+    (camRun.state = 'goto_cleaned' OR camRun.state = 'goto_purged' OR camRun.state = 'goto_scrubbed')
 
Index: branches/eam_branches/20090820/ippTools/share/camtool_pendingcleanuprun.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/camtool_pendingcleanuprun.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/camtool_pendingcleanuprun.sql	(revision 25766)
@@ -9,3 +9,3 @@
 USING (exp_id)
 WHERE
-    (camRun.state = 'goto_cleaned' OR camRun.state = 'goto_purged')
+    (camRun.state = 'goto_cleaned' OR camRun.state = 'goto_purged' OR camRun.state = 'goto_scrubbed')
Index: branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedexp.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedexp.sql	(revision 25766)
@@ -0,0 +1,11 @@
+SELECT
+    detNormalizedExp.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detNormalizedExp
+    USING(det_id,iteration)
+WHERE
+    (detNormalizedExp.data_state = 'cleaned'
+     OR detNormalizedExp.data_state = 'scrubbed'
+     OR detNormalizedExp.data_state = 'purged')
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedimfile.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedimfile.sql	(revision 25766)
@@ -0,0 +1,11 @@
+SELECT
+    detNormalizedImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detNormalizedImfile
+    USING(det_id,iteration)
+WHERE
+    (detNormalizedImfile.data_state = 'cleaned'
+     OR detNormalizedImfile.data_state = 'scrubbed'
+     OR detNormalizedImfile.data_state = 'purged')
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedstat.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedstat.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_normalizedstat.sql	(revision 25766)
@@ -0,0 +1,11 @@
+SELECT
+    detNormalizedStatImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detNormalizedStatImfile
+    USING(det_id,iteration)
+WHERE
+    (detNormalizedStatImfile.data_state = 'cleaned'
+     OR detNormalizedStatImfile.data_state = 'scrubbed'
+     OR detNormalizedStatImfile.data_state = 'purged')
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_processedexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_processedexp.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_processedexp.sql	(revision 25766)
@@ -0,0 +1,11 @@
+-- need to restrict to a single detRunSummary (require all to say 'cleaned'?)
+SELECT
+    detProcessedExp.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detProcessedExp
+    USING(det_id)
+WHERE
+    (detProcessedExp.data_state = 'cleaned'
+     OR detProcessedExp.data_state = 'scrubbed'
+     OR detProcessedExp.data_state = 'purged')
Index: branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_processedimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_processedimfile.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_processedimfile.sql	(revision 25766)
@@ -0,0 +1,11 @@
+-- need to restrict to a single detRunSummary (require all to say 'cleaned'?)
+SELECT
+    detProcessedImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detProcessedImfile
+    USING(det_id)
+WHERE
+    (detProcessedImfile.data_state = 'cleaned'
+     OR detProcessedImfile.data_state = 'scrubbed'
+     OR detProcessedImfile.data_state = 'purged')
Index: branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_residexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_residexp.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_residexp.sql	(revision 25766)
@@ -0,0 +1,10 @@
+SELECT
+    detResidExp.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detResidExp
+    USING(det_id,iteration)
+WHERE
+    (detResidExp.data_state = 'cleaned'
+     OR detResidExp.data_state = 'scrubbed'
+     OR detResidExp.data_state = 'purged')
Index: branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_residimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_residimfile.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_residimfile.sql	(revision 25766)
@@ -0,0 +1,12 @@
+SELECT
+    detResidImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detResidImfile
+    USING(det_id,iteration)
+WHERE
+    (detResidImfile.data_state = 'cleaned'
+     OR detResidImfile.data_state = 'scrubbed'
+     OR detResidImfile.data_state = 'purged')
+
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_stacked.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_stacked.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_donecleanup_stacked.sql	(revision 25766)
@@ -0,0 +1,10 @@
+SELECT
+    detStackedImfile.*,
+    detRunSummary.data_state
+FROM detRunSummary
+JOIN detStackedImfile
+     USING(det_id,iteration)
+WHERE
+     (detStackedImfile.data_state = 'cleaned'
+      OR detStackedImfile.data_state = 'scrubbed'
+      OR detStackedImfile.data_state = 'purged')
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_detrunsummary.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_detrunsummary.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_detrunsummary.sql	(revision 25766)
@@ -0,0 +1,42 @@
+SELECT DISTINCT detRunSummary.*
+FROM detRunSummary
+     JOIN detProcessedImfile USING (det_id) 
+     JOIN detProcessedExp USING (det_id) 
+     JOIN detStackedImfile USING (det_id,iteration)
+     JOIN detResidExp USING (det_id,iteration) 
+     JOIN detResidImfile USING (det_id,iteration) 
+     JOIN detNormalizedStatImfile USING (det_id,iteration) 
+     JOIN detNormalizedImfile USING (det_id,iteration) 
+     JOIN detNormalizedExp USING (det_id,iteration) 
+WHERE (!(
+       (
+        detRunSummary.data_state = 'full' OR
+	detRunSummary.data_state = 'cleaned'
+       ) OR
+       (
+        !((detProcessedImfile.data_state = 'cleaned' OR
+           detProcessedImfile.data_state = 'scrubbed' OR
+           detProcessedImfile.data_state = 'purged') AND
+          (detProcessedExp.data_state = 'cleaned' OR
+           detProcessedExp.data_state = 'scrubbed' OR
+           detProcessedExp.data_state = 'purged') AND
+          (detStackedImfile.data_state = 'cleaned' OR
+           detStackedImfile.data_state = 'scrubbed' OR
+           detStackedImfile.data_state = 'purged') AND
+          (detResidExp.data_state = 'cleaned' OR
+           detResidExp.data_state = 'scrubbed' OR
+           detResidExp.data_state = 'purged') AND
+          (detResidImfile.data_state = 'cleaned' OR
+           detResidImfile.data_state = 'scrubbed' OR
+           detResidImfile.data_state = 'purged') AND
+          (detNormalizedStatImfile.data_state = 'cleaned' OR
+           detNormalizedStatImfile.data_state = 'scrubbed' OR
+           detNormalizedStatImfile.data_state = 'purged') AND
+          (detNormalizedImfile.data_state = 'cleaned' OR
+           detNormalizedImfile.data_state = 'scrubbed' OR
+           detNormalizedImfile.data_state = 'purged') AND
+          (detNormalizedExp.data_state = 'cleaned' OR
+           detNormalizedExp.data_state = 'scrubbed' OR
+           detNormalizedExp.data_state = 'purged')
+	 )
+       )))
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedexp.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedexp.sql	(revision 25766)
@@ -1,9 +1,21 @@
 SELECT
     detNormalizedExp.*,
-    detRunSummary.data_state
+    rawExp.camera    
 FROM detRunSummary
 JOIN detNormalizedExp
     USING(det_id,iteration)
+JOIN detInputExp
+     USING(det_id,iteration)
+JOIN rawExp
+     USING(exp_id)
 WHERE
-    detRunSummary.data_state = 'goto_cleaned'
-AND detNormalizedExp.data_state = 'full'
+    ((detRunSummary.data_state = 'goto_cleaned'
+      AND detNormalizedExp.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_scrubbed'
+      AND detNormalizedExp.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_purged'
+      AND detNormalizedExp.data_state = 'full')
+     OR detNormalizedExp.data_state = 'goto_cleaned'
+     OR detNormalizedExp.data_state = 'goto_scrubbed'
+     OR detNormalizedExp.data_state = 'goto_purged')
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedimfile.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedimfile.sql	(revision 25766)
@@ -1,9 +1,21 @@
-SELECT
+SELECT DISTINCT
     detNormalizedImfile.*,
-    detRunSummary.data_state
+    rawExp.camera
 FROM detRunSummary
 JOIN detNormalizedImfile
     USING(det_id,iteration)
+JOIN detInputExp
+     USING(det_id,iteration)
+JOIN rawExp
+     USING(exp_id)
 WHERE
-    detRunSummary.data_state = 'goto_cleaned'
-AND detNormalizedImfile.data_state = 'full'
+    ((detRunSummary.data_state = 'goto_cleaned'
+      AND detNormalizedImfile.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_scrubbed'
+      AND detNormalizedImfile.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_purged'
+      AND detNormalizedImfile.data_state = 'full')
+     OR detNormalizedImfile.data_state = 'goto_cleaned'
+     OR detNormalizedImfile.data_state = 'goto_scrubbed'
+     OR detNormalizedImfile.data_state = 'goto_purged')
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedstat.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedstat.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_normalizedstat.sql	(revision 25766)
@@ -1,9 +1,21 @@
-SELECT
+SELECT DISTINCT
     detNormalizedStatImfile.*,
-    detRunSummary.data_state
+    rawExp.camera
 FROM detRunSummary
 JOIN detNormalizedStatImfile
     USING(det_id,iteration)
+JOIN detInputExp
+     USING(det_id,iteration)
+JOIN rawExp
+     USING(exp_id)
 WHERE
-    detRunSummary.data_state = 'goto_cleaned'
-AND detNormalizedStatImfile.data_state = 'full'
+    ((detRunSummary.data_state = 'goto_cleaned'
+      AND detNormalizedStatImfile.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_scrubbed'
+      AND detNormalizedStatImfile.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_purged'
+      AND detNormalizedStatImfile.data_state = 'full')
+     OR detNormalizedStatImfile.data_state = 'goto_cleaned'
+     OR detNormalizedStatImfile.data_state = 'goto_scrubbed'
+     OR detNormalizedStatImfile.data_state = 'goto_purged')
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_processedexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_processedexp.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_processedexp.sql	(revision 25766)
@@ -2,9 +2,18 @@
 SELECT
     detProcessedExp.*,
-    detRunSummary.data_state
+    rawExp.camera
 FROM detRunSummary
 JOIN detProcessedExp
     USING(det_id)
+JOIN rawExp
+     USING(exp_id)
 WHERE
-    detRunSummary.data_state = 'goto_cleaned'
-AND detProcessedExp.data_state = 'full'
+    ((detRunSummary.data_state = 'goto_cleaned'
+      AND detProcessedExp.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_scrubbed'
+         AND detProcessedExp.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_purged'
+         AND detProcessedExp.data_state = 'full')
+     OR detProcessedExp.data_state = 'goto_cleaned'
+     OR detProcessedExp.data_state = 'goto_scrubbed'
+     OR detProcessedExp.data_state = 'goto_purged')
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_processedimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_processedimfile.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_processedimfile.sql	(revision 25766)
@@ -1,10 +1,15 @@
--- need to restrict to a single detRunSummary (require all to say 'cleaned'?)
 SELECT
     detProcessedImfile.*,
-    detRunSummary.data_state
+    rawExp.camera
 FROM detRunSummary
 JOIN detProcessedImfile
     USING(det_id)
+JOIN detInputExp
+     USING(det_id,iteration,exp_id)
+JOIN rawExp
+     USING(exp_id)
 WHERE
-    detRunSummary.data_state = 'goto_cleaned'
-AND detProcessedImfile.data_state = 'full'
+     (detProcessedImfile.data_state = 'goto_cleaned'
+     OR detProcessedImfile.data_state = 'goto_scrubbed'
+     OR detProcessedImfile.data_state = 'goto_purged')
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_residexp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_residexp.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_residexp.sql	(revision 25766)
@@ -1,9 +1,20 @@
 SELECT
     detResidExp.*,
-    detRunSummary.data_state
+    rawExp.camera
 FROM detRunSummary
 JOIN detResidExp
     USING(det_id,iteration)
+JOIN detInputExp
+     USING(det_id,iteration,exp_id)
+JOIN rawExp
+    USING(exp_id)
 WHERE
-    detRunSummary.data_state = 'goto_cleaned'
-AND detResidExp.data_state = 'full'
+    ((detRunSummary.data_state = 'goto_cleaned'
+      AND detResidExp.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_scrubbed'
+         AND detResidExp.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_purged'
+         AND detResidExp.data_state = 'full')
+     OR detResidExp.data_state = 'goto_cleaned'
+     OR detResidExp.data_state = 'goto_scrubbed'
+     OR detResidExp.data_state = 'goto_purged')
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_residimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_residimfile.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_residimfile.sql	(revision 25766)
@@ -1,9 +1,22 @@
 SELECT
     detResidImfile.*,
-    detRunSummary.data_state
+    rawExp.camera
 FROM detRunSummary
 JOIN detResidImfile
     USING(det_id,iteration)
+JOIN detInputExp
+    USING(det_id,iteration,exp_id)
+JOIN rawExp
+    USING(exp_id)
 WHERE
-    detRunSummary.data_state = 'goto_cleaned'
-AND detResidImfile.data_state = 'full'
+    ((detRunSummary.data_state = 'goto_cleaned'
+      AND detResidImfile.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_scrubbed'
+      AND detResidImfile.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_purged'
+      AND detResidImfile.data_state = 'full')
+     OR detResidImfile.data_state = 'goto_cleaned'
+     OR detResidImfile.data_state = 'goto_scrubbed'
+     OR detResidImfile.data_state = 'goto_purged')
+
+
Index: branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_stacked.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_stacked.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/dettool_pendingcleanup_stacked.sql	(revision 25766)
@@ -1,9 +1,20 @@
-SELECT
+SELECT DISTINCT
     detStackedImfile.*,
-    detRunSummary.data_state
+    rawExp.camera
 FROM detRunSummary
 JOIN detStackedImfile
-    USING(det_id,iteration)
+     USING(det_id,iteration)
+JOIN detInputExp
+     USING(det_id,iteration)
+JOIN rawExp
+     USING(exp_id)
 WHERE
-    detRunSummary.data_state = 'goto_cleaned'
-AND detStackedImfile.data_state = 'full'
+    ((detRunSummary.data_state = 'goto_cleaned'
+      AND detStackedImfile.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_scrubbed'
+      AND detStackedImfile.data_state = 'full')
+     OR (detRunSummary.data_state = 'goto_purged'
+      AND detStackedImfile.data_state = 'full')
+     OR detStackedImfile.data_state = 'goto_cleaned'
+     OR detStackedImfile.data_state = 'goto_scrubbed'
+     OR detStackedImfile.data_state = 'goto_purged')
Index: branches/eam_branches/20090820/ippTools/share/difftool_completed_runs.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/difftool_completed_runs.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/difftool_completed_runs.sql	(revision 25766)
@@ -1,19 +1,16 @@
-SELECT DISTINCT
-    diff_id,
-    all_magicked as magicked
-FROM (
-    SELECT
-        COUNT(diffInputSkyfile.skycell_id), COUNT(diffSkyfile.skycell_id),
-        diffSkyfile.*,
-        SUM(!diffSkyfile.magicked) = 0 as all_magicked
-    FROM diffRun
-    JOIN diffInputSkyfile USING(diff_id)
-    LEFT JOIN diffSkyfile USING(diff_id, skycell_id)
-    WHERE 
-        diffRun.state = 'new'
-    GROUP BY
-        diffInputSkyfile.diff_id
-    HAVING
-        COUNT(diffInputSkyfile.skycell_id) = COUNT(diffSkyfile.skycell_id)
-        AND SUM(diffSkyfile.fault) = 0
-    ) as Foo
+SELECT
+    COUNT(diffInputSkyfile.skycell_id),
+    COUNT(diffSkyfile.skycell_id),
+    diffSkyfile.*,
+    SUM(!diffSkyfile.magicked) = 0 as all_magicked
+FROM diffRun
+JOIN diffInputSkyfile USING(diff_id)
+LEFT JOIN diffSkyfile USING(diff_id, skycell_id)
+WHERE
+    diffRun.state = 'new'
+-- WHERE hook %s
+GROUP BY
+    diffInputSkyfile.diff_id
+HAVING
+    COUNT(diffInputSkyfile.skycell_id) = COUNT(diffSkyfile.skycell_id)
+    AND SUM(diffSkyfile.fault) = 0
Index: branches/eam_branches/20090820/ippTools/share/difftool_definewarpstack_part1.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/difftool_definewarpstack_part1.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/difftool_definewarpstack_part1.sql	(revision 25766)
@@ -27,5 +27,6 @@
 ) AS diffExp USING(exp_id, warp_id)
 WHERE
-    warpSkyfile.fault = 0
+    warpRun.state = 'full'
+    AND warpSkyfile.fault = 0
     AND warpSkyfile.quality = 0
     -- warp where hook %s
Index: branches/eam_branches/20090820/ippTools/share/difftool_definewarpstack_part2.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/difftool_definewarpstack_part2.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/difftool_definewarpstack_part2.sql	(revision 25766)
@@ -30,4 +30,5 @@
 WHERE
     warpSkyfile.warp_id = %lld
+    AND warpRun.state = 'full'
     AND warpSkyfile.fault = 0
     AND warpSkyfile.quality = 0
Index: branches/eam_branches/20090820/ippTools/share/difftool_skyfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/difftool_skyfile.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/difftool_skyfile.sql	(revision 25766)
@@ -12,4 +12,5 @@
     -- The following are only valid for warps
     -- XXX This needs to be more clever to handle diffs between stacks
+    -- Zero points are appropriate for both forward and backward diffs
     camProcessedInput.zpt_obs,
     camProcessedInput.zpt_stdev,
@@ -19,7 +20,17 @@
     rawInput.camera,
     rawInput.exp_name AS exp_name_1,
+    rawInput.exp_id AS exp_id_1,
+    chipInput.chip_id AS chip_id_1,
+    camInput.cam_id AS cam_id_1,
+    fakeInput.fake_id AS fake_id_1,
+    camProcessedInput.sigma_ra AS sigma_ra_1,
+    camProcessedInput.sigma_dec AS sigma_dec_1,
     rawTemplate.exp_name AS exp_name_2,
-    rawInput.exp_id AS exp_id_1,
-    rawTemplate.exp_id AS exp_id_2
+    rawTemplate.exp_id AS exp_id_2,
+    chipTemplate.chip_id AS chip_id_2,
+    camTemplate.cam_id AS cam_id_2,
+    fakeTemplate.fake_id AS fake_id_2,
+    camProcessedTemplate.sigma_ra AS sigma_ra_2,
+    camProcessedTemplate.sigma_dec AS sigma_dec_2
 FROM diffRun
 JOIN diffSkyfile USING(diff_id)
@@ -43,4 +54,6 @@
 LEFT JOIN camRun AS camTemplate
     ON camTemplate.cam_id = fakeTemplate.cam_id
+LEFT JOIN camProcessedExp AS camProcessedTemplate
+    ON camProcessedTemplate.cam_id = camTemplate.cam_id
 LEFT JOIN chipRun AS chipTemplate
     ON chipTemplate.chip_id = camTemplate.chip_id
Index: branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_camera.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_camera.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_camera.sql	(revision 25766)
@@ -3,4 +3,5 @@
     camRun.cam_id as stage_id,
     rawExp.exp_name as run_tag,
+    camRun.magicked,
     distTarget.label,
     distTarget.target_id,
Index: branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_chip.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_chip.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_chip.sql	(revision 25766)
@@ -2,4 +2,5 @@
     'chip' as stage,
     chipRun.chip_id as stage_id,
+    chipRun.magicked,
     rawExp.exp_name as run_tag,
     chipRun.label,
Index: branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_diff.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_diff.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_diff.sql	(revision 25766)
@@ -2,4 +2,5 @@
     'diff' as stage,
     diffRun.diff_id AS stage_id,
+    diffRun.magicked,
     rawExp.exp_name as run_tag,
     distTarget.label,
Index: branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_fake.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_fake.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_fake.sql	(revision 25766)
@@ -2,4 +2,5 @@
     'fake' as stage,
     fakeRun.fake_id AS stage_id,
+    CAST(0 AS SIGNED) AS magicked,
     rawExp.exp_name as run_tag,
     distTarget.label,
Index: branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_raw.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_raw.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_raw.sql	(revision 25766)
@@ -3,4 +3,5 @@
     rawExp.exp_id AS stage_id,
     rawExp.exp_name AS run_tag,
+    rawExp.magicked,
     distTarget.label,
     distTarget.target_id,
Index: branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_stack.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_stack.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_stack.sql	(revision 25766)
@@ -2,4 +2,5 @@
     'stack' as stage,
     stackRun.stack_id AS stage_id,
+    CAST(0 AS SIGNED) AS magicked,
     -- run tag in the form 'stack.$skycell_id.$stack_id'
     CONCAT_WS('.', 'stack', stackRun.skycell_id, convert(stackRun.stack_id, CHAR)) as run_tag,
@@ -8,4 +9,5 @@
     distTarget.clean
 FROM stackRun
+JOIN stackSumSkyfile USING(stack_id)
 JOIN distTarget ON distTarget.stage = 'stack'
     AND stackRun.label = distTarget.label
@@ -19,2 +21,4 @@
     AND distRun.dist_id IS NULL
     AND ((stackRun.state = 'full') OR (distTarget.clean AND stackRun.state = 'cleaned'))
+    -- we shouldn't need to check fault. If faulted it shouldn't be full
+    AND (stackSumSkyfile.fault = 0 AND stackSumSkyfile.quality = 0)
Index: branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_warp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_warp.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_definebyquery_warp.sql	(revision 25766)
@@ -2,4 +2,5 @@
     'warp' as stage,
     warpRun.warp_id AS stage_id,
+    warpRun.magicked,
     rawExp.exp_name as run_tag,
     distTarget.label,
Index: branches/eam_branches/20090820/ippTools/share/disttool_defineinterest.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_defineinterest.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_defineinterest.sql	(revision 25766)
@@ -0,0 +1,6 @@
+INSERT INTO rcInterest
+    SELECT 0, dest_id, target_id, '@STATE@'
+    FROM distTarget
+        JOIN rcDestination
+        LEFT JOIN rcInterest USING(dest_id, target_id)
+    WHERE (int_id IS NULL)
Index: branches/eam_branches/20090820/ippTools/share/disttool_listinterests.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_listinterests.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_listinterests.sql	(revision 25766)
@@ -0,0 +1,13 @@
+SELECT 
+    int_id,
+    rcInterest.state AS state,
+    dest_id,
+    name AS dest_name,
+    rcDestination.state as dest_state,
+    label,
+    filter,
+    stage,
+    distTarget.state as target_state
+FROM rcInterest 
+    JOIN distTarget USING(target_id)
+    JOIN rcDestination USING(dest_id)
Index: branches/eam_branches/20090820/ippTools/share/disttool_pending_camera.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pending_camera.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_pending_camera.sql	(revision 25766)
@@ -0,0 +1,31 @@
+SELECT
+    distRun.dist_id,
+    distRun.label,
+    stage,
+    stage_id,
+    'exposure' AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    camProcessedExp.path_base,
+    CAST(NULL AS CHAR(255)) as chip_path_base,
+    camRun.state,
+    camRun.state AS data_state,
+    camProcessedExp.quality,
+    distRun.no_magic,
+    chipRun.magicked
+FROM distRun
+JOIN camRun ON camRun.cam_id = distRun.stage_id
+JOIN camProcessedExp USING(cam_id)
+JOIN chipRun USING(chip_id)
+-- JOIN chipProcessedImfile USING(exp_id, chip_id)
+JOIN rawExp using(exp_id)
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+--    AND chipProcessedImfile.class_id = distComponent.component
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'camera'
+    AND distComponent.dist_id IS NULL
+    AND (distRun.clean OR (chipRun.magicked AND camRun.magicked) OR distRun.no_magic)
+    AND (camRun.state = 'full' OR (distRun.clean AND camRun.state = 'cleaned'))
Index: branches/eam_branches/20090820/ippTools/share/disttool_pending_chip.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pending_chip.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_pending_chip.sql	(revision 25766)
@@ -0,0 +1,29 @@
+SELECT
+    distRun.dist_id,
+    distRun.label,
+    stage,
+    stage_id,
+    chipProcessedImfile.class_id AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    chipProcessedImfile.path_base,
+    chipProcessedImfile.path_base as chip_path_base,
+    chipRun.state,
+    chipProcessedImfile.data_state,
+    chipProcessedImfile.quality,
+    distRun.no_magic,
+    chipProcessedImfile.magicked
+FROM distRun
+JOIN chipRun ON chipRun.chip_id = distRun.stage_id
+JOIN rawExp using(exp_id)
+JOIN chipProcessedImfile ON chipProcessedImfile.chip_id = stage_id
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+    AND chipProcessedImfile.class_id = distComponent.component
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'chip'
+    AND distComponent.dist_id IS NULL
+    AND (distRun.clean OR chipRun.magicked OR distRun.no_magic)
+    AND (chipRun.state = 'full' OR (distRun.clean AND chipRun.state = 'cleaned'))
Index: branches/eam_branches/20090820/ippTools/share/disttool_pending_diff.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pending_diff.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_pending_diff.sql	(revision 25766)
@@ -0,0 +1,37 @@
+SELECT
+    distRun.dist_id,
+    distRun.label,
+    stage,
+    stage_id,
+    diffSkyfile.skycell_id AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    diffSkyfile.path_base,
+    CAST(NULL AS CHAR(255)) as chip_path_base,
+    diffRun.state,
+    -- data_state doesn't exist yet
+    -- diffSkyfile.data_state,
+    'full' AS data_state,
+    diffSkyfile.quality,
+    distRun.no_magic,
+    diffSkyfile.magicked
+FROM distRun
+JOIN diffRun ON stage_id = diff_id
+JOIN diffSkyfile using(diff_id)
+JOIN diffInputSkyfile USING(diff_id, skycell_id)
+JOIN warpRun
+    ON warpRun.warp_id = diffInputSkyfile.warp1
+JOIN fakeRun USING(fake_id)
+JOIN camRun USING(cam_id)
+JOIN chipRun USING(chip_id)
+JOIN rawExp USING(exp_id)
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+    AND diffSkyfile.skycell_id = distComponent.component
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'diff'
+    AND distComponent.dist_id IS NULL
+    AND (distRun.clean OR diffRun.magicked OR distRun.no_magic)
+    AND (diffRun.state = 'full' OR (distRun.clean AND diffRun.state = 'cleaned'))
Index: branches/eam_branches/20090820/ippTools/share/disttool_pending_fake.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pending_fake.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_pending_fake.sql	(revision 25766)
@@ -0,0 +1,29 @@
+SELECT
+    distRun.dist_id,
+    distRun.label,
+    stage,
+    stage_id,
+    fakeProcessedImfile.class_id AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    fakeProcessedImfile.path_base,
+    CAST(NULL AS CHAR(255)) AS chip_path_base,
+    fakeRun.state,
+    fakeRun.state AS data_state,
+    0 as quality,
+    distRun.no_magic,
+    0
+FROM distRun
+JOIN fakeRun ON fakeRun.fake_id = distRun.stage_id
+JOIN fakeProcessedImfile USING(fake_id)
+JOIN camRun USING(cam_id)
+JOIN chipRun USING(chip_id, exp_id)
+JOIN rawExp using(exp_id)
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+    AND fakeProcessedImfile.class_id = distComponent.component
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'fake'
+    AND distComponent.dist_id IS NULL
Index: branches/eam_branches/20090820/ippTools/share/disttool_pending_raw.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pending_raw.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_pending_raw.sql	(revision 25766)
@@ -0,0 +1,58 @@
+SELECT
+    distRun.dist_id,
+    distRun.label,
+    stage,
+    stage_id,
+    rawImfile.class_id AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    rawImfile.uri as path_base,         -- change this once rawImfile has path_base
+    chipProcessedImfile.path_base as chip_path_base,
+    CAST(NULL AS CHAR(255)) AS state,
+    CAST(NULL AS CHAR(255)) AS data_state,
+    0 as quality,
+    distRun.no_magic,
+    rawImfile.magicked
+FROM distRun
+JOIN rawExp ON rawExp.exp_id = stage_id
+JOIN rawImfile USING(exp_id)
+JOIN chipRun ON chipRun.exp_id = rawExp.exp_id and chipRun.magicked
+JOIN chipProcessedImfile
+    USING(chip_id, class_id)
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+    AND rawImfile.class_id = distComponent.component
+WHERE
+    distRun.state = 'new'
+    AND distRun.clean = 0
+    AND distRun.stage = 'raw'
+    AND distComponent.dist_id IS NULL
+    AND (rawExp.magicked OR distRun.no_magic)
+UNION
+    -- raw stage clean (dbinfo only)
+SELECT
+    distRun.dist_id,
+    distRun.label,
+    stage,
+    stage_id,
+    'exposure' AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    CAST(NULL AS CHAR(255)) AS path_base,
+    CAST(NULL AS CHAR(255)) AS chip_path_base,
+    CAST(NULL AS CHAR(255)) AS state,
+    CAST(NULL AS CHAR(255)) AS data_state,
+    0 as quality,
+    distRun.no_magic,
+    rawExp.magicked
+FROM distRun
+JOIN rawExp ON exp_id = stage_id
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'raw'
+    AND distRun.clean
+    AND distComponent.dist_id IS NULL
Index: branches/eam_branches/20090820/ippTools/share/disttool_pending_stack.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pending_stack.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_pending_stack.sql	(revision 25766)
@@ -0,0 +1,48 @@
+SELECT DISTINCT
+    distRun.dist_id,
+    distRun.label,
+    stage,
+    stage_id,
+    stackRun.skycell_id AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    stackSumSkyfile.path_base,
+    CAST(NULL AS CHAR(255)) as chip_path_base,
+    stackRun.state,
+    -- data_state doesn't exist yet
+    -- stackSumSkyfile.data_state,
+    'full' AS data_state,
+    stackSumSkyfile.quality,
+    1 AS no_magic,
+    0 AS magicked
+FROM distRun
+JOIN stackRun
+    ON stage_id = stack_id
+JOIN stackSumSkyfile
+    USING(stack_id)
+JOIN stackInputSkyfile
+    USING(stack_id)
+JOIN warpSkyfile
+    ON  stackInputSkyfile.warp_id = warpSkyfile.warp_id
+    AND stackRun.skycell_id       = warpSkyfile.skycell_id
+    AND stackRun.tess_id          = warpSkyfile.tess_id
+JOIN warpRun
+    ON warpRun.warp_id = warpSkyfile.warp_id
+JOIN fakeRun
+    USING(fake_id)
+JOIN camRun
+    USING(cam_id)
+JOIN chipRun
+    ON camRun.chip_id = chipRun.chip_id
+JOIN rawExp 
+     USING (exp_id)
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+    AND stackRun.skycell_id = distComponent.component
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'stack'
+    AND distComponent.dist_id IS NULL
+    AND (stackRun.state = 'full' OR (distRun.clean AND stackRun.state = 'cleaned'))
+    AND (stackSumSkyfile.fault = 0 AND stackSumSkyfile.quality = 0)
Index: branches/eam_branches/20090820/ippTools/share/disttool_pending_warp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pending_warp.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_pending_warp.sql	(revision 25766)
@@ -0,0 +1,32 @@
+SELECT
+    distRun.dist_id,
+    distRun.label,
+    stage,
+    stage_id,
+    warpSkyfile.skycell_id AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    warpSkyfile.path_base,
+    CAST(NULL AS CHAR(255)) as chip_path_base,
+    warpRun.state,
+    warpSkyfile.data_state,
+    warpSkyfile.quality,
+    distRun.no_magic,
+    warpSkyfile.magicked
+FROM distRun
+JOIN warpRun ON stage_id = warp_id
+JOIN warpSkyfile using(warp_id)
+JOIN fakeRun USING(fake_id)
+JOIN camRun USING(cam_id)
+JOIN chipRun ON camRun.chip_id = chipRun.chip_id
+JOIN rawExp using(exp_id)
+LEFT JOIN distComponent 
+    ON distRun.dist_id = distComponent.dist_id 
+    AND warpSkyfile.skycell_id = distComponent.component
+WHERE
+    distRun.state = 'new'
+    AND distRun.stage = 'warp'
+    AND distComponent.dist_id IS NULL
+    AND (distRun.clean OR warpRun.magicked OR distRun.no_magic)
+    AND (warpRun.state = 'full' OR (distRun.clean AND warpRun.state = 'cleaned'))
Index: branches/eam_branches/20090820/ippTools/share/disttool_pendingcomponent.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pendingcomponent.sql	(revision 25206)
+++ 	(revision )
@@ -1,283 +1,0 @@
-SELECT * FROM (
-    -- raw stage
-SELECT
-    distRun.dist_id,
-    distRun.label,
-    stage,
-    stage_id,
-    rawImfile.class_id AS component,
-    clean,
-    rawExp.camera,
-    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
-    rawImfile.uri as path_base,         -- change this once rawImfile has path_base
-    chipProcessedImfile.path_base as chip_path_base,
-    NULL as state,
-    NULL as data_state,
-    0 as quality,
-    distRun.no_magic,
-    rawImfile.magicked
-FROM distRun
-JOIN rawExp ON rawExp.exp_id = stage_id
-JOIN rawImfile USING(exp_id)
-JOIN chipRun ON chipRun.exp_id = rawExp.exp_id and chipRun.magicked
-JOIN chipProcessedImfile
-    USING(chip_id, class_id)
-LEFT JOIN distComponent 
-    ON distRun.dist_id = distComponent.dist_id 
-    AND rawImfile.class_id = distComponent.component
-WHERE
-    distRun.state = 'new'
-    AND distRun.clean = 0
-    AND distRun.stage = 'raw'
-    AND distComponent.dist_id IS NULL
-    AND (rawExp.magicked OR distRun.no_magic)
-    -- where hook 1 %s
-UNION
-    -- raw stage clean (dbinfo only)
-SELECT
-    distRun.dist_id,
-    distRun.label,
-    stage,
-    stage_id,
-    'exposure' AS component,
-    clean,
-    rawExp.camera,
-    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
-    NULL,
-    NULL,
-    NULL as state,
-    NULL as data_state,
-    0 as quality,
-    distRun.no_magic,
-    rawExp.magicked
-FROM distRun
-JOIN rawExp ON exp_id = stage_id
-LEFT JOIN distComponent 
-    ON distRun.dist_id = distComponent.dist_id 
-WHERE
-    distRun.state = 'new'
-    AND distRun.stage = 'raw'
-    AND distRun.clean
-    AND distComponent.dist_id IS NULL
-    -- where hook 2 %s
-
--- chip stage
-UNION
-SELECT
-    distRun.dist_id,
-    distRun.label,
-    stage,
-    stage_id,
-    chipProcessedImfile.class_id AS component,
-    clean,
-    rawExp.camera,
-    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
-    chipProcessedImfile.path_base,
-    chipProcessedImfile.path_base as chip_path_base,
-    chipRun.state,
-    chipProcessedImfile.data_state,
-    chipProcessedImfile.quality,
-    distRun.no_magic,
-    chipProcessedImfile.magicked
-FROM distRun
-JOIN chipRun ON chipRun.chip_id = distRun.stage_id
-JOIN rawExp using(exp_id)
-JOIN chipProcessedImfile ON chipProcessedImfile.chip_id = stage_id
-LEFT JOIN distComponent 
-    ON distRun.dist_id = distComponent.dist_id 
-    AND chipProcessedImfile.class_id = distComponent.component
-WHERE
-    distRun.state = 'new'
-    AND distRun.stage = 'chip'
-    AND distComponent.dist_id IS NULL
-    AND (distRun.clean OR chipRun.magicked OR distRun.no_magic)
-    AND (chipRun.state = 'full' OR (distRun.clean AND chipRun.state = 'cleaned'))
-    -- where hook 3 %s
-UNION
-SELECT
-    distRun.dist_id,
-    distRun.label,
-    stage,
-    stage_id,
-    'exposure' AS component,
---    chipProcessedImfile.class_id AS component,
-    clean,
-    rawExp.camera,
-    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
-    camProcessedExp.path_base,
-    NULL as chip_path_base,
-    camRun.state,
-    NULL,
-    camProcessedExp.quality,
-    distRun.no_magic,
-    chipRun.magicked
-FROM distRun
-JOIN camRun ON camRun.cam_id = distRun.stage_id
-JOIN camProcessedExp USING(cam_id)
-JOIN chipRun USING(chip_id)
--- JOIN chipProcessedImfile USING(exp_id, chip_id)
-JOIN rawExp using(exp_id)
-LEFT JOIN distComponent 
-    ON distRun.dist_id = distComponent.dist_id 
---    AND chipProcessedImfile.class_id = distComponent.component
-WHERE
-    distRun.state = 'new'
-    AND distRun.stage = 'camera'
-    AND distComponent.dist_id IS NULL
-    AND (distRun.clean OR (chipRun.magicked AND camRun.magicked) OR distRun.no_magic)
-    AND (camRun.state = 'full' OR (distRun.clean AND camRun.state = 'cleaned'))
-    -- where hook 4 %s
-UNION
-SELECT
-    distRun.dist_id,
-    distRun.label,
-    stage,
-    stage_id,
-    fakeProcessedImfile.class_id AS component,
-    clean,
-    rawExp.camera,
-    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
-    fakeProcessedImfile.path_base,
-    NULL,
-    fakeRun.state,
-    NULL,
-    0 as quality,
-    distRun.no_magic,
-    0
-FROM distRun
-JOIN fakeRun ON fakeRun.fake_id = distRun.stage_id
-JOIN fakeProcessedImfile USING(fake_id)
-JOIN camRun USING(cam_id)
-JOIN chipRun USING(chip_id, exp_id)
-JOIN rawExp using(exp_id)
-LEFT JOIN distComponent 
-    ON distRun.dist_id = distComponent.dist_id 
-    AND fakeProcessedImfile.class_id = distComponent.component
-WHERE
-    distRun.state = 'new'
-    AND distRun.stage = 'fake'
-    AND distComponent.dist_id IS NULL
-    -- where hook 5 %s
-UNION
-SELECT
-    distRun.dist_id,
-    distRun.label,
-    stage,
-    stage_id,
-    warpSkyfile.skycell_id AS component,
-    clean,
-    rawExp.camera,
-    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
-    warpSkyfile.path_base,
-    NULL as chip_path_base,
-    warpRun.state,
-    warpSkyfile.data_state,
-    warpSkyfile.quality,
-    distRun.no_magic,
-    warpSkyfile.magicked
-FROM distRun
-JOIN warpRun ON stage_id = warp_id
-JOIN warpSkyfile using(warp_id)
-JOIN fakeRun USING(fake_id)
-JOIN camRun USING(cam_id)
-JOIN chipRun ON camRun.chip_id = chipRun.chip_id
-JOIN rawExp using(exp_id)
-LEFT JOIN distComponent 
-    ON distRun.dist_id = distComponent.dist_id 
-    AND warpSkyfile.skycell_id = distComponent.component
-WHERE
-    distRun.state = 'new'
-    AND distRun.stage = 'warp'
-    AND distComponent.dist_id IS NULL
-    AND (distRun.clean OR warpRun.magicked OR distRun.no_magic)
-    AND (warpRun.state = 'full' OR (distRun.clean AND warpRun.state = 'cleaned'))
-    -- where hook 6 %s
-UNION
-SELECT
-    distRun.dist_id,
-    distRun.label,
-    stage,
-    stage_id,
-    diffSkyfile.skycell_id AS component,
-    clean,
-    rawExp.camera,
-    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
-    diffSkyfile.path_base,
-    NULL as chip_path_base,
-    diffRun.state,
-    -- data_state doesn't exist yet
-    -- diffSkyfile.data_state,
-    'full' AS data_state,
-    diffSkyfile.quality,
-    distRun.no_magic,
-    diffSkyfile.magicked
-FROM distRun
-JOIN diffRun ON stage_id = diff_id
-JOIN diffSkyfile using(diff_id)
-JOIN diffInputSkyfile USING(diff_id, skycell_id)
-JOIN warpRun
-    ON warpRun.warp_id = diffInputSkyfile.warp1
-JOIN fakeRun USING(fake_id)
-JOIN camRun USING(cam_id)
-JOIN chipRun USING(chip_id)
-JOIN rawExp USING(exp_id)
-LEFT JOIN distComponent 
-    ON distRun.dist_id = distComponent.dist_id 
-    AND diffSkyfile.skycell_id = distComponent.component
-WHERE
-    distRun.state = 'new'
-    AND distRun.stage = 'diff'
-    AND distComponent.dist_id IS NULL
-    AND (distRun.clean OR diffRun.magicked OR distRun.no_magic)
-    AND (diffRun.state = 'full' OR (distRun.clean AND diffRun.state = 'cleaned'))
-    -- where hook 7 %s
-UNION
-SELECT DISTINCT
-    distRun.dist_id,
-    distRun.label,
-    stage,
-    stage_id,
-    stackRun.skycell_id AS component,
-    clean,
-    rawExp.camera,
-    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
-    stackSumSkyfile.path_base,
-    NULL as chip_path_base,
-    stackRun.state,
-    -- data_state doesn't exist yet
-    -- stackSumSkyfile.data_state,
-    'full' AS data_state,
-    stackSumSkyfile.quality,
-    1 AS no_magic,
-    0 AS magicked
-FROM distRun
-JOIN stackRun
-    ON stage_id = stack_id
-JOIN stackSumSkyfile
-    USING(stack_id)
-JOIN stackInputSkyfile
-    USING(stack_id)
-JOIN warpSkyfile
-    ON  stackInputSkyfile.warp_id = warpSkyfile.warp_id
-    AND stackRun.skycell_id       = warpSkyfile.skycell_id
-    AND stackRun.tess_id          = warpSkyfile.tess_id
-JOIN warpRun
-    ON warpRun.warp_id = warpSkyfile.warp_id
-JOIN fakeRun
-    USING(fake_id)
-JOIN camRun
-    USING(cam_id)
-JOIN chipRun
-    ON camRun.chip_id = chipRun.chip_id
-JOIN rawExp 
-     USING (exp_id)
-LEFT JOIN distComponent 
-    ON distRun.dist_id = distComponent.dist_id 
-    AND stackRun.skycell_id = distComponent.component
-WHERE
-    distRun.state = 'new'
-    AND distRun.stage = 'stack'
-    AND distComponent.dist_id IS NULL
-    AND (stackRun.state = 'full' OR (distRun.clean AND stackRun.state = 'cleaned'))
-    -- where hook 8 %s
-) as Foo
Index: branches/eam_branches/20090820/ippTools/share/disttool_pendingfileset.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_pendingfileset.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_pendingfileset.sql	(revision 25766)
@@ -4,15 +4,16 @@
     distRun.stage,
     stage_id,
+    distTarget.label,
+    distTarget.filter,
     CONCAT_WS('.', distRun.outroot, CONVERT(distRun.dist_id, CHAR)) as dist_dir,
-    rcDSProduct.name AS product_name,
-    rcDSProduct.prod_id,
-    rcDSProduct.dbname AS ds_dbname,
-    rcDSProduct.dbhost AS ds_dbhost
+    rcDestination.name AS product_name,
+    rcDestination.dest_id,
+    rcDestination.dbname AS ds_dbname,
+    rcDestination.dbhost AS ds_dbhost
 FROM rcDestination 
 JOIN rcInterest USING(dest_id) 
 JOIN distTarget USING(target_id) 
-JOIN rcDSProduct USING(prod_id)
 JOIN distRun USING(target_id) 
-LEFT JOIN rcDSFileset USING(prod_id, dist_id)
+LEFT JOIN rcDSFileset USING(dest_id, dist_id)
 WHERE distRun.state = 'full'
     AND rcDestination.state = 'enabled'
Index: branches/eam_branches/20090820/ippTools/share/disttool_queuercrun.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_queuercrun.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_queuercrun.sql	(revision 25766)
@@ -13,7 +13,6 @@
 JOIN rcInterest USING(dest_id) 
 JOIN distTarget USING(target_id) 
-JOIN rcDSProduct USING(prod_id)
 JOIN distRun USING(target_id, stage) 
-JOIN rcDSFileset USING(prod_id, dist_id)
+JOIN rcDSFileset USING(dest_id, dist_id)
 LEFT JOIN rcRun using(fs_id, dest_id)
 WHERE rcRun.rc_id IS NULL
Index: branches/eam_branches/20090820/ippTools/share/disttool_revertcomponent.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_revertcomponent.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_revertcomponent.sql	(revision 25766)
@@ -0,0 +1,5 @@
+DELETE FROM distComponent
+USING distComponent, distRun
+WHERE distComponent.dist_id = distRun.dist_id
+    AND distRun.state = 'new'
+    AND distComponent.fault != 0
Index: branches/eam_branches/20090820/ippTools/share/disttool_revertrun.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_revertrun.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/disttool_revertrun.sql	(revision 25766)
@@ -0,0 +1,4 @@
+UPDATE distRun
+SET distRun.fault = 0
+WHERE distRun.state = 'new'
+    AND distRun.fault != 0
Index: branches/eam_branches/20090820/ippTools/share/disttool_revertrun_delete.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_revertrun_delete.sql	(revision 25206)
+++ 	(revision )
@@ -1,5 +1,0 @@
-DELETE FROM distComponent
-USING distComponent, distRun
-WHERE distComponent.dist_id = distRun.dist_id
-    AND distRun.state = 'new'
-    AND distComponent.fault != 0
Index: branches/eam_branches/20090820/ippTools/share/disttool_revertrun_update.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_revertrun_update.sql	(revision 25206)
+++ 	(revision )
@@ -1,4 +1,0 @@
-UPDATE distRun
-SET distRun.fault = 0
-WHERE distRun.state = 'new'
-    AND distRun.fault != 0
Index: branches/eam_branches/20090820/ippTools/share/disttool_updatercrun.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/disttool_updatercrun.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/disttool_updatercrun.sql	(revision 25766)
@@ -1,6 +1,5 @@
 UPDATE rcRun
 JOIN rcDestination USING(dest_id)
-JOIN rcDSProduct USING(prod_id) 
-JOIN rcDSFileset using(prod_id, fs_id)
+JOIN rcDSFileset using(dest_id, fs_id)
 SET
     -- set hook %s
Index: branches/eam_branches/20090820/ippTools/share/faketool_pendingcleanupimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/faketool_pendingcleanupimfile.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/faketool_pendingcleanupimfile.sql	(revision 25766)
@@ -13,3 +13,7 @@
     USING(fake_id)
 WHERE
-    fakeRun.state = 'goto_cleaned'
+    ((fakeRun.state = 'goto_cleaned' AND fakeProcessedImfile.data_state = 'full')
+OR 
+    (fakeRun.state = 'goto_scrubbed' AND fakeProcessedImfile.data_state = 'full')
+OR 
+    (fakeRun.state = 'goto_purged' AND fakeProcessedImfile.data_state != 'purged'))
Index: branches/eam_branches/20090820/ippTools/share/faketool_pendingcleanuprun.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/faketool_pendingcleanuprun.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/faketool_pendingcleanuprun.sql	(revision 25766)
@@ -11,3 +11,4 @@
 USING (exp_id)
 WHERE
-    fakeRun.state = 'goto_cleaned'
+    (fakeRun.state = 'goto_cleaned' OR fakeRun.state = 'goto_scrubbed' OR fakeRun.state = 'goto_purged')
+
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_completed_runs.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_completed_runs.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_completed_runs.sql	(revision 25766)
@@ -1,9 +1,11 @@
 SELECT DISTINCT
-    magic_ds_id
+    magic_ds_id,
+    re_place,
+    label
 FROM
     (
 -- raw stage
 SELECT
-    magicDSRun.magic_ds_id
+    magicDSRun.*
     FROM magicDSRun
     JOIN rawImfile ON stage_id = rawImfile.exp_id
@@ -23,5 +25,5 @@
 -- chip stage
 SELECT
-    magicDSRun.magic_ds_id
+    magicDSRun.*
     FROM magicDSRun
     JOIN chipProcessedImfile ON stage_id = chip_id
@@ -42,5 +44,5 @@
 -- camera stage
 SELECT
-    magicDSRun.magic_ds_id
+    magicDSRun.*
     FROM magicDSRun
     JOIN camProcessedExp ON stage_id = camProcessedExp.cam_id
@@ -59,5 +61,5 @@
 -- warp stage
 SELECT
-    magicDSRun.magic_ds_id
+    magicDSRun.*
     FROM magicDSRun
     JOIN warpSkyfile on stage_id = warp_id
@@ -79,5 +81,5 @@
 -- diff stage
 SELECT DISTINCT
-    magicDSRun.magic_ds_id
+    magicDSRun.*
     FROM magicDSRun
     JOIN magicRun USING (magic_id)
@@ -101,3 +103,3 @@
         AND SUM(magicDSFile.fault) = 0
 
-   ) as Foo
+   ) as magicDSRun
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_completedrevert.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_completedrevert.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_completedrevert.sql	(revision 25766)
@@ -0,0 +1,10 @@
+SELECT
+    magic_ds_id,
+    state
+FROM magicDSRun
+LEFT JOIN magicDSFile USING(magic_ds_id)
+WHERE 
+    magicDSRun.state = 'goto_censored' OR magicDSRun.state = 'goto_restored'
+GROUP BY magic_ds_id
+HAVING COUNT(component) = 0
+
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_revertdestreakedfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_revertdestreakedfile.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_revertdestreakedfile.sql	(revision 25766)
@@ -0,0 +1,7 @@
+DELETE FROM magicDSFile USING magicDSFile, magicDSRun  
+WHERE (magicDSRun.magic_ds_id = magicDSFile.magic_ds_id) 
+    AND ((magicDSRun.state = 'new' AND magicDSFile.fault != 0)
+      OR (magicDSRun.state = 'goto_restored'
+          OR magicDSRun.state = 'goto_censored'
+         )
+    )
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak.sql	(revision 25206)
+++ 	(revision )
@@ -1,228 +1,0 @@
-SELECT *
-FROM (
-SELECT DISTINCT
-    magicDSRun.magic_ds_id,
-    magicRun.magic_id,
-    magicRun.exp_id,
-    magicDSRun.label,
-    camera,
-    magicMask.uri as streaks_uri,
-    NULL AS inv_streaks_uri,
-    stage,
-    stage_id,
-    class_id as component,
-    rawImfile.uri as uri,
-    NULL as path_base,
-    magicRun.inverse,
-    camProcessedExp.path_base as cam_path_base,
-    outroot,
-    recoveryroot,
-    re_place,
-    remove
-FROM magicDSRun
-JOIN magicMask USING (magic_id)
-JOIN magicRun USING (magic_id)
-JOIN camProcessedExp USING(cam_id)
-JOIN rawImfile ON magicRun.exp_id = rawImfile.exp_id
-LEFT JOIN magicDSFile
-    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
-    AND magicDSFile.component = rawImfile.class_id
-WHERE
-    magicDSRun.state = 'new'
-    AND magicDSRun.stage = 'raw'
-    AND magicDSFile.component IS NULL
-UNION
-  -- chipProcesedImfiles
-SELECT DISTINCT
-    magicDSRun.magic_ds_id,
-    magicDSRun.magic_id,
-    chipRun.exp_id,
-    magicDSRun.label,
-    camera,
-    magicMask.uri as streaks_uri,
-    NULL AS inv_streaks_uri,
-    stage,
-    stage_id,
-    class_id as component,
-    chipProcessedImfile.uri,
-    chipProcessedImfile.path_base,
-    magicRun.inverse,
-    camProcessedExp.path_base as cam_path_base,
-    outroot,
-    recoveryroot,
-    re_place,
-    remove
-FROM magicDSRun
-JOIN magicMask USING (magic_id)
-JOIN magicRun USING(magic_id)
-JOIN camProcessedExp USING(cam_id)
-JOIN chipRun ON chip_id = stage_id
-JOIN chipProcessedImfile USING(chip_id)
-JOIN rawExp ON chipRun.exp_id = rawExp.exp_id
-LEFT JOIN magicDSFile
-    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
-    AND magicDSFile.component = chipProcessedImfile.class_id
-WHERE
-    magicDSRun.state = 'new'
-    AND magicDSRun.stage = 'chip'
-    AND chipRun.state = 'full'
-    AND chipProcessedImfile.fault = 0
-    AND chipProcessedImfile.quality = 0
-    AND magicDSFile.component IS NULL
-UNION
-  -- camProcessedExp
-SELECT DISTINCT
-    magicDSRun.magic_ds_id,
-    magicDSRun.magic_id,
-    chipRun.exp_id,
-    magicDSRun.label,
-    camera,
-    magicMask.uri as streaks_uri,
-    NULL AS inv_streaks_uri,
-    stage,
-    stage_id,
-    'exposure' as component,
-    NULL AS uri,
-    camProcessedExp.path_base,
-    magicRun.inverse,
-    camProcessedExp.path_base as cam_path_base,
-    outroot,
-    recoveryroot,
-    re_place,
-    remove
-FROM magicDSRun
-JOIN magicMask USING (magic_id)
-JOIN magicRun USING(magic_id)
-JOIN camRun ON magicDSRun.stage_id = camRun.cam_id
-JOIN camProcessedExp ON camRun.cam_id = camProcessedExp.cam_id
-JOIN chipRun USING(chip_id)
-JOIN rawExp ON chipRun.exp_id = rawExp.exp_id
-LEFT JOIN magicDSFile
-    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
-WHERE
-    magicDSRun.state = 'new'
-    AND magicDSRun.stage = 'camera'
-    AND camRun.state = 'full'
-    AND chipRun.state = 'full'
-    AND chipRun.magicked
-    AND camProcessedExp.fault = 0
-    AND camProcessedExp.quality = 0
-    AND magicDSFile.component IS NULL
-UNION
--- warpSkyfiles
-SELECT DISTINCT
-    magicDSRun.magic_ds_id,
-    magicRun.magic_id,
-    magicRun.exp_id,
-    magicDSRun.label,
-    camera,
-    magicMask.uri as streaks_uri,
-    NULL AS inv_streaks_uri,
-    stage,
-    stage_id,
-    warpSkyfile.skycell_id as component,
-    warpSkyfile.uri,
-    warpSkyfile.path_base,
-    magicRun.inverse,
-    NULL as cam_path_base,
-    outroot,
-    recoveryroot,
-    re_place,
-    remove
-FROM magicDSRun
-JOIN magicMask USING (magic_id)
-JOIN magicRun USING (magic_id)
-JOIN warpRun ON warp_id = stage_id
-JOIN warpSkyfile USING(warp_id)
-JOIN rawExp ON magicRun.exp_id = rawExp.exp_id
-LEFT JOIN magicDSFile
-    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
-    AND magicDSFile.component = warpSkyfile.skycell_id
-WHERE
-    magicDSRun.state = 'new'
-    AND magicDSRun.stage = 'warp'
-    AND warpRun.state = 'full'
-    AND warpSkyfile.fault = 0
-    AND warpSkyfile.quality = 0
-    AND magicDSFile.component IS NULL
-UNION
--- regular diffSkyfiles
-SELECT DISTINCT
-    magicDSRun.magic_ds_id,
-    magicRun.magic_id,
-    magicRun.exp_id,
-    magicDSRun.label,
-    rawExp.camera,
-    magicMask.uri as streaks_uri,
-    NULL AS inv_streaks_uri,
-    stage,
-    magicRun.diff_id as stage_id,
-    diffSkyfile.skycell_id as component,
-    NULL AS uri,
-    diffSkyfile.path_base,
-    magicRun.inverse,
-    NULL as cam_path_base,
-    outroot,
-    recoveryroot,
-    re_place,
-    remove
-FROM rawExp
-JOIN magicRun USING (exp_id)
-JOIN magicMask USING (magic_id)
-JOIN magicDSRun USING(magic_id)
-JOIN magicInputSkyfile USING(magic_id)
-JOIN diffRun USING(diff_id)
-JOIN diffSkyfile
-    ON  magicRun.diff_id = diffSkyfile.diff_id
-    AND magicInputSkyfile.node = diffSkyfile.skycell_id
-LEFT JOIN magicDSFile
-    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
-    AND magicDSFile.component = diffSkyfile.skycell_id
-WHERE
-    magicDSRun.state = 'new'
-    AND magicDSRun.stage = 'diff'
-    AND diffRun.bothways = 0
-    AND diffSkyfile.fault = 0
-    AND diffSkyfile.quality = 0
-    AND magicDSFile.component IS NULL
--- bothways diffSkyfiles
-UNION
-SELECT DISTINCT
-    magicDSRun.magic_ds_id,
-    magicRun.magic_id,
-    magicRun.exp_id,
-    magicDSRun.label,
-    rawExp.camera,
-    magicMask.uri as streaks_uri,
-    (SELECT uri from magicMask where magic_id = inv_magic_id) AS inv_streaks_uri,
-    stage,
-    magicRun.diff_id as stage_id,
-    diffSkyfile.skycell_id as component,
-    NULL AS uri,
-    diffSkyfile.path_base,
-    magicRun.inverse,
-    NULL as cam_path_base,
-    outroot,
-    recoveryroot,
-    re_place,
-    remove
-FROM rawExp
-JOIN magicRun USING (exp_id)
-JOIN magicMask USING (magic_id)
-JOIN magicDSRun USING(magic_id)
-JOIN magicInputSkyfile USING(magic_id)
-JOIN diffRun USING(diff_id)
-JOIN diffSkyfile
-    ON  magicRun.diff_id = diffSkyfile.diff_id
-    AND magicInputSkyfile.node = diffSkyfile.skycell_id
-LEFT JOIN magicDSFile
-    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
-    AND magicDSFile.component = diffSkyfile.skycell_id
-WHERE
-    magicDSRun.state = 'new'
-    AND magicDSRun.stage = 'diff'
-    AND diffRun.bothways
-    AND diffSkyfile.fault = 0
-    AND diffSkyfile.quality = 0
-    AND magicDSFile.component IS NULL
-) as Foo
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_camera.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_camera.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_camera.sql	(revision 25766)
@@ -0,0 +1,37 @@
+SELECT DISTINCT
+    magicDSRun.magic_ds_id,
+    magicDSRun.magic_id,
+    chipRun.exp_id,
+    magicDSRun.label,
+    camera,
+    magicMask.uri as streaks_uri,
+    CAST(NULL AS CHAR(255)) AS inv_streaks_uri,
+    stage,
+    stage_id,
+    'exposure' as component,
+    CAST(NULL AS CHAR(255)) AS uri,
+    camProcessedExp.path_base,
+    magicRun.inverse,
+    camProcessedExp.path_base as cam_path_base,
+    outroot,
+    recoveryroot,
+    re_place,
+    remove
+FROM magicDSRun
+JOIN magicMask USING (magic_id)
+JOIN magicRun USING(magic_id)
+JOIN camRun ON magicDSRun.stage_id = camRun.cam_id
+JOIN camProcessedExp ON camRun.cam_id = camProcessedExp.cam_id
+JOIN chipRun USING(chip_id)
+JOIN rawExp ON chipRun.exp_id = rawExp.exp_id
+LEFT JOIN magicDSFile
+    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
+WHERE
+    magicDSRun.state = 'new'
+    AND magicDSRun.stage = 'camera'
+    AND camRun.state = 'full'
+    AND chipRun.state = 'full'
+    AND chipRun.magicked
+    AND camProcessedExp.fault = 0
+    AND camProcessedExp.quality = 0
+    AND magicDSFile.component IS NULL
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_chip.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_chip.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_chip.sql	(revision 25766)
@@ -0,0 +1,36 @@
+SELECT DISTINCT
+    magicDSRun.magic_ds_id,
+    magicDSRun.magic_id,
+    chipRun.exp_id,
+    magicDSRun.label,
+    camera,
+    magicMask.uri as streaks_uri,
+    CAST(NULL AS CHAR(255)) AS inv_streaks_uri,
+    stage,
+    stage_id,
+    class_id as component,
+    chipProcessedImfile.uri,
+    chipProcessedImfile.path_base,
+    magicRun.inverse,
+    camProcessedExp.path_base as cam_path_base,
+    outroot,
+    recoveryroot,
+    re_place,
+    remove
+FROM magicDSRun
+JOIN magicMask USING (magic_id)
+JOIN magicRun USING(magic_id)
+JOIN camProcessedExp USING(cam_id)
+JOIN chipRun ON chip_id = stage_id
+JOIN chipProcessedImfile USING(chip_id)
+JOIN rawExp ON chipRun.exp_id = rawExp.exp_id
+LEFT JOIN magicDSFile
+    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
+    AND magicDSFile.component = chipProcessedImfile.class_id
+WHERE
+    magicDSRun.state = 'new'
+    AND magicDSRun.stage = 'chip'
+    AND chipRun.state = 'full'
+    AND chipProcessedImfile.fault = 0
+    AND chipProcessedImfile.quality = 0
+    AND magicDSFile.component IS NULL
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_diff.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_diff.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_diff.sql	(revision 25766)
@@ -0,0 +1,82 @@
+SELECT * FROM (
+SELECT DISTINCT
+    magicDSRun.magic_ds_id,
+    magicRun.magic_id,
+    magicRun.exp_id,
+    magicDSRun.label,
+    rawExp.camera,
+    magicMask.uri as streaks_uri,
+    CAST(NULL AS CHAR(255)) AS inv_streaks_uri,
+    stage,
+    magicRun.diff_id as stage_id,
+    diffSkyfile.skycell_id as component,
+    CAST(NULL AS CHAR(255)) AS uri,
+    diffSkyfile.path_base,
+    magicRun.inverse,
+    CAST(NULL AS CHAR(255)) as cam_path_base,
+    outroot,
+    recoveryroot,
+    re_place,
+    remove
+FROM rawExp
+JOIN magicRun USING (exp_id)
+JOIN magicMask USING (magic_id)
+JOIN magicDSRun USING(magic_id)
+JOIN magicInputSkyfile USING(magic_id)
+JOIN diffRun USING(diff_id)
+JOIN diffSkyfile
+    ON  magicRun.diff_id = diffSkyfile.diff_id
+    AND magicInputSkyfile.node = diffSkyfile.skycell_id
+LEFT JOIN magicDSFile
+    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
+    AND magicDSFile.component = diffSkyfile.skycell_id
+WHERE
+    magicDSRun.state = 'new'
+    AND magicDSRun.stage = 'diff'
+    AND diffRun.bothways = 0
+    AND diffSkyfile.fault = 0
+    AND diffSkyfile.quality = 0
+    AND magicDSFile.component IS NULL
+-- bothways diffSkyfiles
+UNION
+SELECT DISTINCT
+    magicDSRun.magic_ds_id,
+    magicRun.magic_id,
+    magicRun.exp_id,
+    magicDSRun.label,
+    rawExp.camera,
+    magicMask.uri as streaks_uri,
+    (SELECT uri from magicMask where magic_id = inv_magic_id) AS inv_streaks_uri,
+    stage,
+    magicRun.diff_id as stage_id,
+    diffSkyfile.skycell_id as component,
+    CAST(NULL AS CHAR(255)) AS uri,
+    diffSkyfile.path_base,
+    magicRun.inverse,
+    CAST(NULL AS CHAR(255)) as cam_path_base,
+    outroot,
+    recoveryroot,
+    re_place,
+    remove
+FROM rawExp
+JOIN magicRun USING (exp_id)
+JOIN magicMask USING (magic_id)
+JOIN magicDSRun USING(magic_id)
+JOIN magicInputSkyfile USING(magic_id)
+JOIN diffRun USING(diff_id)
+JOIN diffSkyfile
+    ON  magicRun.diff_id = diffSkyfile.diff_id
+    AND magicInputSkyfile.node = diffSkyfile.skycell_id
+LEFT JOIN magicDSFile
+    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
+    AND magicDSFile.component = diffSkyfile.skycell_id
+WHERE
+    magicDSRun.state = 'new'
+    AND magicDSRun.stage = 'diff'
+    AND diffRun.bothways
+    AND diffSkyfile.fault = 0
+    AND diffSkyfile.quality = 0
+    AND magicDSFile.component IS NULL
+) as magicDSRun
+-- we need the following so this query is compatible with the other stages
+WHERE magic_ds_id IS NOT NULL
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_raw.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_raw.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_raw.sql	(revision 25766)
@@ -0,0 +1,31 @@
+SELECT DISTINCT
+    magicDSRun.magic_ds_id,
+    magicRun.magic_id,
+    magicRun.exp_id,
+    magicDSRun.label,
+    camera,
+    magicMask.uri as streaks_uri,
+    CAST(NULL AS CHAR(255)) AS inv_streaks_uri,
+    stage,
+    stage_id,
+    class_id as component,
+    rawImfile.uri as uri,
+    CAST(NULL AS CHAR(255)) as path_base,
+    magicRun.inverse,
+    camProcessedExp.path_base as cam_path_base,
+    outroot,
+    recoveryroot,
+    re_place,
+    remove
+FROM magicDSRun
+JOIN magicMask USING (magic_id)
+JOIN magicRun USING (magic_id)
+JOIN camProcessedExp USING(cam_id)
+JOIN rawImfile ON magicRun.exp_id = rawImfile.exp_id
+LEFT JOIN magicDSFile
+    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
+    AND magicDSFile.component = rawImfile.class_id
+WHERE
+    magicDSRun.state = 'new'
+    AND magicDSRun.stage = 'raw'
+    AND magicDSFile.component IS NULL
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_warp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_warp.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_todestreak_warp.sql	(revision 25766)
@@ -0,0 +1,35 @@
+SELECT DISTINCT
+    magicDSRun.magic_ds_id,
+    magicRun.magic_id,
+    magicRun.exp_id,
+    magicDSRun.label,
+    camera,
+    magicMask.uri as streaks_uri,
+    CAST(NULL AS CHAR(255)) AS inv_streaks_uri,
+    stage,
+    stage_id,
+    warpSkyfile.skycell_id as component,
+    warpSkyfile.uri,
+    warpSkyfile.path_base,
+    magicRun.inverse,
+    CAST(NULL AS CHAR(255)) as cam_path_base,
+    outroot,
+    recoveryroot,
+    re_place,
+    remove
+FROM magicDSRun
+JOIN magicMask USING (magic_id)
+JOIN magicRun USING (magic_id)
+JOIN warpRun ON warp_id = stage_id
+JOIN warpSkyfile USING(warp_id)
+JOIN rawExp ON magicRun.exp_id = rawExp.exp_id
+LEFT JOIN magicDSFile
+    ON magicDSRun.magic_ds_id = magicDSFile.magic_ds_id
+    AND magicDSFile.component = warpSkyfile.skycell_id
+WHERE
+    magicDSRun.state = 'new'
+    AND magicDSRun.stage = 'warp'
+    AND warpRun.state = 'full'
+    AND warpSkyfile.fault = 0
+    AND warpSkyfile.quality = 0
+    AND magicDSFile.component IS NULL
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_torestore.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_torestore.sql	(revision 25206)
+++ 	(revision )
@@ -1,12 +1,0 @@
-SELECT 
-    magic_ds_id,
-    stage,
-    stage_id
-    component,
-    backup_path_base,
-    recovery_path_base
-FROM magicDSFile
-JOIN magicDSRun USING(magic_ds_id)
-WHERE magicDSRun.state = 'goto_restored'
-    AND backup_path_base IS NOT NULL
-    AND recovery_path_base IS NOT NULL
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_camera.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_camera.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_camera.sql	(revision 25766)
@@ -1,4 +1,5 @@
 SELECT
     magic_ds_id,
+    magicDSRun.state,
     exp_id,
     re_place,
@@ -19,4 +20,7 @@
     JOIN rawExp using(exp_id)
 WHERE magicDSRun.stage = 'camera'
-    AND (magicDSRun.state = 'new' OR magicDSRun.state = 'censored')
-    AND magicDSFile.fault > 0
+    AND ((magicDSRun.state = 'new' AND magicDSFile.fault > 0)
+         OR ((magicDSRun.state = 'goto_censored' OR magicDSRun.state = 'goto_restored')
+              AND (backup_path_base IS NOT NULL)
+            )
+        )
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_chip.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_chip.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_chip.sql	(revision 25766)
@@ -1,4 +1,5 @@
 SELECT
     magic_ds_id,
+    magicDSRun.state,
     exp_id,
     re_place,
@@ -18,4 +19,7 @@
     JOIN rawExp using(exp_id)
 WHERE magicDSRun.stage = 'chip'
-    AND (magicDSRun.state = 'new' OR magicDSRun.state = 'censored')
-    AND magicDSFile.fault > 0
+    AND ((magicDSRun.state = 'new' AND magicDSFile.fault > 0)
+         OR ((magicDSRun.state = 'goto_censored' OR magicDSRun.state = 'goto_restored')
+              AND ((backup_path_base IS NOT NULL) OR (recovery_path_base IS NOT NULL))
+            )
+        )
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_diff.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_diff.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_diff.sql	(revision 25766)
@@ -1,4 +1,5 @@
 SELECT
     magic_ds_id,
+    magicDSRun.state,
     exp_id,
     re_place,
@@ -18,4 +19,7 @@
     JOIN rawExp USING(exp_id)
 WHERE magicDSRun.stage = 'diff'
-    AND (magicDSRun.state = 'new' OR magicDSRun.state = 'censored')
-    AND magicDSFile.fault > 0
+    AND ((magicDSRun.state = 'new' AND magicDSFile.fault > 0)
+         OR ((magicDSRun.state = 'goto_censored' OR magicDSRun.state = 'goto_restored')
+              AND ((backup_path_base IS NOT NULL) OR (recovery_path_base IS NOT NULL))
+            )
+        )
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_raw.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_raw.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_raw.sql	(revision 25766)
@@ -1,4 +1,5 @@
 SELECT
     magic_ds_id,
+    magicDSRun.state,
     exp_id,
     re_place,
@@ -15,7 +16,8 @@
     JOIN magicDSFile using(magic_ds_id)
     JOIN rawImfile ON (stage_id = exp_id AND component = class_id)
-    JOIN summitImfile ON (rawImfile.exp_name = summitImfile.exp_name 
-                      AND rawImfile.tmp_class_id = summitImfile.class_id)
 WHERE magicDSRun.stage = 'raw'
-    AND (magicDSRun.state = 'new' OR magicDSRun.state = 'censored')
-    AND magicDSFile.fault > 0
+    AND ((magicDSRun.state = 'new' AND magicDSFile.fault > 0)
+         OR ((magicDSRun.state = 'goto_censored' OR magicDSRun.state = 'goto_restored')
+              AND ((backup_path_base IS NOT NULL) OR (recovery_path_base IS NOT NULL))
+            )
+        )
Index: branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_warp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_warp.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/magicdstool_torevert_warp.sql	(revision 25766)
@@ -1,4 +1,5 @@
 SELECT
     magic_ds_id,
+    magicDSRun.state,
     exp_id,
     re_place,
@@ -21,4 +22,7 @@
     JOIN rawExp USING(exp_id)
 WHERE magicDSRun.stage = 'warp'
-    AND (magicDSRun.state = 'new' OR magicDSRun.state = 'censored')
-    AND magicDSFile.fault > 0
+    AND ((magicDSRun.state = 'new' AND magicDSFile.fault > 0)
+         OR ((magicDSRun.state = 'goto_censored' OR magicDSRun.state = 'goto_restored')
+              AND ((backup_path_base IS NOT NULL) OR (recovery_path_base IS NOT NULL))
+            )
+        )
Index: branches/eam_branches/20090820/ippTools/share/magictool_censor_camera.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_censor_camera.sql	(revision 25206)
+++ 	(revision )
@@ -1,8 +1,0 @@
-UPDATE magicRun 
-    JOIN magicDSRun USING(magic_id)
-    JOIN magicDSFile USING(magic_ds_id)
-    JOIN camRun ON magic_ds_id = magicked
-SET camRun.magicked = 0,
-    magicDSRun.state = 'censored',
-    magicDSFile.fault = 42
-
Index: branches/eam_branches/20090820/ippTools/share/magictool_censor_chip.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_censor_chip.sql	(revision 25206)
+++ 	(revision )
@@ -1,9 +1,0 @@
-UPDATE chipRun 
-    JOIN chipProcessedImfile USING(chip_id, exp_id) 
-    JOIN magicDSRun ON chipRun.magicked = magicDSRun.magic_ds_id 
-    JOIN magicDSFile USING(magic_ds_id) 
-    JOIN magicRun USING(magic_id, exp_id)
-SET chipProcessedImfile.magicked = 0, 
-    chipRun.magicked = 0, 
-    magicDSRun.state = 'censored', 
-    magicDSFile.fault = 42
Index: branches/eam_branches/20090820/ippTools/share/magictool_censor_diff.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_censor_diff.sql	(revision 25206)
+++ 	(revision )
@@ -1,9 +1,0 @@
-UPDATE magicRun 
-    JOIN magicDSRun USING(magic_id)
-    JOIN magicDSFile USING(magic_ds_id)
-    JOIN diffRun ON magic_ds_id = magicked
-    JOIN diffSkyfile ON diffRun.diff_id = diffSkyfile.diff_id
-SET diffRun.magicked = 0,
-    diffSkyfile.magicked = 0,
-    magicDSRun.state = 'censored',
-    magicDSFile.fault = 42
Index: branches/eam_branches/20090820/ippTools/share/magictool_censor_raw.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_censor_raw.sql	(revision 25206)
+++ 	(revision )
@@ -1,10 +1,0 @@
-UPDATE magicRun
-    JOIN magicDSRun USING(magic_id)
-    JOIN magicDSFile USING(magic_ds_id) 
-    JOIN rawExp ON rawExp.magicked = magic_ds_id
-    JOIN rawImfile ON rawExp.exp_id = rawImfile.exp_id
-SET rawImfile.magicked = 0, 
-    rawExp.magicked = 0, 
-    magicDSRun.state = 'censored', 
-    magicDSFile.fault = 42
-
Index: branches/eam_branches/20090820/ippTools/share/magictool_censor_warp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_censor_warp.sql	(revision 25206)
+++ 	(revision )
@@ -1,9 +1,0 @@
-UPDATE magicRun 
-    JOIN magicDSRun USING(magic_id)
-    JOIN magicDSFile USING(magic_ds_id)
-    JOIN warpRun ON magic_ds_id = magicked
-    JOIN warpSkyfile using(warp_id)
-SET warpRun.magicked = 0,
-    warpSkyfile.magicked = 0,
-    magicDSRun.state = 'censored',
-    magicDSFile.fault = 42
Index: branches/eam_branches/20090820/ippTools/share/magictool_restore_camera.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_restore_camera.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magictool_restore_camera.sql	(revision 25766)
@@ -0,0 +1,6 @@
+UPDATE magicRun 
+    JOIN magicDSRun USING(magic_id)
+    JOIN camRun ON stage = 'camera' AND stage_id = camRun.cam_id
+SET camRun.magicked = 0,
+    magicDSRun.state = '@NEW_STATE@'
+WHERE re_place
Index: branches/eam_branches/20090820/ippTools/share/magictool_restore_chip.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_restore_chip.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magictool_restore_chip.sql	(revision 25766)
@@ -0,0 +1,8 @@
+UPDATE magicRun
+    JOIN magicDSRun USING(magic_id)
+    JOIN chipRun ON stage = 'chip' AND stage_id = chip_id
+    JOIN chipProcessedImfile USING(chip_id)
+SET chipProcessedImfile.magicked = 0, 
+    chipRun.magicked = 0, 
+    magicDSRun.state = '@NEW_STATE@'
+WHERE re_place
Index: branches/eam_branches/20090820/ippTools/share/magictool_restore_diff.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_restore_diff.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magictool_restore_diff.sql	(revision 25766)
@@ -0,0 +1,8 @@
+UPDATE magicRun 
+    JOIN magicDSRun USING(magic_id)
+    JOIN diffRun ON stage = 'diff' AND stage_id = diffRun.diff_id
+    JOIN diffSkyfile ON diffRun.diff_id = diffSkyfile.diff_id
+SET diffRun.magicked = 0,
+    diffSkyfile.magicked = 0,
+    magicDSRun.state = '@NEW_STATE@'
+WHERE re_place
Index: branches/eam_branches/20090820/ippTools/share/magictool_restore_raw.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_restore_raw.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magictool_restore_raw.sql	(revision 25766)
@@ -0,0 +1,8 @@
+UPDATE magicRun
+    JOIN magicDSRun USING(magic_id)
+    JOIN rawExp ON stage = 'raw' AND stage_id = rawExp.exp_id
+    JOIN rawImfile ON rawExp.exp_id = rawImfile.exp_id
+SET rawImfile.magicked = 0, 
+    rawExp.magicked = 0, 
+    magicDSRun.state = '@NEW_STATE@'
+WHERE re_place
Index: branches/eam_branches/20090820/ippTools/share/magictool_restore_warp.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/magictool_restore_warp.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/magictool_restore_warp.sql	(revision 25766)
@@ -0,0 +1,8 @@
+UPDATE magicRun 
+    JOIN magicDSRun USING(magic_id)
+    JOIN warpRun ON stage = 'warp' AND stage_id = warp_id
+    JOIN warpSkyfile using(warp_id)
+SET warpRun.magicked = 0,
+    warpSkyfile.magicked = 0,
+    magicDSRun.state = '@NEW_STATE@'
+WHERE re_place
Index: branches/eam_branches/20090820/ippTools/share/pstamptool_completedreq.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pstamptool_completedreq.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/pstamptool_completedreq.sql	(revision 25766)
@@ -0,0 +1,8 @@
+SELECT * 
+FROM pstampRequest 
+WHERE state = 'run'
+    AND (
+    	SELECT count(*) FROM pstampJob 
+	WHERE pstampJob.req_id = pstampRequest.req_id
+		AND pstampJob.state != 'stop'
+	) = 0
Index: branches/eam_branches/20090820/ippTools/share/pstamptool_listjob.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pstamptool_listjob.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/pstamptool_listjob.sql	(revision 25766)
@@ -0,0 +1,6 @@
+SELECT
+    pstampJob.*,
+    pstampRequest.name,
+    pstampRequest.outProduct
+FROM pstampJob
+    JOIN pstampRequest USING(req_id)
Index: branches/eam_branches/20090820/ippTools/share/pstamptool_pendingjob.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pstamptool_pendingjob.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/pstamptool_pendingjob.sql	(revision 25766)
@@ -1,4 +1,7 @@
-SELECT *
- FROM pstampJob
- WHERE state = 'run'
-    AND fault = 0
+SELECT pstampJob.*
+FROM pstampJob
+    JOIN pstampRequest using(req_id)
+WHERE pstampRequest.state = 'run'
+    AND pstampRequest.fault = 0
+    AND pstampJob.state = 'run'
+    AND pstampJob.fault = 0
Index: branches/eam_branches/20090820/ippTools/share/pstamptool_pendingreq.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pstamptool_pendingreq.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/pstamptool_pendingreq.sql	(revision 25766)
@@ -7,2 +7,3 @@
     USING(ds_id)
  WHERE pstampRequest.state = 'new'
+    AND pstampRequest.fault = 0
Index: branches/eam_branches/20090820/ippTools/share/pstamptool_revertjob.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pstamptool_revertjob.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/pstamptool_revertjob.sql	(revision 25766)
@@ -0,0 +1,7 @@
+UPDATE pstampJob 
+    JOIN pstampRequest USING(req_id)
+SET pstampJob.fault = 0
+WHERE  pstampRequest.state = 'run'
+    AND pstampJob.state = 'run'
+    # do not revert faults >= 10 those are faults due to requestor errors
+    AND pstampJob.fault < 10
Index: branches/eam_branches/20090820/ippTools/share/pstamptool_revertreq.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pstamptool_revertreq.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/pstamptool_revertreq.sql	(revision 25766)
@@ -0,0 +1,4 @@
+UPDATE pstampRequest
+    SET fault = 0
+WHERE pstampRequest.state != 'stop'
+    
Index: branches/eam_branches/20090820/ippTools/share/pstamptool_revertreq_deletejobs.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pstamptool_revertreq_deletejobs.sql	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/share/pstamptool_revertreq_deletejobs.sql	(revision 25766)
@@ -0,0 +1,5 @@
+-- delete jobs that got added by an incomplete pstamp parser run
+DELETE pstampJob
+FROM pstampJob
+    JOIN pstampRequest USING(req_id)
+WHERE pstampRequest.state = 'new'
Index: branches/eam_branches/20090820/ippTools/share/pxadmin_create_tables.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pxadmin_create_tables.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/pxadmin_create_tables.sql	(revision 25766)
@@ -58,4 +58,6 @@
     epoch TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     hostname VARCHAR(64),
+    bytes INT,
+    md5sum VARCHAR(32),
     PRIMARY KEY(exp_name, camera, telescope, class, class_id),
     KEY(fault),
@@ -94,4 +96,6 @@
     uri VARCHAR(255),
     epoch TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+    bytes INT,
+    md5sum VARCHAR(32),
     PRIMARY KEY(exp_id, tmp_class_id),
     FOREIGN KEY(exp_id) REFERENCES newExp(exp_id)
@@ -237,4 +241,7 @@
     raw_image_id BIGINT AUTO_INCREMENT,
     magicked BIGINT,
+    bytes INT,
+    md5sum VARCHAR(32),
+    burntool_state SMALLINT,
     PRIMARY KEY(exp_id, class_id),
     KEY(tmp_class_id),
@@ -451,4 +458,38 @@
 ) ENGINE=innodb DEFAULT CHARSET=latin1;
 
+CREATE TABLE addRun (
+    add_id BIGINT AUTO_INCREMENT,
+    cam_id BIGINT,
+    state VARCHAR(64),
+    workdir VARCHAR(255),
+    workdir_state VARCHAR(64),
+    label VARCHAR(64),
+    dvodb VARCHAR(255),
+    magicked BIGINT,
+    PRIMARY KEY(add_id),
+    KEY(add_id),
+    KEY(cam_id),
+    KEY(state),
+    KEY(workdir_state),
+    KEY(label),
+    INDEX(add_id, cam_id),
+    FOREIGN KEY(cam_id) REFERENCES camRun(cam_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE addProcessedExp (
+    add_id BIGINT AUTO_INCREMENT,
+    dtime_addstar FLOAT,
+    n_stars INT,
+    path_base VARCHAR(255),
+    fault SMALLINT NOT NULL,
+    PRIMARY KEY(add_id),
+    FOREIGN KEY(add_id) REFERENCES addRun(add_id)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
+CREATE TABLE addMask (
+    label VARCHAR(64),
+    PRIMARY KEY(label)
+) ENGINE=innodb DEFAULT CHARSET=latin1;
+
 CREATE TABLE fakeRun (
     fake_id BIGINT AUTO_INCREMENT,
@@ -1191,4 +1232,5 @@
         name VARCHAR(64) UNIQUE,
         reqType VARCHAR(16),
+        label VARCHAR(64),
         outProduct VARCHAR(64),
         uri VARCHAR(255),
@@ -1207,4 +1249,5 @@
         exp_id BIGINT,
         outputBase VARCHAR(255),
+        options BIGINT,
         PRIMARY KEY(job_id, req_id),
         KEY(job_id),
@@ -1229,4 +1272,5 @@
     stage       VARCHAR(64),
     stage_id    BIGINT,
+    magic_ds_id BIGINT,
     label       VARCHAR(64),
     outroot     VARCHAR(255),
@@ -1256,24 +1300,15 @@
 
 
-CREATE TABLE rcDSProduct (
-    prod_id     BIGINT AUTO_INCREMENT,
-    name        VARCHAR(64),
-    dbname      VARCHAR(64),
-    dbhost      VARCHAR(64),
-    PRIMARY KEY(prod_id)
-)  ENGINE=innodb DEFAULT CHARSET=latin1;
-
 CREATE TABLE rcDestination (
     dest_id     BIGINT AUTO_INCREMENT,
-    prod_id     BIGINT,
     name        VARCHAR(64),
     status_uri  VARCHAR(255),
     comment     VARCHAR(255),
     last_fileset VARCHAR(255),
+    dbname      VARCHAR(64),
+    dbhost      VARCHAR(64),
     state       VARCHAR(64),
-    PRIMARY KEY(dest_id),
-    FOREIGN KEY(prod_id) REFERENCES rcDSProduct(prod_id)
+    PRIMARY KEY(dest_id)
 )  ENGINE=innodb DEFAULT CHARSET=latin1;
-
 
 CREATE TABLE rcInterest (
@@ -1291,14 +1326,13 @@
     fs_id       BIGINT AUTO_INCREMENT,
     dist_id     BIGINT,
-    prod_id     BIGINT,
+    dest_id     BIGINT,
     name        VARCHAR(255),
     state       VARCHAR(64),
     registered  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
     fault       SMALLINT DEFAULT 0,
-    PRIMARY KEY(dist_id, prod_id),
+    PRIMARY KEY(dist_id, dest_id),
     KEY(fs_id),
     FOREIGN KEY(dist_id) REFERENCES distRun(dist_id),
-    FOREIGN KEY(prod_id) REFERENCES rcDSProduct(prod_id)
---    KEY(dist_id, prod_id)
+    FOREIGN KEY(dest_id) REFERENCES rcDestination(dest_id)
 )  ENGINE=innodb DEFAULT CHARSET=latin1;
 
@@ -1407,4 +1441,6 @@
     pub_id BIGINT AUTO_INCREMENT, -- link to publishRun
     path_base VARCHAR(255),     -- base path of output
+    hostname VARCHAR(64),       -- name of host
+    dtime_script FLOAT,         -- run time for script
     fault SMALLINT NOT NULL DEFAULT 0, -- Fault code
     PRIMARY KEY(pub_id),
Index: branches/eam_branches/20090820/ippTools/share/pxadmin_drop_tables.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/pxadmin_drop_tables.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/pxadmin_drop_tables.sql	(revision 25766)
@@ -19,4 +19,7 @@
 DROP TABLE IF EXISTS detRun;
 DROP TABLE IF EXISTS detInputExp;
+DROP TABLE IF EXISTS addRun;
+DROP TABLE IF EXISTS addProcessedExp;
+DROP TABLE IF EXISTS addMask;
 DROP TABLE IF EXISTS fakeRun;
 DROP TABLE IF EXISTS fakeProcessedImfile;
Index: branches/eam_branches/20090820/ippTools/share/rcserver_updatercrun.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/rcserver_updatercrun.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/rcserver_updatercrun.sql	(revision 25766)
@@ -1,9 +1,4 @@
 UPDATE rcRun
 JOIN rcDestination USING(dest_id)
-JOIN rcDSProduct USING(prod_id) 
-JOIN rcDSFileset using(prod_id, fs_id)
+JOIN rcDSFileset using(dest_id, fs_id)
 SET
-rcRun.fault= 42, rcDestination.last_fileset = 'o4741g0236o.chip.14519.33.1'
-
-
-
Index: branches/eam_branches/20090820/ippTools/share/regtool_pendingimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/regtool_pendingimfile.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/regtool_pendingimfile.sql	(revision 25766)
@@ -6,5 +6,7 @@
     newExp.workdir,
     newImfile.tmp_class_id,
-    newImfile.uri
+    newImfile.uri,
+    newImfile.bytes,
+    newImfile.md5sum
 FROM newImfile
 JOIN newExp
Index: branches/eam_branches/20090820/ippTools/share/regtool_updateprocessedimfile.sql
===================================================================
--- branches/eam_branches/20090820/ippTools/share/regtool_updateprocessedimfile.sql	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/share/regtool_updateprocessedimfile.sql	(revision 25766)
@@ -1,4 +1,4 @@
 UPDATE rawImfile
-  SET user_1 = %lf
+  SET burntool_state = %d
   WHERE
     rawImfile.exp_id = %lld
Index: branches/eam_branches/20090820/ippTools/src/Makefile.am
===================================================================
--- branches/eam_branches/20090820/ippTools/src/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/Makefile.am	(revision 25766)
@@ -1,3 +1,4 @@
 bin_PROGRAMS = \
+	addtool \
 	caltool \
 	camtool \
@@ -23,9 +24,6 @@
 	pubtool
 
-
-bin_SCRIPTS = \
-	fakemagic
-
 pkginclude_HEADERS = \
+	pxadd.h \
 	pxadmin.h \
 	pxcam.h \
@@ -34,4 +32,5 @@
 	pxdata.h \
 	pxfake.h \
+	pxmagic.h \
 	pxregister.h \
 	pxtag.h \
@@ -42,4 +41,5 @@
 
 noinst_HEADERS = \
+	addtool.h \
 	caltool.h \
 	camtool.h \
@@ -68,4 +68,5 @@
 libpxtools_la_LDFLAGS   = -release $(PACKAGE_VERSION)
 libpxtools_la_SOURCES   = \
+	pxadd.c \
 	pxcam.c \
 	pxchip.c \
@@ -75,4 +76,5 @@
 	pxfake.c \
 	pxfault.c \
+	pxmagic.c \
 	pxregister.c \
 	pxtag.c \
@@ -96,4 +98,10 @@
     pstamptool.c \
     pstamptoolConfig.c
+
+addtool_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS)
+addtool_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
+addtool_SOURCES = \
+    addtool.c \
+    addtoolConfig.c
 
 caltool_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS)
Index: branches/eam_branches/20090820/ippTools/src/addtool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/addtool.c	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/src/addtool.c	(revision 25766)
@@ -0,0 +1,1116 @@
+/*
+ * addtool.c
+ *
+ * Copyright (C) 2006  Joshua Hoblitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+
+#include "pxtools.h"
+#include "pxadd.h"
+#include "addtool.h"
+
+static bool definebyqueryMode(pxConfig *config);
+static bool updaterunMode(pxConfig *config);
+static bool pendingexpMode(pxConfig *config);
+static bool addprocessedexpMode(pxConfig *config);
+static bool processedexpMode(pxConfig *config);
+static bool revertprocessedexpMode(pxConfig *config);
+static bool updateprocessedexpMode(pxConfig *config);
+static bool blockMode(pxConfig *config);
+static bool maskedMode(pxConfig *config);
+static bool unblockMode(pxConfig *config);
+static bool pendingcleanuprunMode(pxConfig *config);
+static bool pendingcleanupexpMode(pxConfig *config);
+static bool donecleanupMode(pxConfig *config);
+static bool exportrunMode(pxConfig *config);
+static bool importrunMode(pxConfig *config);
+
+# define MODECASE(caseName, func) \
+    case caseName: \
+    if (!func(config)) { \
+        goto FAIL; \
+    } \
+    break;
+
+int main(int argc, char **argv)
+{
+    psLibInit(NULL);
+
+    pxConfig *config = addtoolConfig(NULL, argc, argv);
+    if (!config) {
+        psError(PXTOOLS_ERR_CONFIG, false, "failed to configure");
+        goto FAIL;
+    }
+
+    switch (config->mode) {
+        MODECASE(ADDTOOL_MODE_DEFINEBYQUERY,        definebyqueryMode);
+        MODECASE(ADDTOOL_MODE_UPDATERUN,            updaterunMode);
+        MODECASE(ADDTOOL_MODE_PENDINGEXP,           pendingexpMode);
+        MODECASE(ADDTOOL_MODE_ADDPROCESSEDEXP,      addprocessedexpMode);
+        MODECASE(ADDTOOL_MODE_PROCESSEDEXP,         processedexpMode);
+        MODECASE(ADDTOOL_MODE_REVERTPROCESSEDEXP,   revertprocessedexpMode);
+        MODECASE(ADDTOOL_MODE_UPDATEPROCESSEDEXP,   updateprocessedexpMode);
+        MODECASE(ADDTOOL_MODE_BLOCK,                blockMode);
+        MODECASE(ADDTOOL_MODE_MASKED,               maskedMode);
+        MODECASE(ADDTOOL_MODE_UNBLOCK,              unblockMode);
+        MODECASE(ADDTOOL_MODE_PENDINGCLEANUPRUN,    pendingcleanuprunMode);
+        MODECASE(ADDTOOL_MODE_PENDINGCLEANUPEXP,    pendingcleanupexpMode);
+        MODECASE(ADDTOOL_MODE_DONECLEANUP,          donecleanupMode);
+        MODECASE(ADDTOOL_MODE_EXPORTRUN,            exportrunMode);
+        MODECASE(ADDTOOL_MODE_IMPORTRUN,            importrunMode);
+        default:
+            psAbort("invalid option (this should not happen)");
+    }
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(EXIT_SUCCESS);
+
+FAIL:
+    psErrorStackPrint(stderr, "\n");
+    int exit_status = pxerrorGetExitStatus();
+
+    psFree(config);
+    pmConfigDone();
+    psLibFinalize();
+
+    exit(exit_status);
+}
+
+
+static bool definebyqueryMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    psMetadata *where = psMetadataAlloc();
+    pxaddGetSearchArgs (config, where);
+    pxAddLabelSearchArgs (config, where, "-label", "addRun.label", "==");
+    PXOPT_COPY_STR(config->args, where, "-reduction", "addRun.reduction", "==");
+
+    if (!psListLength(where->list) &&
+        !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        return false;
+    }
+
+    PXOPT_LOOKUP_STR(workdir, config->args, "-set_workdir", false, false);
+    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+    PXOPT_LOOKUP_STR(reduction, config->args, "-set_reduction", false, false);
+    PXOPT_LOOKUP_STR(dvodb, config->args, "-set_dvodb", false, false);
+
+    // find the cam_id of all the exposures that we want to queue up.
+    psString query = pxDataGet("addtool_find_cam_id.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    // use psDBGenerateWhereSQL because the SQL yields an intermediate table
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("addtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // start a transaction so we don't end up with an exp without any associted
+    // imfiles
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(output);
+        return false;
+    }
+
+    // would could do this "all in the database" if we didn't want the option
+    // of changing the label/reduction/expgroup/dvodb/etc.  So we're pulling the
+    // data out so we have the option of changing these values or leaving the
+    // old values in place (i.e., passing the values through).
+
+
+    // loop over our list of addRun rows
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *md = output->data[i];
+
+        addRunRow *row = addRunObjectFromMetadata(md);
+        if (!row) {
+            psError(PS_ERR_UNKNOWN, false, "failed to convert metadata into addRun");
+            psFree(output);
+            return false;
+        }
+
+        // queue the exp
+        if (!pxaddQueueByCamID(config,
+			       row->cam_id,
+			       workdir     ? workdir   : row->workdir,
+			       label       ? label     : row->label,
+			       "RECIPE",
+			       dvodb       ? dvodb     : row->dvodb
+			       
+        )) {
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PS_ERR_UNKNOWN, false,
+                    "failed to trying to queue chip_id: %" PRId64, row->cam_id);
+            psFree(row);
+            psFree(output);
+            return false;
+        }
+        psFree(row);
+    }
+    psFree(output);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+
+static bool updaterunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxaddGetSearchArgs (config, where);
+    PXOPT_COPY_S64(config->args, where, "-add_id",    "addRun.add_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-label",     "addRun.label", "==");
+    PXOPT_COPY_STR(config->args, where, "-state",     "addRun.state", "==");
+    PXOPT_COPY_STR(config->args, where, "-reduction", "addRun.reduction", "==");
+
+    if (!psListLength(where->list)
+        && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        return false;
+    }
+
+    PXOPT_LOOKUP_STR(state, config->args, "-set_state", false, false);
+    PXOPT_LOOKUP_STR(label, config->args, "-set_label", false, false);
+
+    if ((!state) && (!label)) {
+        psError(PXTOOLS_ERR_DATA, false, "parameters are required");
+        psFree(where);
+        return false;
+    }
+
+    if (state) {
+        // set addRun.state to state
+        if (!pxaddRunSetStateByQuery(config, where, state)) {
+            psFree(where);
+            return false;
+        }
+    }
+
+    if (label) {
+        // set addRun.label to label
+        if (!pxaddRunSetLabelByQuery(config, where, label)) {
+            psFree(where);
+            return false;
+        }
+    }
+
+    psFree(where);
+
+    return true;
+}
+
+
+static bool pendingexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxaddGetSearchArgs (config, where);
+    PXOPT_COPY_S64(config->args, where, "-add_id",    "addRun.add_id", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "addRun.label", "==");
+    PXOPT_COPY_STR(config->args, where, "-reduction", "addRun.reduction", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = pxDataGet("addtool_find_pendingexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // use psDBGenerateWhereSQL because the SQL yields an intermediate table
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("addtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negate simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "addPendingExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+/* static bool pendingimfileMode(pxConfig *config) */
+/* { */
+/*     PS_ASSERT_PTR_NON_NULL(config, false); */
+
+/*     psMetadata *where = psMetadataAlloc(); */
+/*     pxaddGetSearchArgs (config, where); */
+/*     PXOPT_COPY_S64(config->args, where, "-add_id",    "addRun.add_id",                "=="); */
+/*     pxAddLabelSearchArgs (config, where, "-label",    "addRun.label",                 "=="); */
+/*     PXOPT_COPY_STR(config->args, where, "-reduction", "addRun.reduction",             "=="); */
+/*     PXOPT_COPY_S64(config->args, where, "-chip_id",   "addRun.chip_id",              "=="); */
+/*     PXOPT_COPY_STR(config->args, where, "-class_id",  "addProcessedExp.class_id", "=="); */
+
+/*     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false); */
+
+/*     psString query = pxDataGet("addtool_find_pendingimfile.sql"); */
+/*     if (!query) { */
+/*         psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement"); */
+/*         return false; */
+/*     } */
+
+/*     // use psDBGenerateWhereSQL because the SQL yields an intermediate table */
+/*     if (psListLength(where->list)) { */
+/*         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL); */
+/*         psStringAppend(&query, " AND %s", whereClause); */
+/*         psFree(whereClause); */
+/*     } */
+/*     psFree(where); */
+
+/*     if (!p_psDBRunQuery(config->dbh, query)) { */
+/*         psError(PS_ERR_UNKNOWN, false, "database error"); */
+/*         psFree(query); */
+/*         return false; */
+/*     } */
+/*     psFree(query); */
+
+/*     psArray *output = p_psDBFetchResult(config->dbh); */
+/*     if (!output) { */
+/*         psError(PS_ERR_UNKNOWN, false, "database error"); */
+/*         return false; */
+/*     } */
+/*     if (!psArrayLength(output)) { */
+/*         psTrace("addtool", PS_LOG_INFO, "no rows found"); */
+/*         psFree(output); */
+/*         return true; */
+/*     } */
+
+/*     // negate simple so the default is true */
+/*     if (!ippdbPrintMetadatas(stdout, output, "addProcessedExp", !simple)) { */
+/*         psError(PS_ERR_UNKNOWN, false, "failed to print array"); */
+/*         psFree(output); */
+/*         return false; */
+/*     } */
+
+/*     psFree(output); */
+
+/*     return true; */
+/* } */
+
+static bool addprocessedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // required
+    PXOPT_LOOKUP_S64(add_id, config->args, "-add_id", true, false);
+
+    // optional
+    PXOPT_LOOKUP_F32(dtime_addstar, config->args,  "-dtime_addstar", false, false);
+
+    PXOPT_LOOKUP_S32(n_stars, config->args,        "-n_stars", false, false);
+
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", false, false);
+
+    PXOPT_LOOKUP_S64(magicked, config->args, "-magicked", false, false);
+
+    // generate restrictions
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-add_id",   "addRun.add_id",   "==");
+
+    psString query = pxDataGet("addtool_find_pendingexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // use psDBGenerateWhereSQL because the SQL yields an intermediate table
+    if (psListLength(where->list)) {
+        psString whereClaus = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClaus);
+        psFree(whereClaus);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("addtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(output);
+        return false;
+    }
+
+    addRunRow *pendingRow = addRunObjectFromMetadata(output->data[0]);
+    psFree(output);
+    addProcessedExpRow *row = addProcessedExpRowAlloc(
+        pendingRow->add_id,
+        dtime_addstar,
+        n_stars,
+        path_base,
+	0
+        );
+
+    if (!addProcessedExpInsertObject(config->dbh, row)) {
+        // rollback
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(row);
+        psFree(pendingRow);
+        return false;
+    }
+
+    // since there is only one exp per 'new' set addRun.state = 'full'
+    if (!pxaddRunSetState(config, row->add_id, "full", magicked)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to change addRun.state for add_id: %" PRId64, row->add_id);
+        psFree(row);
+        psFree(pendingRow);
+        return false;
+    }
+
+    // NULL for end_stage means go as far as possible
+    // EAM : skip here if fault != 0
+    // Also, we can run fake even if tess_id is not defined
+/*     if (fault || (pendingRow->end_stage && psStrcasestr(pendingRow->end_stage, "add"))) { */
+/*         psFree(row); */
+/*         psFree(pendingRow); */
+/*         if (!psDBCommit(config->dbh)) { */
+/*             psError(PS_ERR_UNKNOWN, false, "database error"); */
+/*             return false; */
+/*         } */
+/*         return true; */
+/*     } */
+    psFree(row);
+    // else continue on...
+
+/*     if (!pxfakeQueueByAddID(config, */
+/*             pendingRow->add_id, */
+/*             pendingRow->workdir, */
+/*             pendingRow->label, */
+/*             pendingRow->reduction, */
+/*             pendingRow->expgroup, */
+/*             pendingRow->dvodb, */
+/*             pendingRow->tess_id, */
+/*             pendingRow->end_stage */
+/*     )) { */
+/*         // rollback */
+/*         if (!psDBRollback(config->dbh)) { */
+/*             psError(PS_ERR_UNKNOWN, false, "database error"); */
+/*         } */
+/*         psError(PS_ERR_UNKNOWN, false, "failed to queue new fakeRun"); */
+/*         psFree(pendingRow); */
+/*         return false; */
+/*     } */
+    psFree(pendingRow);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+
+static bool processedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
+
+    // generate restrictions
+    psMetadata *where = psMetadataAlloc();
+    pxaddGetSearchArgs (config, where);
+    PXOPT_COPY_S64(config->args, where, "-add_id",    "addRun.add_id",    "==");
+    pxAddLabelSearchArgs (config, where, "-label",    "addRun.label",     "==");
+    PXOPT_COPY_STR(config->args, where, "-reduction", "addRun.reduction", "==");
+
+    if (!psListLength(where->list) &&
+        !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_DATA, false, "search parameters (or -all) are required");
+        return false;
+    }
+
+    psString query = pxDataGet("addtool_find_processedexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " WHERE %s", whereClause);
+        psFree(whereClause);
+    } 
+
+    // we either add AND (condition) or WHERE (condition):
+    if (where->list && faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", " AND addProcessedExp.fault != 0");
+    } 
+    if (where->list && !faulted) {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", " AND addProcessedExp.fault = 0");
+    }
+    if (!where->list && faulted) {
+        // list only faulted rows
+        psStringAppend(&query, " %s", " WHERE addProcessedExp.fault != 0");
+    } 
+    if (!where->list && !faulted) {
+        // don't list faulted rows
+        psStringAppend(&query, " %s", " WHERE addProcessedExp.fault = 0");
+    }
+    psFree(where);
+
+    // order by add_id so that the postage stamp parser can easliy find the 'latest' astrometry
+    psStringAppend(&query, " ORDER BY add_id");
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("addtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negate simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "addProcessedExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool revertprocessedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxaddGetSearchArgs (config, where);
+    PXOPT_COPY_S64(config->args, where, "-add_id",    "addRun.add_id",         "==");
+    pxAddLabelSearchArgs (config, where, "-label",    "addRun.label",     "==");
+    PXOPT_COPY_STR(config->args, where, "-reduction", "addRun.reduction",      "==");
+/*     PXOPT_COPY_S16(config->args, where, "-fault", "addProcessedExp.fault", "=="); */
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
+        psFree(where);
+        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        return false;
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(where);
+        return false;
+    }
+
+    {
+        psString query = pxDataGet("addtool_reset_faulted_runs.sql");
+        if (!query) {
+            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psFree(where);
+            return false;
+        }
+
+        // use psDBGenerateWhereConditionalSQL with AND ... because the SQL ends in a WHERE
+        if (where && psListLength(where->list)) {
+            psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+            psStringAppend(&query, " AND %s", whereClause);
+            psFree(whereClause);
+        }
+
+        if (!p_psDBRunQuery(config->dbh, query)) {
+            // rollback
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            psFree(query);
+            psFree(where);
+            return false;
+        }
+        psFree(query);
+    }
+
+    {
+        psString query = pxDataGet("addtool_revertprocessedexp.sql");
+        if (!query) {
+            // rollback
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            psFree(where);
+            return false;
+        }
+
+        // use psDBGenerateWhereConditionalSQL with AND ... because the SQL ends in a WHERE
+        if (where && psListLength(where->list)) {
+            psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+            psStringAppend(&query, " AND %s", whereClause);
+            psFree(whereClause);
+        }
+
+        if (!p_psDBRunQuery(config->dbh, query)) {
+            // rollback
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            psFree(query);
+            psFree(where);
+            return false;
+        }
+        psFree(query);
+    }
+    psFree(where);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+
+static bool updateprocessedexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_S16(fault, config->args, "-fault", true, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-add_id",   "add_id",   "==");
+    PXOPT_COPY_S64(config->args, where, "-cam_id",  "cam_id",  "==");
+/*     PXOPT_COPY_STR(config->args, where, "-class",    "class",    "=="); */
+/*     PXOPT_COPY_STR(config->args, where, "-class_id", "class_id", "=="); */
+
+    if (!pxSetFaultCode(config->dbh, "addProcessedExp", where, fault)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to set set fault flag");
+        psFree (where);
+        return false;
+    }
+    psFree (where);
+
+    return true;
+}
+
+
+static bool blockMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_STR(label, config->args, "-label", true, false);
+
+    if (!addMaskInsert(config->dbh, label)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+
+static bool maskedMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psString query = psStringCopy("SELECT * FROM addMask");
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("addtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "addMask", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool unblockMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_STR(label, config->args, "-label", true, false);
+
+    char *query = "DELETE FROM addMask WHERE label = '%s'";
+
+    if (!p_psDBRunQueryF(config->dbh, query, label)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
+
+static bool pendingcleanuprunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    pxAddLabelSearchArgs (config, where, "-label", "addRun.label", "==");
+
+    psString query = pxDataGet("addtool_pendingcleanuprun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("addtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "addPendingCleanupRun", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool pendingcleanupexpMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_S64(add_id, config->args, "-add_id", false, false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    if (add_id) {
+        PXOPT_COPY_S64(config->args, where, "-add_id", "add_id", "==");
+    }
+    pxAddLabelSearchArgs (config, where, "-label", "label", "==");
+
+    psString query = pxDataGet("addtool_pendingcleanupexp.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("chiptool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "addPendingCleanupExp", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+
+static bool donecleanupMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    psString query = pxDataGet("addtool_donecleanup.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (where && psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("addtool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    // negative simple so the default is true
+    if (!ippdbPrintMetadatas(stdout, output, "addDoneCleanup", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
+
+bool exportrunMode(pxConfig *config)
+{
+  typedef struct ExportTable {
+    char tableName[80];
+    char sqlFilename[80];
+  } ExportTable;
+
+  int numExportTables = 2;
+
+  PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+  PXOPT_LOOKUP_S64(det_id, config->args, "-add_id", true,  false);
+  PXOPT_LOOKUP_STR(outfile, config->args, "-outfile", true,  false);
+  PXOPT_LOOKUP_U64(limit,   config->args, "-limit",   false, false);
+  PXOPT_LOOKUP_BOOL(clean, config->args, "-clean", false);
+
+  FILE *f = fopen (outfile, "w");
+  if (f == NULL) {
+    psError(PS_ERR_UNKNOWN, false, "failed to open output file");
+    return false;
+  }
+
+  psMetadata *where = psMetadataAlloc();
+  PXOPT_COPY_S64(config->args, where, "-add_id", "add_id", "==");
+
+  ExportTable tables [] = {
+    {"addRun", "addtool_export_run.sql"},
+    {"addProcessedExp", "addtool_export_processed_exp.sql"},
+  };
+
+  for (int i=0; i < numExportTables; i++) {
+    psString query = pxDataGet(tables[i].sqlFilename);
+    if (!query) {
+      psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+      return false;
+    }
+
+    if (where && psListLength(where->list)) {
+      psString whereClause = psDBGenerateWhereSQL(where, NULL);
+      psStringAppend(&query, " %s", whereClause);
+      psFree(whereClause);
+    }
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+      psString limitString = psDBGenerateLimitSQL(limit);
+      psStringAppend(&query, " %s", limitString);
+      psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+      psError(PS_ERR_UNKNOWN, false, "database error");
+      psFree(query);
+      return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+      psError(PS_ERR_UNKNOWN, false, "database error");
+      return false;
+    }
+    if (!psArrayLength(output)) {
+      psError(PS_ERR_UNKNOWN, true, "no rows found");
+      psFree(output);
+      return false;
+    }
+
+    if (clean) {
+        if (!strcmp(tables[i].tableName, "addRun")) {
+            if (!pxSetStateCleaned("addRun", "state", output)) {
+                psFree(output);
+                psError(PS_ERR_UNKNOWN, false, "pxSetStateClean failed for table %s",  tables[i].tableName);
+                return false;
+            }
+        }
+    }
+
+    // we must write the export table in non-simple (true) format
+    if (!ippdbPrintMetadatas(f, output, tables[i].tableName, true)) {
+      psError(PS_ERR_UNKNOWN, false, "failed to print array");
+      psFree(output);
+      return false;
+    }
+    psFree(output);
+  }
+
+  fclose (f);
+
+  return true;
+}
+
+bool importrunMode(pxConfig *config)
+{
+  unsigned int nFail;
+
+  PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+  PXOPT_LOOKUP_STR(infile, config->args, "-infile", true,  false);
+
+  psMetadata *input = psMetadataConfigRead (NULL, &nFail, infile, false);
+
+  fprintf (stdout, "---- input ----\n");
+  psMetadataPrint (stderr, input, 1);
+
+  psMetadataItem *item = psMetadataLookup (input, "addRun");
+  psAssert (item, "entry not in input?");
+  psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
+
+  psMetadataItem *entry = psListGet (item->data.list, 0);
+  assert (entry);
+  assert (entry->type == PS_DATA_METADATA);
+  addRunRow *addRun = addRunObjectFromMetadata (entry->data.md);
+  addRunInsertObject (config->dbh, addRun);
+
+  // fprintf (stdout, "---- add run ----\n");
+  // psMetadataPrint (stderr, entry->data.md, 1);
+
+  item = psMetadataLookup (input, "addProcessedExp");
+  psAssert (item, "entry not in input?");
+  psAssert (item->type == PS_DATA_METADATA_MULTI, "entry not multi?");
+
+  for (int i = 0; i < item->data.list->n; i++) {
+    psMetadataItem *entry = psListGet (item->data.list, i);
+    assert (entry);
+    assert (entry->type == PS_DATA_METADATA);
+    addProcessedExpRow *addProcessedExp = addProcessedExpObjectFromMetadata (entry->data.md);
+    addProcessedExpInsertObject (config->dbh, addProcessedExp);
+
+    // fprintf (stdout, "---- row %d ----\n", i);
+    // psMetadataPrint (stderr, entry->data.md, 1);
+  }
+
+  return true;
+}
Index: branches/eam_branches/20090820/ippTools/src/addtool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/addtool.h	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/src/addtool.h	(revision 25766)
@@ -0,0 +1,46 @@
+/*
+ * addtool.h
+ *
+ * Copyright (C) 2006  Joshua Hoblitt, Christopher Waters
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef ADDTOOL_H
+#define ADDTOOL_H 1
+
+#include "pxtools.h"
+
+typedef enum {
+    ADDTOOL_MODE_NONE      = 0x0,
+    ADDTOOL_MODE_DEFINEBYQUERY,
+    ADDTOOL_MODE_UPDATERUN,
+    ADDTOOL_MODE_PENDINGEXP,
+    ADDTOOL_MODE_ADDPROCESSEDEXP,
+    ADDTOOL_MODE_PROCESSEDEXP,
+    ADDTOOL_MODE_REVERTPROCESSEDEXP,
+    ADDTOOL_MODE_UPDATEPROCESSEDEXP,
+    ADDTOOL_MODE_BLOCK,
+    ADDTOOL_MODE_MASKED,
+    ADDTOOL_MODE_UNBLOCK,
+    ADDTOOL_MODE_PENDINGCLEANUPRUN,
+    ADDTOOL_MODE_PENDINGCLEANUPEXP,
+    ADDTOOL_MODE_DONECLEANUP,
+    ADDTOOL_MODE_EXPORTRUN,
+    ADDTOOL_MODE_IMPORTRUN
+} addtoolMode;
+
+pxConfig *addtoolConfig(pxConfig *config, int argc, char **argv);
+
+#endif // ADDTOOL_H
Index: branches/eam_branches/20090820/ippTools/src/addtoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/addtoolConfig.c	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/src/addtoolConfig.c	(revision 25766)
@@ -0,0 +1,212 @@
+/*
+ * addtoolConfig.c
+ *
+ * Copyright (C) 2009  Joshua Hoblitt, Chris Waters
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+#include <stdint.h>
+
+#include <psmodules.h>
+
+#include "pxtools.h"
+#include "pxadd.h"
+#include "addtool.h"
+
+pxConfig *addtoolConfig(pxConfig *config, int argc, char **argv)
+{
+    if (!config) {
+        config = pxConfigAlloc();
+    }
+
+    pmConfigReadParamsSet(false);
+
+    // setup site config
+    config->modules = pmConfigRead(&argc, argv, NULL);
+    if (!config->modules) {
+        psError(PS_ERR_UNKNOWN, false, "Can't find site configuration");
+        psFree(config);
+        return NULL;
+    }
+
+    // -definebyquery
+    // XXX need to allow multiple chip_ids
+    // XXX need to allow multiple exp_ids
+    psMetadata *definebyqueryArgs = psMetadataAlloc();
+    pxcamSetSearchArgs(definebyqueryArgs);
+    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by chipRun label", NULL);
+    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-reduction",          0, "search by chipRun reduction class", NULL);
+
+    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-set_workdir",        0, "define workdir", NULL);
+    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-set_label",          0, "define label", NULL);
+    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-set_reduction",      0, "define reduction class", NULL);
+    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-set_dvodb",          0, "define DVO db", NULL);
+    psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-all",               0, "allow everything to be queued without search terms", false);
+
+    // -updaterun
+    // XXX need to allow multiple add_ids
+    // XXX need to allow multiple chip_ids
+    // XXX need to allow multiple exp_ids
+    psMetadata *updaterunArgs = psMetadataAlloc();
+    pxcamSetSearchArgs(updaterunArgs);
+    psMetadataAddS64(updaterunArgs, PS_LIST_TAIL, "-add_id",             0, "search by add_id", 0);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-label", 		 0, "search by camRun label", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-state", 		 0, "search by camRun state", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-reduction",          0, "search by camRun reduction class", NULL);
+    psMetadataAddBool(updaterunArgs, PS_LIST_TAIL, "-all",               0, "allow everything to be queued without search terms", false);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-set_state",          0, "set state", NULL);
+    psMetadataAddStr(updaterunArgs, PS_LIST_TAIL, "-set_label",          0, "set label", NULL);
+
+    // -pendingexp
+    psMetadata *pendingexpArgs = psMetadataAlloc();
+    pxcamSetSearchArgs(pendingexpArgs);
+    psMetadataAddS64(pendingexpArgs, PS_LIST_TAIL, "-add_id",            0, "search by add_id", 0);
+    psMetadataAddS64(pendingexpArgs, PS_LIST_TAIL, "-cam_id",            0, "search by cam_id", 0);
+    psMetadataAddStr(pendingexpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by camRun label", NULL);
+    psMetadataAddStr(pendingexpArgs, PS_LIST_TAIL, "-reduction",         0, "search by camRun reduction class", NULL);
+    psMetadataAddU64(pendingexpArgs, PS_LIST_TAIL, "-limit",             0, "limit result set to N items", 0);
+    psMetadataAddBool(pendingexpArgs, PS_LIST_TAIL, "-simple",           0, "use the simple output format", false);
+
+    // XXX is this used? psMetadataAddStr(pendingimfileArgs, PS_LIST_TAIL, "-class",    0,            "search by class", NULL);
+
+    // -addprocessedexp
+    psMetadata *addprocessedexpArgs = psMetadataAlloc();
+    psMetadataAddS64(addprocessedexpArgs, PS_LIST_TAIL, "-add_id", 0,            "define addtool ID (required)", 0);
+
+    psMetadataAddF32(addprocessedexpArgs, PS_LIST_TAIL, "-dtime_addstar", 0, "define elapsed time for DVO insertion (seconds)", NAN);
+    psMetadataAddS32(addprocessedexpArgs, PS_LIST_TAIL, "-n_stars", 0,            "define number of stars", 0);
+
+    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-path_base", 0,            "define base output location", NULL);
+    psMetadataAddS64(addprocessedexpArgs, PS_LIST_TAIL, "-magicked", 0,             "set magicked", 0);
+    // -processedexp
+    psMetadata *processedexpArgs = psMetadataAlloc();
+    pxcamSetSearchArgs(processedexpArgs);
+    psMetadataAddS64(processedexpArgs, PS_LIST_TAIL, "-add_id",   0,            "search by add_id", 0);
+    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "search by addRun label", NULL);
+    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-reduction",0,            "search by addRun reduction class", NULL);
+
+    psMetadataAddU64(processedexpArgs, PS_LIST_TAIL, "-limit",    0,            "limit result set to N items", 0);
+    psMetadataAddBool(processedexpArgs, PS_LIST_TAIL, "-all",     0,            "list everything without restriction", false);
+    psMetadataAddBool(processedexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+/*     psMetadataAddBool(processedexpArgs, PS_LIST_TAIL, "-faulted", 0,            "only return imfiles with a fault status set", false); */
+
+    // -revertprocessedexp
+    // XXX need to allow multiple add_ids
+    // XXX need to allow multiple chip_ids
+    // XXX need to allow multiple exp_ids
+    psMetadata *revertprocessedexpArgs = psMetadataAlloc();
+    pxcamSetSearchArgs(revertprocessedexpArgs);
+    psMetadataAddS64(revertprocessedexpArgs, PS_LIST_TAIL, "-add_id",   0,            "search by add_id", 0);
+    psMetadataAddStr(revertprocessedexpArgs, PS_LIST_TAIL, "-label",    PS_META_DUPLICATE_OK, "search by addRun label", NULL);
+    psMetadataAddStr(revertprocessedexpArgs, PS_LIST_TAIL, "-reduction",0,            "search by addRun reduction class", NULL);
+
+    psMetadataAddBool(revertprocessedexpArgs, PS_LIST_TAIL, "-all",  0,            "allow everything to be queued without search terms", false);
+
+    // -updateprocessedexp
+    // XXX allow full search options?
+    psMetadata *updateprocessedexpArgs = psMetadataAlloc();
+    psMetadataAddS64(updateprocessedexpArgs, PS_LIST_TAIL, "-add_id", 0,            "search by addtool ID", 0);
+    psMetadataAddS64(updateprocessedexpArgs, PS_LIST_TAIL, "-cam_id",  0,            "search by camtool ID", 0);
+
+    // -block
+    psMetadata *blockArgs = psMetadataAlloc();
+    psMetadataAddStr(blockArgs, PS_LIST_TAIL, "-label",  0,            "name of a label to mask out (required)", NULL);
+
+    // -masked
+    psMetadata *maskedArgs = psMetadataAlloc();
+    psMetadataAddBool(maskedArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+
+    // -unblock
+    psMetadata *unblockArgs = psMetadataAlloc();
+    psMetadataAddStr(unblockArgs, PS_LIST_TAIL, "-label",  0,            "name of a label to unmask (required)", NULL);
+
+    // -pendingcleanuprun
+    // XXX allow full search options?
+    psMetadata *pendingcleanuprunArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanuprunArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "list blocks for specified label", NULL);
+    psMetadataAddBool(pendingcleanuprunArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanuprunArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -pendingcleanupexp
+    // XXX allow full search options?
+    psMetadata *pendingcleanupexpArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcleanupexpArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "list blocks for specified label", NULL);
+    psMetadataAddS64(pendingcleanupexpArgs, PS_LIST_TAIL, "-add_id", 0,            "search by addstar ID", 0);
+    psMetadataAddBool(pendingcleanupexpArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(pendingcleanupexpArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -donecleanup
+    psMetadata *donecleanupArgs = psMetadataAlloc();
+    psMetadataAddStr(donecleanupArgs, PS_LIST_TAIL, "-label",  0,            "list blocks for specified label", NULL);
+    psMetadataAddBool(donecleanupArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddU64(donecleanupArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
+
+    // -exportrun
+    psMetadata *exportrunArgs = psMetadataAlloc();
+    psMetadataAddS64(exportrunArgs, PS_LIST_TAIL, "-add_id", 0,          "export this addstar ID (required)", 0);
+    psMetadataAddStr(exportrunArgs, PS_LIST_TAIL, "-outfile", 0,          "export to this file (required)", NULL);
+    psMetadataAddU64(exportrunArgs, PS_LIST_TAIL, "-limit",   0,          "limit result set to N items", 0);
+    psMetadataAddBool(exportrunArgs, PS_LIST_TAIL, "-clean",  0,          "export tables as cleaned", false);
+
+    // -importrun
+    psMetadata *importrunArgs = psMetadataAlloc();
+    psMetadataAddStr(importrunArgs, PS_LIST_TAIL, "-infile",  0,          "import from this file (required)", NULL);
+
+
+    psMetadata *argSets = psMetadataAlloc();
+    psMetadata *modes = psMetadataAlloc();
+
+    PXOPT_ADD_MODE("-definebyquery",        "create runs from cam stage",           ADDTOOL_MODE_DEFINEBYQUERY, definebyqueryArgs);
+    PXOPT_ADD_MODE("-updaterun",            "change add run properties",            ADDTOOL_MODE_UPDATERUN,      updaterunArgs);
+    PXOPT_ADD_MODE("-pendingexp",           "show pending exps",                    ADDTOOL_MODE_PENDINGEXP,    pendingexpArgs);
+    PXOPT_ADD_MODE("-addprocessedexp",      "add a processed exp",                  ADDTOOL_MODE_ADDPROCESSEDEXP, addprocessedexpArgs);
+    PXOPT_ADD_MODE("-processedexp",         "show processed exps",                  ADDTOOL_MODE_PROCESSEDEXP,  processedexpArgs);
+    PXOPT_ADD_MODE("-revertprocessedexp",   "change procesed exp properties",       ADDTOOL_MODE_REVERTPROCESSEDEXP,  revertprocessedexpArgs);
+    PXOPT_ADD_MODE("-updateprocessedexp",   "undo a processed exp",                 ADDTOOL_MODE_UPDATEPROCESSEDEXP,updateprocessedexpArgs);
+    PXOPT_ADD_MODE("-block",                "set a label block",                    ADDTOOL_MODE_BLOCK,         blockArgs);
+    PXOPT_ADD_MODE("-masked",               "show blocked labels",                  ADDTOOL_MODE_MASKED,        maskedArgs);
+    PXOPT_ADD_MODE("-unblock",              "remove a label block",                 ADDTOOL_MODE_UNBLOCK,       unblockArgs);
+    PXOPT_ADD_MODE("-pendingcleanuprun",    "show runs that need to be cleaned up", ADDTOOL_MODE_PENDINGCLEANUPRUN, pendingcleanuprunArgs);
+    PXOPT_ADD_MODE("-pendingcleanupexp",    "show exps for cleanup runs",           ADDTOOL_MODE_PENDINGCLEANUPEXP, pendingcleanupexpArgs);
+    PXOPT_ADD_MODE("-donecleanup",          "show runs that have been cleaned",     ADDTOOL_MODE_DONECLEANUP,       donecleanupArgs);
+    PXOPT_ADD_MODE("-exportrun",            "export run for import on other database", ADDTOOL_MODE_EXPORTRUN, exportrunArgs);
+    PXOPT_ADD_MODE("-importrun",            "import run from metadata file",           ADDTOOL_MODE_IMPORTRUN, importrunArgs);
+
+    if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
+        psError(PS_ERR_UNKNOWN, false, "option parsing failed");
+        psFree(argSets);
+        psFree(modes);
+        psFree(config);
+        return NULL;
+    }
+
+    psFree(argSets);
+    psFree(modes);
+
+    // define Database handle, if used
+    config->dbh = psMemIncrRefCounter(pmConfigDB(config->modules));
+    if (!config->dbh) {
+        psError(PS_ERR_UNKNOWN, false, "Can't configure database");
+        psFree(config);
+        return NULL;
+    }
+
+    return config;
+}
Index: branches/eam_branches/20090820/ippTools/src/camtool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/camtool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/camtool.c	(revision 25766)
@@ -656,4 +656,21 @@
         return false;
     }
+
+/*     if (!pxaddQueueByCamID(config, */
+/* 			   pendingRow->cam_id, */
+/* 			   pendingRow->workdir, */
+/* 			   pendingRow->label, */
+/* 			   pendingRow->reduction, */
+/* 			   pendingRow->dvodb */
+/*     )) { */
+/*         // rollback */
+/*         if (!psDBRollback(config->dbh)) { */
+/*             psError(PS_ERR_UNKNOWN, false, "database error"); */
+/*         } */
+/*         psError(PS_ERR_UNKNOWN, false, "failed to queue new addRun"); */
+/*         psFree(pendingRow); */
+/*         return false; */
+/*     } */
+
     psFree(pendingRow);
 
Index: branches/eam_branches/20090820/ippTools/src/chiptool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/chiptool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/chiptool.c	(revision 25766)
@@ -54,4 +54,5 @@
 static bool tofullimfileMode(pxConfig *config);
 static bool topurgedimfileMode(pxConfig *config);
+static bool toscrubbedimfileMode(pxConfig *config);
 static bool exportrunMode(pxConfig *config);
 static bool importrunMode(pxConfig *config);
@@ -93,4 +94,5 @@
         MODECASE(CHIPTOOL_MODE_TOFULLIMFILE,            tofullimfileMode);
         MODECASE(CHIPTOOL_MODE_TOPURGEDIMFILE,          topurgedimfileMode);
+	MODECASE(CHIPTOOL_MODE_TOSCRUBBEDIMFILE,        toscrubbedimfileMode);
         MODECASE(CHIPTOOL_MODE_EXPORTRUN,               exportrunMode);
         MODECASE(CHIPTOOL_MODE_IMPORTRUN,               importrunMode);
@@ -601,5 +603,9 @@
     PXOPT_COPY_STR(config->args, where, "-reduction", "chipRun.reduction", "==");
     pxAddLabelSearchArgs (config, where, "-label", "chipRun.label", "LIKE");
-    PXOPT_COPY_S64(config->args, where, "-magicked", "chipRun.magicked", "==");
+    PXOPT_COPY_S64(config->args, where, "-magicked", "chipProcessedImfile.magicked", "==");
+
+    PXOPT_LOOKUP_U64(magicked, config->args, "-magicked", false, false);
+    PXOPT_LOOKUP_BOOL(destreaked, config->args,     "-destreaked", false);
+    PXOPT_LOOKUP_BOOL(not_destreaked, config->args, "-not_destreaked", false);
 
     if (!psListLength(where->list) &&
@@ -629,4 +635,18 @@
         // don't list faulted rows
         psStringAppend(&query, " %s", "AND chipProcessedImfile.fault = 0");
+    }
+    if (not_destreaked) {
+        if (destreaked) {
+            psError(PXTOOLS_ERR_DATA, true, "providing -not_destreaked and -destreaked makes no sense");
+            return false;
+        }
+        if (magicked) {
+            psError(PXTOOLS_ERR_DATA, true, "providing -not_destreaked and -magicked makes no sense");
+            return false;
+        }
+        psStringAppend(&query, " AND chipProcessedImfile.magicked = 0");
+    }
+    if (destreaked) {
+        psStringAppend(&query, " AND chipProcessedImfile.magicked != 0");
     }
 
@@ -1333,5 +1353,8 @@
     return change_imfile_data_state(config, "purged", "goto_purged");
 }
-
+static bool toscrubbedimfileMode(pxConfig *config)
+{
+  return change_imfile_data_state(config, "scrubbed", "goto_scrubbed");
+}
 bool exportrunMode(pxConfig *config)
 {
Index: branches/eam_branches/20090820/ippTools/src/chiptool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/chiptool.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/chiptool.h	(revision 25766)
@@ -45,4 +45,5 @@
     CHIPTOOL_MODE_TOFULLIMFILE,
     CHIPTOOL_MODE_TOPURGEDIMFILE,
+    CHIPTOOL_MODE_TOSCRUBBEDIMFILE,
     CHIPTOOL_MODE_EXPORTRUN,
     CHIPTOOL_MODE_IMPORTRUN
Index: branches/eam_branches/20090820/ippTools/src/chiptoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/chiptoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/chiptoolConfig.c	(revision 25766)
@@ -158,5 +158,8 @@
     psMetadataAddStr(processedimfileArgs,  PS_LIST_TAIL, "-reduction",          0, "search by reduction class", NULL);
     psMetadataAddStr(processedimfileArgs,  PS_LIST_TAIL, "-label",  PS_META_DUPLICATE_OK, "search by chipRun label (LIKE comparison)", NULL);
-    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-magicked",  0,        "search by magicked status", false);
+
+    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-destreaked",  0,      "search for destreaked images", false);
+    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-not_destreaked",  0,  "search for images that have not been destreaked", false);
+    psMetadataAddS64(processedimfileArgs, PS_LIST_TAIL, "-magicked",  0,        "search by magicked value", 0);
     psMetadataAddU64(processedimfileArgs,  PS_LIST_TAIL, "-limit",  0,           "limit result set to N items", 0);
     psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-all",  0,            "list everything without search terms", false);
@@ -247,4 +250,9 @@
     psMetadataAddS64(topurgedimfileArgs, PS_LIST_TAIL, "-chip_id", 0,          "chip ID to update", 0);
     psMetadataAddStr(topurgedimfileArgs, PS_LIST_TAIL, "-class_id",  0,        "class ID to update", NULL);
+
+    // -toscrubbedimfile
+    psMetadata *toscrubbedimfileArgs = psMetadataAlloc();
+    psMetadataAddS64(toscrubbedimfileArgs, PS_LIST_TAIL, "-chip_id", 0,        "chip ID to update", 0);
+    psMetadataAddStr(toscrubbedimfileArgs, PS_LIST_TAIL, "-class_id", 0,       "class ID to update", NULL);
 
     // -exportrun
@@ -282,4 +290,5 @@
     PXOPT_ADD_MODE("-tofullimfile",         "set imfile state to full",              CHIPTOOL_MODE_TOFULLIMFILE,         tofullimfileArgs);
     PXOPT_ADD_MODE("-topurgedimfile",       "set imfile state to purged",            CHIPTOOL_MODE_TOPURGEDIMFILE,       topurgedimfileArgs);
+    PXOPT_ADD_MODE("-toscrubbedimfile",     "set imfile state to scrubbed",          CHIPTOOL_MODE_TOSCRUBBEDIMFILE,     toscrubbedimfileArgs);
 
     PXOPT_ADD_MODE("-exportrun",            "export run for import on other database", CHIPTOOL_MODE_EXPORTRUN, exportrunArgs);
Index: branches/eam_branches/20090820/ippTools/src/dettool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/dettool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/dettool.c	(revision 25766)
@@ -150,4 +150,5 @@
         MODECASE(DETTOOL_MODE_UPDATEDETRUN,     updatedetrunMode);
         MODECASE(DETTOOL_MODE_RERUN,            rerunMode);
+	MODECASE(DETTOOL_MODE_PENDINGCLEANUP_DETRUNSUMMARY, pendingcleanup_detrunsummaryMode);
         // register
         MODECASE(DETTOOL_MODE_REGISTER_DETREND, register_detrendMode);
@@ -1827,4 +1828,15 @@
     if (!strcmp(data_state, "drop")) return true;
     if (!strcmp(data_state, "register")) return true;
+    // These are valid data states, and are necessary for the cleanup to work correctly.
+    if (!strcmp(data_state, "full")) return true;
+    if (!strcmp(data_state, "goto_cleaned")) return true;
+    if (!strcmp(data_state, "goto_scrubbed")) return true;
+    if (!strcmp(data_state, "goto_purged")) return true;
+    if (!strcmp(data_state, "cleaned")) return true;
+    if (!strcmp(data_state, "scrubbed")) return true;
+    if (!strcmp(data_state, "purged")) return true;
+    if (!strcmp(data_state, "error_cleaned")) return true;
+    if (!strcmp(data_state, "error_scrubbed")) return true;
+    if (!strcmp(data_state, "error_purged")) return true;
 
     psError(PS_ERR_UNKNOWN, true, "invalid data state: %s", data_state);
@@ -1853,5 +1865,5 @@
 
     if (!isValidDataState (data_state)) return false;
-
+    
     char *query = "UPDATE detProcessedImfile SET data_state = '%s'"
 	" WHERE det_id = %" PRId64
@@ -1900,5 +1912,5 @@
 	" WHERE det_id = %" PRId64
 	" AND iteration = %" PRId32
-	" AND class_id = %s";
+	" AND class_id = '%s'";
     if (!p_psDBRunQueryF(config->dbh, query, data_state, det_id, iteration, class_id)) {
         psError(PS_ERR_UNKNOWN, false,
@@ -1922,6 +1934,7 @@
 	" WHERE det_id = %" PRId64
 	" AND iteration = %" PRId32
-	" AND class_id = %s";
-    if (!p_psDBRunQueryF(config->dbh, query, data_state, det_id, iteration)) {
+	" AND class_id = '%s'";
+/*     fprintf(stderr,"DETTOOL SAYS: %s\n",query); */
+    if (!p_psDBRunQueryF(config->dbh, query, data_state, det_id, iteration,class_id)) {
         psError(PS_ERR_UNKNOWN, false,
                 "failed to change state for det_id %" PRId64 ", iteration %" PRId32, 
@@ -1944,5 +1957,5 @@
 	" WHERE det_id = %" PRId64
 	" AND iteration = %" PRId32
-	" AND class_id = %s";
+	" AND class_id = '%s'";
     if (!p_psDBRunQueryF(config->dbh, query, data_state, det_id, iteration, class_id)) {
         psError(PS_ERR_UNKNOWN, false,
Index: branches/eam_branches/20090820/ippTools/src/dettool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/dettool.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/dettool.h	(revision 25766)
@@ -111,4 +111,5 @@
     DETTOOL_MODE_REVERTDETRUNSUMMARY,
     DETTOOL_MODE_UPDATEDETRUNSUMMARY,
+    DETTOOL_MODE_PENDINGCLEANUP_DETRUNSUMMARY,
     DETTOOL_MODE_UPDATEDETRUN,
     DETTOOL_MODE_RERUN,
@@ -209,4 +210,5 @@
 bool revertdetrunsummaryMode(pxConfig *config);
 bool updatedetrunsummaryMode(pxConfig *config);
+bool pendingcleanup_detrunsummaryMode(pxConfig *config);
 
 // other utilities
Index: branches/eam_branches/20090820/ippTools/src/dettoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/dettoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/dettoolConfig.c	(revision 25766)
@@ -41,11 +41,11 @@
     // XXX EAM : is this used?  does it make sense?
     psMetadata *pendingArgs = psMetadataAlloc();
-    psMetadataAddS64(pendingArgs, PS_LIST_TAIL, "-exp_id",  0,            "search by exposure ID", 0);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_type",  0,            "search by exposure type", NULL);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-inst",  0,            "search by camera", NULL);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-telescope",  0,            "search by telescope", NULL);
-    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-filter",  0,            "search by filter", NULL);
+    psMetadataAddS64(pendingArgs, PS_LIST_TAIL, "-exp_id",  0,         "search by exposure ID", 0);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_type",  0,       "search by exposure type", NULL);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-inst",  0,           "search by camera", NULL);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-telescope",  0,      "search by telescope", NULL);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-filter",  0,         "search by filter", NULL);
     psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-uri",  0,            "search by URL", NULL);
-    psMetadataAddBool(pendingArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddBool(pendingArgs, PS_LIST_TAIL, "-simple",  0,        "use the simple output format", false);
 
     // -definebytag
@@ -125,4 +125,5 @@
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_posang_min",  0,            "define min rotator position angle", NAN);
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_posang_max",  0,            "define max rotator position angle", NAN);
+
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_sun_angle_min",  0,            "define min solar angle", NAN);
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_sun_angle_max",  0,            "define max solar angle", NAN);
@@ -137,4 +138,5 @@
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_moon_phase_max",  0,          "define max moon phase", NAN);
     psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-comment",                0,          "search by comment field (LIKE comparison)", NULL);
+
 
     psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-pretend",  0,            "print the exposures that would be included in the detrend run and exit", false);
@@ -207,7 +209,7 @@
     // -addcorrectimfile
     psMetadata *addcorrectimfileArgs = psMetadataAlloc();
-    psMetadataAddS64(addcorrectimfileArgs, PS_LIST_TAIL, "-det_id",  0,            "define detrend ID (required)", 0);
-    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-class_id",  0,            "search for class ID (required)", NULL);
-    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-uri",  0,            "define resid file URI", NULL);
+    psMetadataAddS64(addcorrectimfileArgs, PS_LIST_TAIL, "-det_id",  0,        "define detrend ID (required)", 0);
+    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-class_id",  0,      "search for class ID (required)", NULL);
+    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-uri",  0,           "define resid file URI", NULL);
     psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-bg",  0,            "define exposure background", NAN);
     psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-bg_stdev",  0,            "define exposure background stdev", NAN);
@@ -306,5 +308,5 @@
     psMetadataAddS64(updateprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
     psMetadataAddStr(updateprocessedimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
-    psMetadataAddStr(updateprocessedimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+    psMetadataAddStr(updateprocessedimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "set state", NULL);
 
     // -pendingcleanup_processedimfile
@@ -366,5 +368,5 @@
     psMetadataAddS64(updateprocessedexpArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
     psMetadataAddS64(updateprocessedexpArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
-    psMetadataAddStr(updateprocessedexpArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+    psMetadataAddStr(updateprocessedexpArgs, PS_LIST_TAIL, "-data_state",           0,            "set state", NULL);
 
     // -pendingcleanup_processedexp
@@ -426,5 +428,5 @@
     psMetadataAddS32(updatestackedArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
     psMetadataAddStr(updatestackedArgs, PS_LIST_TAIL, "-class_id",  0,            "search by class ID", NULL);
-    psMetadataAddStr(updatestackedArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+    psMetadataAddStr(updatestackedArgs, PS_LIST_TAIL, "-data_state",           0,            "set state", NULL);
 
     // -pendingcleanup_stacked
@@ -478,5 +480,5 @@
     psMetadataAddS32(updatenormalizedstatArgs, PS_LIST_TAIL, "-iteration",  0,            "search by iteration number", 0);
     psMetadataAddStr(updatenormalizedstatArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
-    psMetadataAddStr(updatenormalizedstatArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+    psMetadataAddStr(updatenormalizedstatArgs, PS_LIST_TAIL, "-data_state",           0,            "set state", NULL);
 
     // -pendingcleanup_normalizedstat
@@ -540,5 +542,5 @@
     psMetadataAddS32(updatenormalizedimfileArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
     psMetadataAddStr(updatenormalizedimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
-    psMetadataAddStr(updatenormalizedimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+    psMetadataAddStr(updatenormalizedimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "set state", NULL);
 
     // -pendingcleanup_normalizedimfile
@@ -598,5 +600,5 @@
     psMetadataAddS64(updatenormalizedexpArgs, PS_LIST_TAIL, "-det_id",               0,            "search by chip ID", 0);
     psMetadataAddS32(updatenormalizedexpArgs, PS_LIST_TAIL, "-iteration", 0,            "search by iteration number", 0);
-    psMetadataAddStr(updatenormalizedexpArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+    psMetadataAddStr(updatenormalizedexpArgs, PS_LIST_TAIL, "-data_state",           0,            "set state", NULL);
 
     // -pendingcleanup_normalizedexp
@@ -678,5 +680,5 @@
     psMetadataAddS64(updateresidimfileArgs, PS_LIST_TAIL, "-exp_id",               0,            "search by exp_id", 0);
     psMetadataAddStr(updateresidimfileArgs, PS_LIST_TAIL, "-class_id",             0,            "search by exp_name", NULL);
-    psMetadataAddStr(updateresidimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+    psMetadataAddStr(updateresidimfileArgs, PS_LIST_TAIL, "-data_state",           0,            "set state", NULL);
 
     // -pendingcleanup_residimfile
@@ -759,5 +761,5 @@
     psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-path_base",  0,            "define base output location", NULL);
     psMetadataAddBool(updateresidexpArgs, PS_LIST_TAIL, "-reject",  0,            "exposure is not to be stacked in the next iteration", false);
-    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-data_state",           0,            "search for telescope", NULL);
+    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-data_state",           0,            "set state", NULL);
 
     // -pendingcleanup_residexp
@@ -813,4 +815,13 @@
     psMetadataAddBool(updatedetrunsummaryArgs, PS_LIST_TAIL, "-accept",  0,            "declare that this detrun iteration is accepted as a master", false);
     psMetadataAddBool(updatedetrunsummaryArgs, PS_LIST_TAIL, "-reject",  0,            "reject this detrun iteration as a master", false);
+    psMetadataAddStr(updatedetrunsummaryArgs, PS_LIST_TAIL, "-data_state", 0,          "set the data state", NULL);
+    psMetadataAddS32(updatedetrunsummaryArgs, PS_LIST_TAIL, "-iteration", 0,           "search by iteration number", 0);
+
+    // -pendingcleanup_detrunsummary
+    psMetadata *pendingcleanup_detrunsummaryArgs = psMetadataAlloc();
+    psMetadataAddS64(pendingcleanup_detrunsummaryArgs, PS_LIST_TAIL, "-det_id", 0,     "search by detrend ID (required)", 0);
+    psMetadataAddS32(pendingcleanup_detrunsummaryArgs, PS_LIST_TAIL, "-iteration", 0,  "search by iteration number", 0);
+    psMetadataAddU64(pendingcleanup_detrunsummaryArgs, PS_LIST_TAIL, "-limit",  0,     "limit result set to N items", 0);
+    psMetadataAddBool(pendingcleanup_detrunsummaryArgs, PS_LIST_TAIL, "-simple", 0,    "use the simple output format", false);
 
     // -updatedetrun
@@ -968,4 +979,6 @@
     PXOPT_ADD_MODE("-updatedetrunsummary", "", DETTOOL_MODE_UPDATEDETRUNSUMMARY, updatedetrunsummaryArgs);
 
+    PXOPT_ADD_MODE("-pendingcleanup_detrunsummary", "", DETTOOL_MODE_PENDINGCLEANUP_DETRUNSUMMARY, pendingcleanup_detrunsummaryArgs);
+
     PXOPT_ADD_MODE("-updatedetrun", "", DETTOOL_MODE_UPDATEDETRUN, updatedetrunArgs);
     PXOPT_ADD_MODE("-rerun",           "", DETTOOL_MODE_RERUN,         rerunArgs);
Index: branches/eam_branches/20090820/ippTools/src/dettool_detrunsummary.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/dettool_detrunsummary.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/dettool_detrunsummary.c	(revision 25766)
@@ -336,5 +336,65 @@
 }
 
-// XXX need to add -data_state here
+bool pendingcleanup_detrunsummaryMode(pxConfig *config) {
+  PS_ASSERT_PTR_NON_NULL(config, false);
+
+  PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+  PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+  psMetadata *where = psMetadataAlloc();
+  PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
+  PXOPT_COPY_S32(config->args, where, "-iteration", "iteration", "==");
+
+  psString query = pxDataGet("dettool_pendingcleanup_detrunsummary.sql");
+  if (!query) {
+    psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+    return(false);
+  }
+  
+  if (psListLength(where->list)) {
+    psString whereClause = psDBGenerateWhereConditionSQL(where, "detRunSummary");
+    psStringAppend(&query, " AND %s", whereClause);
+    psFree(whereClause);
+  }
+  psFree(where);
+
+  // treat limit == 0 as "no limit"
+  if (limit) {
+    psString limitString = psDBGenerateLimitSQL(limit);
+    psStringAppend(&query, " %s", limitString);
+    psFree(limitString);
+  }
+  //  fprintf(stderr,">>>%s<<<\n",query);
+  if (!p_psDBRunQuery(config->dbh, query)) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    psFree(query);
+    return(false);
+  }
+  psFree(query);
+
+  psArray *output = p_psDBFetchResult(config->dbh);
+  if (!output) {
+    psError(PS_ERR_UNKNOWN, false, "database error");
+    return(false);
+  }
+  if (!psArrayLength(output)) {
+    psTrace("dettool", PS_LOG_INFO, "no rows found");
+    psFree(output);
+    return(true);
+  }
+
+  // negative simple so the default is true
+  if (!ippdbPrintMetadatas(stdout, output, "pendingCleanupDetRun", !simple)) {
+    psError(PS_ERR_UNKNOWN, false, "failed to print array");
+    psFree(output);
+    return(false);
+  }
+  psFree(output);
+
+  return(true);
+}
+
+
+// preliminary code now.
 bool updatedetrunsummaryMode(pxConfig *config)
 {
@@ -344,4 +404,7 @@
     PXOPT_LOOKUP_BOOL(accept, config->args, "-accept", false);
     PXOPT_LOOKUP_BOOL(reject, config->args, "-reject", false);
+    PXOPT_LOOKUP_STR(data_state, config->args, "-data_state", ((accept == 0)&&(reject == 0)), false);
+    PXOPT_LOOKUP_S32(iteration, config->args, "-iteration", ((accept == 0)&&(reject == 0)), false);
+
 
     if (accept && reject) {
@@ -350,13 +413,109 @@
     }
 
-    if (!(accept || reject)) {
-        psError(PS_ERR_UNKNOWN, true, "either -accept or -reject is required");
-        return false;
-    }
-
-    char *query = "UPDATE detRunSummary SET accept = %d WHERE det_id = %"PRId64;
-    if (!p_psDBRunQueryF(config->dbh, query, accept, det_id)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
+    if (!(accept || reject || (data_state != NULL))) {
+        psError(PS_ERR_UNKNOWN, true, "either -accept or -reject is required if -data_state is not supplied");
+        return false;
+    }
+
+    if (accept || reject) {
+      char *query = "UPDATE detRunSummary SET accept = %d WHERE det_id = %"PRId64;
+      if (!p_psDBRunQueryF(config->dbh, query, accept, det_id)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+      }
+    }
+    else {
+      PS_ASSERT_PTR_NON_NULL(data_state,false);
+
+/*       if (!isValidDataState(data_state)) return false; */
+      
+      
+      
+      char *query_detRunSummary = "UPDATE detRunSummary SET data_state = '%s'"
+	" WHERE det_id = %" PRId64
+	" AND iteration = %" PRId32;
+      if (!p_psDBRunQueryF(config->dbh, query_detRunSummary, data_state, det_id,iteration)) {
+	psError(PS_ERR_UNKNOWN, false,
+		"failed to change state for det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	return false;
+      }
+
+      /* This check allows the one update to flag everything for cleanup.  The check for full is only temporary while I test for bugs. */
+      if ((!strncmp(data_state,"goto_",5)
+	   //	   || (!strcmp(data_state,"full"))
+	   //	   || (!strcmp(data_state,"cleaned"))
+	   ))	{
+	char *query_detProcessedImfile = "UPDATE detProcessedImfile SET data_state = '%s'"
+	  " WHERE det_id = %" PRId64;
+	if (!p_psDBRunQueryF(config->dbh, query_detProcessedImfile,data_state,det_id)) {
+	  psError(PS_ERR_UNKNOWN, false,
+		  "failed to change state for detProcessedImfile det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	  return(false);
+	}
+	
+	char *query_detProcessedExp = "UPDATE detProcessedExp SET data_state = '%s'"
+	  " WHERE det_id = %" PRId64;
+	if (!p_psDBRunQueryF(config->dbh, query_detProcessedExp,data_state,det_id)) {
+	  psError(PS_ERR_UNKNOWN, false,
+		  "failed to change state for detProcessedExp det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	  return(false);
+	}
+	
+	char *query_detNormalizedImfile = "UPDATE detNormalizedImfile SET data_state = '%s'"
+	  " WHERE det_id = %" PRId64
+	  " AND iteration = %" PRId32;
+	if (!p_psDBRunQueryF(config->dbh, query_detNormalizedImfile,data_state,det_id,iteration)) {
+	  psError(PS_ERR_UNKNOWN, false,
+		  "failed to change state for detNormalizedImfile det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	  return(false);
+	}
+	
+	char *query_detNormalizedStatImfile = "UPDATE detNormalizedStatImfile SET data_state = '%s'"
+	  " WHERE det_id = %" PRId64
+	  " AND iteration = %" PRId32;
+	if (!p_psDBRunQueryF(config->dbh, query_detNormalizedStatImfile,data_state,det_id,iteration)) {
+	  psError(PS_ERR_UNKNOWN, false,
+		  "failed to change state for detNormalizedStatImfile det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	  return(false);
+	}
+
+	char *query_detNormalizedExp = "UPDATE detNormalizedExp SET data_state = '%s'"
+	  " WHERE det_id = %" PRId64
+	  " AND iteration = %" PRId32;
+	if (!p_psDBRunQueryF(config->dbh, query_detNormalizedExp,data_state,det_id,iteration)) {
+	  psError(PS_ERR_UNKNOWN, false,
+		  "failed to change state for detNormalizedExp det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	  return(false);
+	}
+	
+	char *query_detResidImfile = "UPDATE detResidImfile SET data_state = '%s'"
+	  " WHERE det_id = %" PRId64
+	  " AND iteration = %" PRId32;
+	if (!p_psDBRunQueryF(config->dbh, query_detResidImfile,data_state,det_id,iteration)) {
+	  psError(PS_ERR_UNKNOWN, false,
+		  "failed to change state for detResidImfile det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	  return(false);
+	}
+	
+	char *query_detResidExp = "UPDATE detResidExp SET data_state = '%s'"
+	  " WHERE det_id = %" PRId64
+	  " AND iteration = %" PRId32;
+	if (!p_psDBRunQueryF(config->dbh, query_detResidExp,data_state,det_id,iteration)) {
+	  psError(PS_ERR_UNKNOWN, false,
+		  "failed to change state for detResidExp det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	  return(false);
+	}
+	
+	char *query_detStackedImfile = "UPDATE detStackedImfile SET data_state = '%s'"
+	  " WHERE det_id = %" PRId64
+	  " AND iteration = %" PRId32;
+	if (!p_psDBRunQueryF(config->dbh, query_detStackedImfile,data_state,det_id,iteration)) {
+	  psError(PS_ERR_UNKNOWN, false,
+		  "failed to change state for detStackedImfile det_id %" PRId64 ", iteration %" PRId32, det_id,iteration);
+	  return(false);
+	}
+      }
+      /* End if */
+      
     }
 
Index: branches/eam_branches/20090820/ippTools/src/dettool_processedimfile.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/dettool_processedimfile.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/dettool_processedimfile.c	(revision 25766)
@@ -314,5 +314,5 @@
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
+/*     int i; */
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-det_id", "det_id", "==");
@@ -345,4 +345,5 @@
         return false;
     }
+/*     fprintf(stderr,"DETTOOL:procimfile: %s\n",query); */
     psFree(query);
 
@@ -350,8 +351,10 @@
     if (!output) {
         psError(PS_ERR_UNKNOWN, false, "database error");
+/* 	fprintf(stderr,"WTF !output?\n"); */
         return false;
     }
     if (!psArrayLength(output)) {
         psTrace("dettool", PS_LOG_INFO, "no rows found");
+/* 	fprintf(stderr,"WTF no rows??\n"); */
         psFree(output);
         return true;
@@ -359,4 +362,6 @@
 
     // negative simple so the default is true
+/*     i = (int) ippdbPrintMetadatas(stdout, output, "detCleanupProcessedImfile", !simple); */
+/*     fprintf(stderr,">>%d<<\n",i); */
     if (!ippdbPrintMetadatas(stdout, output, "detCleanupProcessedImfile", !simple)) {
         psError(PS_ERR_UNKNOWN, false, "failed to print array");
@@ -364,4 +369,6 @@
         return false;
     }
+/*     fprintf(stderr,"DETTOOL:procimfile: %s\n",output); */
+/*     psFree(output); */
 
     psFree(output);
Index: branches/eam_branches/20090820/ippTools/src/difftool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/difftool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/difftool.c	(revision 25766)
@@ -37,4 +37,5 @@
 static bool todiffskyfileMode(pxConfig *config);
 static bool adddiffskyfileMode(pxConfig *config);
+static bool advanceMode(pxConfig *config);
 static bool diffskyfileMode(pxConfig *config);
 static bool revertdiffskyfileMode(pxConfig *config);
@@ -50,5 +51,4 @@
 
 static bool setdiffRunState(pxConfig *config, psS64 diff_id, const char *state, psS64 magicked);
-static bool diffRunComplete(pxConfig *config);
 
 # define MODECASE(caseName, func) \
@@ -76,8 +76,9 @@
         MODECASE(DIFFTOOL_MODE_TODIFFSKYFILE,         todiffskyfileMode);
         MODECASE(DIFFTOOL_MODE_ADDDIFFSKYFILE,        adddiffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_ADVANCE,               advanceMode);
         MODECASE(DIFFTOOL_MODE_DIFFSKYFILE,           diffskyfileMode);
         MODECASE(DIFFTOOL_MODE_REVERTDIFFSKYFILE,     revertdiffskyfileMode);
         MODECASE(DIFFTOOL_MODE_DEFINEPOPRUN,          definepoprunMode);
-        MODECASE(DIFFTOOL_MODE_DEFINEWARPSTACK,         definewarpstackMode);
+        MODECASE(DIFFTOOL_MODE_DEFINEWARPSTACK,       definewarpstackMode);
         MODECASE(DIFFTOOL_MODE_DEFINEWARPWARP,        definewarpwarpMode);
         MODECASE(DIFFTOOL_MODE_PENDINGCLEANUPRUN,     pendingcleanuprunMode);
@@ -555,12 +556,4 @@
     }
 
-    if (!diffRunComplete(config)) {
-        if (!psDBRollback(config->dbh)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-        }
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
     // point of no return
     if (!psDBCommit(config->dbh)) {
@@ -569,4 +562,95 @@
     }
 
+
+    return true;
+}
+
+static bool advanceMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where,  "-diff_id", "diffRun.diff_id", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "diffRun.label", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+
+    // look for completed diffRuns
+    psString query = pxDataGet("difftool_completed_runs.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    psString whereString = psStringCopy("");
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&whereString, "\n AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(whereString);
+        return false;
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, whereString)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        psFree(whereString);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+    psFree(query);
+    psFree(whereString);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("difftool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *row = output->data[i];
+
+        psS64 diff_id = psMetadataLookupS64(NULL, row, "diff_id");
+        psS64 magicked = psMetadataLookupS64(NULL, row, "magicked");
+
+        // set diffRun.state to 'full'
+        if (!setdiffRunState(config, diff_id, "full", magicked)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to change diffRun.state for diff_id: %" PRId64,
+                diff_id);
+            psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
+            return false;
+        }
+    }
+    psFree(output);
+
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
 
     return true;
@@ -581,13 +665,34 @@
     PXOPT_COPY_S64(config->args, where,  "-diff_id", "diffSkyfile.diff_id", "==");
     PXOPT_COPY_STR(config->args, where, "-skycell_id", "diffInputSkyfile.skycell_id", "==");
-    PXOPT_COPY_S64(config->args, where,  "-diff_skyfile_id", "diffInputSkyfile.diff_skyfile_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-diff_skyfile_id", "diffInputSkyfile.diff_skyfile_id", "==");
     PXOPT_COPY_STR(config->args, where, "-tess_id", "diffRun.tess_id", "==");
     PXOPT_COPY_S16(config->args, where, "-fault", "diffSkyfile.fault", "==");
-    PXOPT_COPY_S64(config->args, where, "-exp_id", "rawInput.exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_name", "rawInput.exp_name", "==");
-    PXOPT_COPY_STR(config->args, where, "-warp_id", "warpInput.warp_id", "==");
-
+    PXOPT_COPY_S64(config->args, where,  "-magicked", "diffSkyfile.magicked", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "diffRun.label", "LIKE");
+
+    PXOPT_LOOKUP_BOOL(template, config->args, "-template", false);
+    if (!template) {
+        PXOPT_COPY_S64(config->args, where, "-exp_id", "rawInput.exp_id", "==");
+        PXOPT_COPY_STR(config->args, where, "-exp_name", "rawInput.exp_name", "==");
+        PXOPT_COPY_STR(config->args, where, "-warp_id", "warpInput.warp_id", "==");
+        PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawInput.dateobs",  ">=");
+        PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawInput.dateobs",  "<=");
+        PXOPT_COPY_STR(config->args, where, "-filter",     "rawInput.filter", "==");
+    } else {
+        PXOPT_COPY_S64(config->args, where, "-exp_id", "rawTemplate.exp_id", "==");
+        PXOPT_COPY_STR(config->args, where, "-exp_name", "rawTemplate.exp_name", "==");
+        PXOPT_COPY_STR(config->args, where, "-warp_id", "warpTemplate.warp_id", "==");
+        PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawTemplate.dateobs",  ">=");
+        PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawTemplate.dateobs",  "<=");
+        PXOPT_COPY_STR(config->args, where, "-filter",     "rawTemplate.filter", "==");
+    }
+
+    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    PXOPT_LOOKUP_U64(magicked, config->args,        "-magicked", false, false);
+    PXOPT_LOOKUP_BOOL(destreaked, config->args,     "-destreaked", false);
+    PXOPT_LOOKUP_BOOL(not_destreaked, config->args, "-not_destreaked", false);
 
     psString query = pxDataGet("difftool_skyfile.sql");
@@ -601,6 +706,24 @@
         psStringAppend(&query, " WHERE %s", whereClause);
         psFree(whereClause);
+    } else if (!all) {
+        psError(PXTOOLS_ERR_DATA, true, "search parameters or -all are required");
     }
     psFree(where);
+
+    if (not_destreaked) {
+        if (destreaked) {
+            psError(PXTOOLS_ERR_DATA, true, "providing -not_destreaked and -destreaked makes no sense");
+            return false;
+        }
+        if (magicked) {
+            psError(PXTOOLS_ERR_DATA, true, "providing -not_destreaked and -magicked makes no sense");
+            return false;
+        }
+        psStringAppend(&query, " AND diffSkyfile.magicked = 0");
+    }
+    if (destreaked) {
+        psStringAppend(&query, " AND diffSkyfile.magicked != 0");
+    }
+
 
     // treat limit == 0 as "no limit"
@@ -1810,49 +1933,4 @@
 }
 
-static bool diffRunComplete(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // look for completed diffRuns
-    psString query = pxDataGet("difftool_completed_runs.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    psArray *output = p_psDBFetchResult(config->dbh);
-    if (!output) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!psArrayLength(output)) {
-        psTrace("difftool", PS_LOG_INFO, "no rows found");
-        psFree(output);
-        return true;
-    }
-    for (long i = 0; i < psArrayLength(output); i++) {
-        psMetadata *row = output->data[i];
-
-        psS64 diff_id = psMetadataLookupS64(NULL, row, "diff_id");
-        psS64 magicked = psMetadataLookupS64(NULL, row, "magicked");
-
-        // set diffRun.state to 'stop'
-        if (!setdiffRunState(config, diff_id, "full", magicked)) {
-            psError(PS_ERR_UNKNOWN, false, "failed to change diffRun.state for diff_id: %" PRId64,
-                diff_id);
-            psFree(output);
-            return false;
-        }
-    }
-
-    return true;
-}
 
 bool exportrunMode(pxConfig *config)
Index: branches/eam_branches/20090820/ippTools/src/difftool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/difftool.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/difftool.h	(revision 25766)
@@ -31,4 +31,5 @@
     DIFFTOOL_MODE_TODIFFSKYFILE,
     DIFFTOOL_MODE_ADDDIFFSKYFILE,
+    DIFFTOOL_MODE_ADVANCE,
     DIFFTOOL_MODE_DIFFSKYFILE,
     DIFFTOOL_MODE_REVERTDIFFSKYFILE,
Index: branches/eam_branches/20090820/ippTools/src/difftoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/difftoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/difftoolConfig.c	(revision 25766)
@@ -115,16 +115,32 @@
     psMetadataAddBool(adddiffskyfileArgs, PS_LIST_TAIL, "-magicked",  0, "define magicked state", false);
 
+    // -advance
+    psMetadata *advanceArgs = psMetadataAlloc();
+    psMetadataAddS64(advanceArgs, PS_LIST_TAIL, "-diff_id", 0, "select by diff ID", 0);
+    psMetadataAddStr(advanceArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "select by label", NULL);
+    psMetadataAddS32(advanceArgs, PS_LIST_TAIL, "-limit", 0, "limit number of results", 0);
+
     // -diffskyfile
     psMetadata *diffskyfileArgs = psMetadataAlloc();
-    psMetadataAddS64(diffskyfileArgs, PS_LIST_TAIL, "-diff_id", 0,            "search by diff ID", 0);
-    psMetadataAddStr(diffskyfileArgs , PS_LIST_TAIL, "-skycell_id",  0,       "define skycell ID", NULL);
-    psMetadataAddS64(diffskyfileArgs, PS_LIST_TAIL, "-diff_skyfile_id", 0,    "search by diff_skyfile_id ID", 0);
-    psMetadataAddStr(diffskyfileArgs, PS_LIST_TAIL, "-tess_id",  0,            "define tessellation ID", NULL);
-    psMetadataAddS64(diffskyfileArgs, PS_LIST_TAIL, "-exp_id",  0,            "define exposure ID", 0);
-    psMetadataAddStr(diffskyfileArgs , PS_LIST_TAIL, "-exp_name",  0,         "define exposure name", NULL);
-    psMetadataAddStr(diffskyfileArgs , PS_LIST_TAIL, "-warp_id",  0,         "define warp_id", NULL);
-    psMetadataAddU64(diffskyfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
-    psMetadataAddBool(diffskyfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
-    psMetadataAddS16(diffskyfileArgs, PS_LIST_TAIL, "-fault",  0,            "define fault code", 0);
+    psMetadataAddS64(diffskyfileArgs, PS_LIST_TAIL,  "-diff_id", 0,           "search by diff ID", 0);
+    psMetadataAddStr(diffskyfileArgs , PS_LIST_TAIL, "-skycell_id",  0,      "search by skycell ID", NULL);
+    psMetadataAddS64(diffskyfileArgs, PS_LIST_TAIL,  "-diff_skyfile_id", 0,   "search by diff_skyfile_id ID", 0);
+    psMetadataAddStr(diffskyfileArgs, PS_LIST_TAIL,  "-tess_id",  0,          "search by tessellation ID", NULL);
+    psMetadataAddStr(diffskyfileArgs , PS_LIST_TAIL, "-warp_id",  0,         "search by warp_id", NULL);
+    psMetadataAddBool(diffskyfileArgs, PS_LIST_TAIL, "-template",  0,        "apply exposure args to template of bothways diff", false);
+    psMetadataAddS64(diffskyfileArgs, PS_LIST_TAIL,  "-exp_id",  0,           "search by exposure ID", 0);
+    psMetadataAddStr(diffskyfileArgs , PS_LIST_TAIL, "-exp_name",  0,        "search by exposure name", NULL);
+    psMetadataAddTime(diffskyfileArgs, PS_LIST_TAIL, "-dateobs_begin", 0,    "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(diffskyfileArgs, PS_LIST_TAIL, "-dateobs_end", 0,      "search for exposures by time (<=)", NULL);
+    psMetadataAddStr(diffskyfileArgs, PS_LIST_TAIL,  "-filter", 0,           "search for filter", NULL);
+    psMetadataAddS64(diffskyfileArgs, PS_LIST_TAIL,  "-magicked", 0,         "search by magicked value", 0);
+    psMetadataAddBool(diffskyfileArgs, PS_LIST_TAIL, "-destreaked",  0,      "search for destreaked images", false);
+    psMetadataAddBool(diffskyfileArgs, PS_LIST_TAIL, "-not_destreaked",  0,  "search for images that are not destreaked", false);
+    psMetadataAddStr(diffskyfileArgs,  PS_LIST_TAIL, "-label",  PS_META_DUPLICATE_OK, "search by diffRun label (LIKE comparison)", NULL);
+    psMetadataAddS16(diffskyfileArgs, PS_LIST_TAIL,  "-fault",  0,           "search by fault code", 0);
+
+    psMetadataAddBool(diffskyfileArgs, PS_LIST_TAIL, "-all",  0,             "search without arguments", false);
+    psMetadataAddU64(diffskyfileArgs, PS_LIST_TAIL,  "-limit",  0,            "limit result set to N items", 0);
+    psMetadataAddBool(diffskyfileArgs, PS_LIST_TAIL, "-simple",  0,          "use the simple output format", false);
 
     // -revertdiffskyfile
@@ -267,4 +283,5 @@
     PXOPT_ADD_MODE("-todiffskyfile",    "", DIFFTOOL_MODE_TODIFFSKYFILE,     todiffskyfileArgs);
     PXOPT_ADD_MODE("-adddiffskyfile",   "", DIFFTOOL_MODE_ADDDIFFSKYFILE,    adddiffskyfileArgs);
+    PXOPT_ADD_MODE("-advance",          "", DIFFTOOL_MODE_ADVANCE,           advanceArgs);
     PXOPT_ADD_MODE("-diffskyfile",      "", DIFFTOOL_MODE_DIFFSKYFILE,       diffskyfileArgs);
     PXOPT_ADD_MODE("-revertdiffskyfile","", DIFFTOOL_MODE_REVERTDIFFSKYFILE, revertdiffskyfileArgs);
Index: branches/eam_branches/20090820/ippTools/src/disttool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/disttool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/disttool.c	(revision 25766)
@@ -2,5 +2,5 @@
  * disttool.c
  *
- * Copyright (C) 2008
+ * Copyright (C) 2008-2009
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -37,4 +37,5 @@
 static bool pendingcomponentMode(pxConfig *config);
 static bool addprocessedcomponentMode(pxConfig *config);
+static bool revertcomponentMode(pxConfig *config);
 static bool processedcomponentMode(pxConfig *config);
 static bool toadvanceMode(pxConfig *config);
@@ -51,7 +52,4 @@
 static bool listtargetMode(pxConfig *config);
 
-static bool definedsproductMode(pxConfig *config);
-static bool updatedsproductMode(pxConfig *config);
-
 static bool definedestinationMode(pxConfig *config);
 static bool updatedestinationMode(pxConfig *config);
@@ -59,4 +57,5 @@
 static bool defineinterestMode(pxConfig *config);
 static bool updateinterestMode(pxConfig *config);
+static bool listinterestsMode(pxConfig *config);
 
 # define MODECASE(caseName, func) \
@@ -86,4 +85,5 @@
         MODECASE(DISTTOOL_MODE_ADDPROCESSEDCOMPONENT, addprocessedcomponentMode);
         MODECASE(DISTTOOL_MODE_PROCESSEDCOMPONENT, processedcomponentMode);
+        MODECASE(DISTTOOL_MODE_REVERTCOMPONENT, revertcomponentMode);
         MODECASE(DISTTOOL_MODE_TOADVANCE, toadvanceMode);
         MODECASE(DISTTOOL_MODE_PENDINGFILESET, pendingfilesetMode);
@@ -97,10 +97,9 @@
         MODECASE(DISTTOOL_MODE_UPDATETARGET, updatetargetMode);
         MODECASE(DISTTOOL_MODE_LISTTARGET, listtargetMode);
-        MODECASE(DISTTOOL_MODE_DEFINEDSPRODUCT, definedsproductMode);
-        MODECASE(DISTTOOL_MODE_UPDATEDSPRODUCT, updatedsproductMode);
         MODECASE(DISTTOOL_MODE_DEFINEDESTINATION, definedestinationMode);
         MODECASE(DISTTOOL_MODE_UPDATEDESTINATION, updatedestinationMode);
         MODECASE(DISTTOOL_MODE_DEFINEINTEREST, defineinterestMode);
         MODECASE(DISTTOOL_MODE_UPDATEINTEREST, updateinterestMode);
+        MODECASE(DISTTOOL_MODE_LISTINTERESTS, listinterestsMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -151,4 +150,5 @@
             stage,
             stage_id,
+            0,
             set_label,
             outroot,
@@ -223,5 +223,6 @@
         }
     } else if (!strcmp(stage, "camera")) {
-        magicRunType = "chipRun";    // This is used below to set the magicked business
+        magicRunType = "camRun";    // This is used below to set the magicked business
+        runJoinStr = "camRun.cam_id";
         query = pxDataGet("disttool_definebyquery_camera.sql");
         if (!query) {
@@ -288,5 +289,5 @@
             psStringAppend(&query, " AND (stackRun.label = '%s')", label);
         }
-        // stack stage doesn't require magic (perhaps let the script do this?
+        // stack stage doesn't require magic
         no_magic = true;
     } else {
@@ -306,24 +307,15 @@
 
     if (!no_magic) {
-        psStringAppend(&query, " AND (distTarget.clean OR %s.magicked)", magicRunType);
+        psStringAppend(&query, " AND (%s.magicked)", magicRunType);
 
         // is selecting by magic_ds_id really interesting?
         if (magic_ds_id) {
-            if (strcmp(stage, "camera")) {
-                // stage other than camera
-                if (!runJoinStr) {
-                    psError(PS_ERR_PROGRAMMING, true, "cannot select by magic_ds_id for stage: %s", stage);
-                    psFree(query);
-                    return false;
-                }
-                psStringAppend(&joinHook, "\nJOIN magicDSRun ON magicDSRun.stage = distTarget.stage"
+            if (!runJoinStr) {
+                psError(PS_ERR_PROGRAMMING, true, "cannot select by magic_ds_id for stage: %s", stage);
+                psFree(query);
+                return false;
+            }
+            psStringAppend(&joinHook, "\nJOIN magicDSRun ON magicDSRun.stage = distTarget.stage"
                                               " AND magicDSRun.stage_id = %s", runJoinStr);
-            } else {
-                // camera masks are magicked when the chipRun is magicked
-                // XXX: This is confusing. Is it dangerous?
-                // Maybe I should add a magicked bit to camRun. Note this isn't
-                psStringAppend(&joinHook, "\nJOIN magicDSRun ON magicDSRun.stage = 'chip'"
-                                              " AND magicDSRun.stage_id = chipRun.chip_id");
-            }
             psStringAppend(&query, " AND (magicDSRun.state = 'full' AND magicDSRun.re_place AND (magic_ds_id = %" PRId64 "))", magic_ds_id);
         }
@@ -377,4 +369,5 @@
         psString run_tag = psMetadataLookupStr(NULL, md, "run_tag");
         psS64 stage_id = psMetadataLookupS64(NULL, md, "stage_id");
+        psS64 magic_ds_id = psMetadataLookupS64(NULL, md, "magicked");
         psS64 target_id = psMetadataLookupS64(NULL, md, "target_id");
         psString target_label = psMetadataLookupStr(NULL, md, "label");
@@ -395,4 +388,5 @@
                 stage,
                 stage_id,
+                magic_ds_id,
                 new_label,
                 outroot,
@@ -500,8 +494,5 @@
     PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
 
-    // we need to disambiguate fault so make a copy of the where list before adding fault
-    psMetadata *whereComponent = psMetadataCopy(NULL, where);
     PXOPT_COPY_S16(config->args, where,  "-fault", "distRun.fault", "==");
-    PXOPT_COPY_S16(config->args, whereComponent, "-fault", "distComponent.fault", "==");
 
     // It might be useful to be able to query by the parameters of the underlying runs
@@ -513,84 +504,77 @@
     }
 
-    if (!psDBTransaction(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
+    psString query = pxDataGet("disttool_revertrun.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+
+    int numUpdated = psDBAffectedRows(config->dbh);
+
+    psLogMsg("disttool", PS_LOG_INFO, "Updated %d dist runs", numUpdated);
+
+    return true;
+}
+
+static bool revertcomponentMode(pxConfig *config)
+{
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-dist_id", "distRun.dist_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");;
+    PXOPT_COPY_STR(config->args, where, "-component", "component", "==");;
+    PXOPT_COPY_S64(config->args, where, "-stage_id", "stage_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-state", "state", "==");
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
+
+    PXOPT_COPY_S16(config->args, where,  "-fault", "distComponent.fault", "==");
+
+    // It might be useful to be able to query by the parameters of the underlying runs
+
+    if (!psListLength(where->list) && !psMetadataLookupBool(NULL, config->args, "-all")) {
         psFree(where);
-        return false;
-    }
-
-    // Update state to 'new'
-    int numUpdated;                     // Number updated
-    {
-        psString query = pxDataGet("disttool_revertrun_update.sql");
-        if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-
-        if (psListLength(where->list)) {
-            psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-            psStringAppend(&query, " AND %s", whereClause);
-            psFree(whereClause);
-        }
-
-        if (!p_psDBRunQuery(config->dbh, query)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(query);
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-        psFree(query);
-
-        numUpdated = psDBAffectedRows(config->dbh);
-    }
-
-    psLogMsg("disttool", PS_LOG_INFO, "Updated %d dist runs", numUpdated);
-
-    // Delete product
-    int numDeleted;                     // Number deleted
-    {
-        psString query = pxDataGet("disttool_revertrun_delete.sql");
-        if (!query) {
-            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-
-        if (psListLength(whereComponent->list)) {
-            psString whereClause = psDBGenerateWhereConditionSQL(whereComponent, NULL);
-            psStringAppend(&query, " AND %s", whereClause);
-            psFree(whereClause);
-        }
-
-        if (!p_psDBRunQuery(config->dbh, query)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-            psFree(query);
-            if (!psDBRollback(config->dbh)) {
-                psError(PS_ERR_UNKNOWN, false, "database error");
-            }
-            return false;
-        }
-        psFree(query);
-
-        numDeleted = psDBAffectedRows(config->dbh);
-    }
+        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        return false;
+    }
+
+    psString query = pxDataGet("disttool_revertcomponent.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psFree(where);
+        return false;
+    }
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+
+    int numDeleted = psDBAffectedRows(config->dbh);
 
     psLogMsg("disttool", PS_LOG_INFO, "Deleted %d distComponents", numDeleted);
 
-    psFree(where);
-    psFree(whereComponent);
-
-    if (!psDBCommit(config->dbh)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
     return true;
 }
@@ -600,16 +584,18 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
+    PXOPT_LOOKUP_STR(stage, config->args, "-stage", true, false);
+
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-dist_id", "dist_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
-    pxAddLabelSearchArgs (config, where, "-label", "label", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "distRun.label", "==");
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
-    // look for "inputs" that need to processed
-    psString query = pxDataGet("disttool_pendingcomponent.sql");
+    psString queryFile = NULL;
+    psStringAppend(&queryFile, "disttool_pending_%s.sql", stage);
+    psString query = pxDataGet(queryFile);
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement from %s", queryFile);
         return false;
     }
@@ -617,5 +603,5 @@
     if (psListLength(where->list)) {
         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " WHERE %s", whereClause);
+        psStringAppend(&query, " AND %s", whereClause);
         psFree(whereClause);
     }
@@ -629,28 +615,5 @@
     }
 
-    // the query has where hooks for each stage.
-    // right now we aren't using them.
-    // XXX: I think that I want to change the query from a union of selects on the various
-    // stages to separate queries. As it is pending data at the later stages of the pipline
-    // will get blocked by pending earlier stages
-    psString    raw_where = "";
-    psString    raw_clean_where = "";
-    psString    chip_where = "";
-    psString    camera_where = "";
-    psString    fake_where = "";
-    psString    warp_where = "";
-    psString    diff_where = "";
-    psString    stack_where = "";
-
-    if (!p_psDBRunQueryF(config->dbh,
-            query,
-            raw_where,
-            raw_clean_where,
-            chip_where,
-            camera_where,
-            fake_where,
-            warp_where,
-            diff_where,
-            stack_where)) {
+    if (!p_psDBRunQuery(config->dbh, query)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
@@ -868,4 +831,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-dist_id", "dist_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-stage", "distRun.stage", "==");
     pxAddLabelSearchArgs (config, where, "-label", "distRun.label", "==");
 
@@ -939,5 +903,5 @@
     // required values
     PXOPT_LOOKUP_S64(dist_id, config->args, "-dist_id", true, false);
-    PXOPT_LOOKUP_S64(prod_id, config->args, "-prod_id", true, false);
+    PXOPT_LOOKUP_S64(dest_id, config->args, "-dest_id", true, false);
 
     PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
@@ -949,5 +913,5 @@
             0,          // fs_id
             dist_id,
-            prod_id,
+            dest_id,
             name,
             "full",
@@ -964,5 +928,5 @@
     PXOPT_COPY_S64(config->args, where, "-fs_id", "fs_id", "==");
     PXOPT_COPY_S64(config->args, where, "-dist_id", "rcDSFileset.dist_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-prod_id", "prod_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
     PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");;
     PXOPT_COPY_S64(config->args, where, "-stage_id", "stage_id", "==");
@@ -1092,5 +1056,4 @@
     PXOPT_COPY_S64(config->args, where, "-dist_id",  "dist_id", "==");
     PXOPT_COPY_S64(config->args, where, "-dest_id",  "dest_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-prod_id",  "prod_id", "==");
     PXOPT_COPY_S64(config->args, where, "-target_id","target_id", "==");
     PXOPT_COPY_S64(config->args, where, "-fs_id",    "fs_id", "==");
@@ -1433,99 +1396,12 @@
 }
 
-static bool definedsproductMode(pxConfig *config)
+static bool definedestinationMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
     // required
-    PXOPT_LOOKUP_STR(name, config->args,   "-name", true, false);
-    PXOPT_LOOKUP_STR(dbname, config->args, "-ds_dbname", true, false);
-    PXOPT_LOOKUP_STR(dbhost, config->args, "-ds_dbhost", true, false);
-
-    // XXX: should we insure that these names do not contatin any whitespace?
-
-    rcDSProductRow *row = rcDSProductRowAlloc(
-            0,          // prod_id
-            name,
-            dbname,
-            dbhost
-            );
-            
-    if (!row) {
-        psError(PS_ERR_UNKNOWN, false, "failed to allocate rcDSProduct object");
-        return false;
-    }
-   if (!rcDSProductInsertObject(config->dbh, row)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(row);
-        return false;
-    }
-
-    // get the assigned target_id
-    row->prod_id = psDBLastInsertID(config->dbh);
-
-    if (!rcDSProductPrintObject(stdout, row, true)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print object");
-        psFree(row);
-        return false;
-    }
-
-    psFree(row);
-
-    return true;
-}
-static bool updatedsproductMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-prod_id", "prod_id", "==");
-
-    PXOPT_LOOKUP_STR(dbname, config->args, "-ds_dbname", false, false);
-    PXOPT_LOOKUP_STR(dbhost, config->args, "-ds_dbhost", false, false);
-
-    if (!(dbname || dbhost)) {
-        psError(PS_ERR_UNKNOWN, true, "one or more of dbname or dbhost is required");
-        psFree(where);
-        return false;
-    }
-    psString query = psStringCopy("UPDATE rcDSProduct SET");
-    psString sep = "";
-    if (dbname) {
-        psStringAppend(&query, " dbname = '%s'", dbname);
-        sep = ",";
-    }
-    if (dbhost) {
-        psStringAppend(&query, " %s dbhost = '%s'", sep, dbhost);
-    }
-
-    if (psListLength(where->list)) {
-        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " WHERE %s", whereClause);
-        psFree(whereClause);
-    } else {
-        psError(PS_ERR_UNKNOWN, true, "search parameters are required");
-        psFree(where);
-        psFree(query);
-        return false;
-    }
-    psFree(where);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
-    psFree(query);
-
-    return true;
-}
-
-static bool definedestinationMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-
-    // required
-    PXOPT_LOOKUP_S64(prod_id, config->args,      "-prod_id", true, false);
     PXOPT_LOOKUP_STR(name, config->args,         "-name", true, false);
+    PXOPT_LOOKUP_STR(dbname, config->args,       "-ds_dbname", true, false);
+    PXOPT_LOOKUP_STR(dbhost, config->args,       "-ds_dbhost", true, false);
 
     // optional
@@ -1539,9 +1415,10 @@
     rcDestinationRow *row = rcDestinationRowAlloc(
             0,          // dest_id
-            prod_id,
             name,
             status_uri,
             comment,
             last_fileset,
+            dbname,
+            dbhost,
             state ? state : "enabled"
             );
@@ -1577,5 +1454,4 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-prod_id", "prod_id", "==");
 
     PXOPT_LOOKUP_STR(state, config->args, "-set_state", false, false);
@@ -1599,5 +1475,5 @@
     // last_fileset normally gets set by updatercrunMode
     // Allowing it to be set here might cause problems
-    // especially since we are allowing selection by prod_id
+    // especially since we are allowing selection by dest_id
     if (last_fileset) {
         psStringAppend(&query, " %s last_fileset = '%s'", sep, last_fileset);
@@ -1631,40 +1507,102 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    // required
-    PXOPT_LOOKUP_S64(dest_id, config->args,      "-dest_id", true, false);
-    PXOPT_LOOKUP_S64(target_id, config->args,    "-target_id", true, false);
+    // one of these is required
+    PXOPT_LOOKUP_S64(dest_id, config->args,      "-dest_id", false, false);
+    PXOPT_LOOKUP_STR(dest_name, config->args,    "-dest_name", false, false);
+    if (!dest_id && !dest_name) {
+        psError(PS_ERR_UNKNOWN, true, "either dest_id or dest_name is required");
+        return false;
+    }
+
+    // either target_id or stage and label are required
+    PXOPT_LOOKUP_S64(target_id, config->args,    "-target_id", false, false);
+    PXOPT_LOOKUP_STR(stage, config->args,        "-stage", false, false);
+    PXOPT_LOOKUP_STR(label, config->args,        "-label", false, false);
+    PXOPT_LOOKUP_STR(filter, config->args,       "-filter", false, false);
+    PXOPT_LOOKUP_BOOL(clean, config->args,       "-clean", false);
+
+    if (!target_id) {
+        bool error = false;
+        if (!stage) {
+            psError(PS_ERR_UNKNOWN, true, "stage is required if target_id is not supplied");
+            error = true;
+        }
+        if (!label) {
+            psError(PS_ERR_UNKNOWN, !error, "label is required if target_id is not supplied");
+            error = true;
+        }
+        if (error) {
+            return false;
+        }
+    }
 
     // optional
+    PXOPT_LOOKUP_S64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_STR(state, config->args,        "-set_state", false, false);
-
-    // XXX: should we insure that these names do not contatin any whitespace?
-
-    rcInterestRow *row = rcInterestRowAlloc(
-            0,          // int_id
-            dest_id,
-            target_id,
-            state ? state : "enabled"
-            );
-            
-    if (!row) {
-        psError(PS_ERR_UNKNOWN, false, "failed to allocate rcInterest object");
-        return false;
-    }
-   if (!rcInterestInsertObject(config->dbh, row)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(row);
-        return false;
-    }
-
-    // get the assigned target_id
-    row->int_id = psDBLastInsertID(config->dbh);
-
-    if (!rcInterestPrintObject(stdout, row, true)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to print object");
-        psFree(row);
-        return false;
-    }
-
-    psFree(row);
+    if (state) {
+        if (strcmp(state, "enabled") && strcmp(state, "disabled")) {
+            psError(PS_ERR_PROGRAMMING, true, "state must be enabled or disabled");
+            return false;
+        }
+    } else {
+        // default state
+        state = "enabled";
+    }
+
+    // now that we've done all of our argument checking, copy the values to where
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-dest_name", "rcDestination.name", "==");
+    PXOPT_COPY_S64(config->args, where, "-target_id", "target_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-filter", "filter", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
+
+    psString query = pxDataGet("disttool_defineinterest.sql");
+
+    if (!psListLength(where->list)) {
+        // can't get here
+        psError(PS_ERR_PROGRAMMING, true, "search parameters are required");
+        psFree(where);
+        psFree(query);
+        return false;
+    }
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psStringAppend(&query, " AND %s", whereClause);
+    psFree(whereClause);
+    psFree(where);
+    if (clean) {
+        psStringAppend(&query, " AND (distTarget.clean)");
+    } else {
+        psStringAppend(&query, " AND (!distTarget.clean)");
+    }
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+    {
+        // psStringSubstitute fails unless the input is a psString which it determines by
+        // comparing the memory blocks free function to an expected value.
+        // pxDataGet uses psSlurp which leaves a different free function on the memory block.
+        // To work around this make a copy of the query before doing the substitution.
+        psString queryCopy = psStringCopy(query);
+        psFree(query);
+        query = queryCopy;
+    }
+    // change the @STATE@ in the sql file to our state
+    if (!psStringSubstitute(&query, state, "@STATE@")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to substitute state string");
+        return false;
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+    int numInserted = psDBAffectedRows(config->dbh);
+    printf("inserted %d rows into rcInterest\n", numInserted);
 
     return true;
@@ -1710,3 +1648,83 @@
     return true;
 }
-
+static bool listinterestsMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-int_id", "int_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-dest_id", "dest_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-dest_name", "name", "==");
+    PXOPT_COPY_S64(config->args, where, "-target_id", "target_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-filter", "filter", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-state", "state", "==");
+
+    PXOPT_LOOKUP_BOOL(clean, config->args, "-clean", false);
+    PXOPT_LOOKUP_BOOL(full, config->args, "-full", false);
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+
+    if (clean && full) {
+        psError(PS_ERR_UNKNOWN, false, "can't select both -clean and -full");
+        return false;
+    }
+
+    psString query = pxDataGet("disttool_listinterests.sql");
+
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " WHERE %s", whereClause);
+        psFree(whereClause);
+        if (clean) {
+            psStringAppend(&query, " AND (clean)");
+        } else if (full) {
+            psStringAppend(&query, " AND (!clean)");
+        }
+    } else if (clean) {
+        psStringAppend(&query, " WHERE clean");
+    } else if (full) {
+        psStringAppend(&query, " WHERE !clean");
+    }
+    psFree(where);
+
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("disttool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+
+    if (!ippdbPrintMetadatas(stdout, output, "rcInterest", !simple)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to print array");
+        psFree(output);
+        return false;
+    }
+
+    psFree(output);
+
+    return true;
+}
Index: branches/eam_branches/20090820/ippTools/src/disttool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/disttool.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/disttool.h	(revision 25766)
@@ -31,4 +31,5 @@
     DISTTOOL_MODE_PENDINGCOMPONENT,
     DISTTOOL_MODE_ADDPROCESSEDCOMPONENT,
+    DISTTOOL_MODE_REVERTCOMPONENT,
     DISTTOOL_MODE_PROCESSEDCOMPONENT,
     DISTTOOL_MODE_TOADVANCE,
@@ -42,6 +43,4 @@
     DISTTOOL_MODE_DEFINEDESTINATION,
     DISTTOOL_MODE_UPDATEDESTINATION,
-    DISTTOOL_MODE_DEFINEDSPRODUCT,
-    DISTTOOL_MODE_UPDATEDSPRODUCT,
     DISTTOOL_MODE_DEFINETARGET,
     DISTTOOL_MODE_UPDATETARGET,
@@ -49,4 +48,5 @@
     DISTTOOL_MODE_DEFINEINTEREST,
     DISTTOOL_MODE_UPDATEINTEREST,
+    DISTTOOL_MODE_LISTINTERESTS,
 } disttoolMode;
 
Index: branches/eam_branches/20090820/ippTools/src/disttoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/disttoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/disttoolConfig.c	(revision 25766)
@@ -95,6 +95,6 @@
     // -pendingcomponent
     psMetadata *pendingcomponentArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingcomponentArgs, PS_LIST_TAIL, "-stage",    0, "limit results to runs for stage (required)", NULL);
     psMetadataAddS64(pendingcomponentArgs, PS_LIST_TAIL, "-dist_id", 0, "define dist_id", 0);
-    psMetadataAddStr(pendingcomponentArgs, PS_LIST_TAIL, "-stage",    0, "limit results to runs for stage", NULL);
     psMetadataAddStr(pendingcomponentArgs, PS_LIST_TAIL, "-label",    PS_META_DUPLICATE_OK, "limit results to label", NULL);
     psMetadataAddU64(pendingcomponentArgs, PS_LIST_TAIL, "-limit",  0,  "limit result set to N items", 0);
@@ -111,4 +111,15 @@
     psMetadataAddS32(addprocessedcomponentArgs, PS_LIST_TAIL, "-fault", 0, "define fault code", 0);
 
+    // -revertcomponent
+    psMetadata *revertcomponentArgs = psMetadataAlloc();
+    psMetadataAddS64(revertcomponentArgs, PS_LIST_TAIL, "-dist_id", 0, "define dist_id", 0);
+    psMetadataAddStr(revertcomponentArgs, PS_LIST_TAIL, "-component", 0, "define component", NULL);
+    psMetadataAddStr(revertcomponentArgs, PS_LIST_TAIL, "-stage",    0, "define stage", NULL);
+    psMetadataAddS64(revertcomponentArgs, PS_LIST_TAIL, "-stage_id", 0, "define stage_id", 0);
+    psMetadataAddStr(revertcomponentArgs, PS_LIST_TAIL, "-state",    0, "define state", NULL);
+    psMetadataAddStr(revertcomponentArgs, PS_LIST_TAIL, "-label",    0, "define label", NULL);
+    psMetadataAddS16(revertcomponentArgs, PS_LIST_TAIL, "-fault", 0, "define fault code", 0);
+    psMetadataAddBool(revertcomponentArgs, PS_LIST_TAIL, "-all",    0, "revert all faulted runs", NULL);
+
     // -processedcomponent
     psMetadata *processedcomponentArgs = psMetadataAlloc();
@@ -135,5 +146,5 @@
     psMetadata *addfilesetArgs = psMetadataAlloc();
     psMetadataAddS64(addfilesetArgs, PS_LIST_TAIL, "-dist_id", 0, "define dist_id", 0);
-    psMetadataAddS64(addfilesetArgs, PS_LIST_TAIL, "-prod_id", 0, "define prod_id", 0);
+    psMetadataAddS64(addfilesetArgs, PS_LIST_TAIL, "-dest_id", 0, "define dest_id", 0);
     psMetadataAddStr(addfilesetArgs, PS_LIST_TAIL, "-name",    0, "define file name", NULL);
     psMetadataAddS32(addfilesetArgs, PS_LIST_TAIL, "-fault",   0, "define fault code", 0);
@@ -150,5 +161,5 @@
     psMetadataAddS64(revertfilesetArgs, PS_LIST_TAIL, "-fs_id",   0, "define fs_id", 0);
     psMetadataAddS64(revertfilesetArgs, PS_LIST_TAIL, "-dist_id", 0, "define dist_id", 0);
-    psMetadataAddS64(revertfilesetArgs, PS_LIST_TAIL, "-prod_id", 0, "define dist_id", 0);
+    psMetadataAddS64(revertfilesetArgs, PS_LIST_TAIL, "-dest_id", 0, "define dist_id", 0);
     psMetadataAddStr(revertfilesetArgs, PS_LIST_TAIL, "-stage",   0, "define stage", NULL);
     psMetadataAddS64(revertfilesetArgs, PS_LIST_TAIL, "-stage_id",0, "define stage_id", 0);
@@ -162,5 +173,4 @@
     psMetadataAddS64(queuercrunArgs, PS_LIST_TAIL, "-dist_id",   0, "define dist_id", 0);
     psMetadataAddS64(queuercrunArgs, PS_LIST_TAIL, "-dest_id",   0, "define dest_id", 0);
-    psMetadataAddS64(queuercrunArgs, PS_LIST_TAIL, "-prod_id",   0, "define prod_id", 0);
     psMetadataAddS64(queuercrunArgs, PS_LIST_TAIL, "-target_id", 0, "define target_id", 0);
     psMetadataAddS64(queuercrunArgs, PS_LIST_TAIL, "-fs_id",     0, "define fs_id", 0);
@@ -189,22 +199,9 @@
     psMetadataAddBool(revertrcrunArgs, PS_LIST_TAIL, "-all",     0, "revert all faulted runs", NULL);
 
-    // -definedsproduct
-    psMetadata *definedsproductArgs = psMetadataAlloc();
-    psMetadataAddStr(definedsproductArgs, PS_LIST_TAIL, "-name",  0, "define product name", NULL);
-    psMetadataAddStr(definedsproductArgs, PS_LIST_TAIL, "-ds_dbname",0, "define data store database name", NULL);
-    psMetadataAddStr(definedsproductArgs, PS_LIST_TAIL, "-ds_dbhost",0, "define data store database host", NULL);
-
-    // -updatedsproduct
-    // does this mode make sense?
-    psMetadata *updatedsproductArgs = psMetadataAlloc();
-    psMetadataAddS64(updatedsproductArgs, PS_LIST_TAIL, "-prod_id",   0, "select by prod_id", 0);
-    // can't select by name because it isn't necssarily unique
-    psMetadataAddStr(updatedsproductArgs, PS_LIST_TAIL, "-ds_dbname",0, "define data store database name", NULL);
-    psMetadataAddStr(updatedsproductArgs, PS_LIST_TAIL, "-ds_dbhost",0, "define data store database host", NULL);
-
     // -definedestination
     psMetadata *definedestinationArgs = psMetadataAlloc();
-    psMetadataAddS64(definedestinationArgs, PS_LIST_TAIL, "-prod_id",     0, "define prod_id (required)", 0);
     psMetadataAddStr(definedestinationArgs, PS_LIST_TAIL, "-name",        0, "define destination name (required)", NULL);
+    psMetadataAddStr(definedestinationArgs, PS_LIST_TAIL, "-ds_dbname",0, "define data store database name (required)", NULL);
+    psMetadataAddStr(definedestinationArgs, PS_LIST_TAIL, "-ds_dbhost",0, "define data store database host (required)", NULL);
     psMetadataAddStr(definedestinationArgs, PS_LIST_TAIL, "-status_uri",  0, "define status_uri", NULL);
     psMetadataAddStr(definedestinationArgs, PS_LIST_TAIL, "-comment",     0, "define comment", NULL);
@@ -215,10 +212,7 @@
     psMetadata *updatedestinationArgs = psMetadataAlloc();
     psMetadataAddS64(updatedestinationArgs, PS_LIST_TAIL, "-dest_id",     0, "define dest_id", 0);
-    psMetadataAddS64(updatedestinationArgs, PS_LIST_TAIL, "-prod_id",     0, "define prod_id", 0);
     psMetadataAddStr(updatedestinationArgs, PS_LIST_TAIL, "-name",        0, "define destination name", NULL);
     psMetadataAddStr(updatedestinationArgs, PS_LIST_TAIL, "-status_uri",  0, "define status_uri", NULL);
     psMetadataAddStr(updatedestinationArgs, PS_LIST_TAIL, "-comment",     0, "define comment", NULL);
-//  last_fileset gets updated by -updatercrun
-//  psMetadataAddStr(updatedestinationArgs, PS_LIST_TAIL, "-set_last_fileset",0, "define last_fileset", NULL);
     psMetadataAddStr(updatedestinationArgs, PS_LIST_TAIL, "-set_state",   0, "define state", NULL);
 
@@ -254,7 +248,13 @@
     // -defineinterest
     psMetadata *defineinterestArgs = psMetadataAlloc();
-    psMetadataAddS64(defineinterestArgs, PS_LIST_TAIL, "-dest_id",   0, "define dest_id (required)", 0);
-    psMetadataAddS64(defineinterestArgs, PS_LIST_TAIL, "-target_id", 0, "define target_id (required)", 0);
+    psMetadataAddS64(defineinterestArgs, PS_LIST_TAIL, "-dest_id",   0, "define dest_id", 0);
+    psMetadataAddStr(defineinterestArgs, PS_LIST_TAIL, "-dest_name", 0, "define destination name (LIKE comparison)", NULL);
+    psMetadataAddS64(defineinterestArgs, PS_LIST_TAIL, "-target_id", 0, "define target_id", 0);
+    psMetadataAddStr(defineinterestArgs, PS_LIST_TAIL, "-stage",     0, "define stage", NULL);
+    psMetadataAddStr(defineinterestArgs, PS_LIST_TAIL, "-label",     0, "define label", NULL);
+    psMetadataAddStr(defineinterestArgs, PS_LIST_TAIL, "-filter",    0, "define filter (LIKE comparison)", NULL);
+    psMetadataAddBool(defineinterestArgs, PS_LIST_TAIL,"-clean",     0, "list clean targets", false);
     psMetadataAddStr(defineinterestArgs, PS_LIST_TAIL, "-set_state", 0, "define state", NULL);
+    psMetadataAddU64(defineinterestArgs, PS_LIST_TAIL, "-limit",     0, "limit number of targets listed to N", 0);
 
     // -updateinterest
@@ -265,4 +265,19 @@
     psMetadataAddStr(updateinterestArgs, PS_LIST_TAIL, "-set_state", 0, "define state (required)", NULL);
 
+    // -listinterests
+    psMetadata *listinterestsArgs = psMetadataAlloc();
+    psMetadataAddS64(listinterestsArgs, PS_LIST_TAIL, "-target_id", 0, "list interests with target_id", 0);
+    psMetadataAddS64(listinterestsArgs, PS_LIST_TAIL, "-dest_id", 0, "list interests with dest_id", 0);
+    psMetadataAddS64(listinterestsArgs, PS_LIST_TAIL, "-int_id", 0, "list interests with int_id", 0);
+    psMetadataAddStr(listinterestsArgs, PS_LIST_TAIL, "-dest_name",  0, "list interests for destinationn name)", NULL);
+    psMetadataAddStr(listinterestsArgs, PS_LIST_TAIL, "-label",  0, "list interests for label (LIKE comparison)", NULL);
+    psMetadataAddStr(listinterestsArgs, PS_LIST_TAIL, "-filter",    0, "list interests by filter (LIKE comparison)", NULL);
+    psMetadataAddStr(listinterestsArgs, PS_LIST_TAIL, "-stage",     0, "list interests for stage", NULL);
+    psMetadataAddBool(listinterestsArgs, PS_LIST_TAIL,"-clean",     0, "list clean interests", false);
+    psMetadataAddBool(listinterestsArgs, PS_LIST_TAIL,"-full",      0, "list full interests", false);
+    psMetadataAddStr(listinterestsArgs, PS_LIST_TAIL, "-state",     0, "list interests in state", NULL);
+    psMetadataAddU64(listinterestsArgs, PS_LIST_TAIL, "-limit",     0, "limit number of interests listed to N", 0);
+    psMetadataAddBool(listinterestsArgs, PS_LIST_TAIL, "-simple",  0, "use the simple output format", false);
+
     psMetadata *argSets = psMetadataAlloc();
     psMetadata *modes = psMetadataAlloc();
@@ -272,6 +287,7 @@
     PXOPT_ADD_MODE("-updaterun",    "", DISTTOOL_MODE_UPDATERUN, updaterunArgs);
     PXOPT_ADD_MODE("-revertrun",    "", DISTTOOL_MODE_REVERTRUN, revertrunArgs);
-    PXOPT_ADD_MODE("-pendingcomponent",       "", DISTTOOL_MODE_PENDINGCOMPONENT,    pendingcomponentArgs);
-    PXOPT_ADD_MODE("-addprocessedcomponent",      "", DISTTOOL_MODE_ADDPROCESSEDCOMPONENT, addprocessedcomponentArgs);
+    PXOPT_ADD_MODE("-pendingcomponent",   "", DISTTOOL_MODE_PENDINGCOMPONENT,    pendingcomponentArgs);
+    PXOPT_ADD_MODE("-addprocessedcomponent", "", DISTTOOL_MODE_ADDPROCESSEDCOMPONENT, addprocessedcomponentArgs);
+    PXOPT_ADD_MODE("-revertcomponent",    "", DISTTOOL_MODE_REVERTCOMPONENT, revertcomponentArgs);
     PXOPT_ADD_MODE("-processedcomponent", "", DISTTOOL_MODE_PROCESSEDCOMPONENT, processedcomponentArgs);
     PXOPT_ADD_MODE("-toadvance",          "", DISTTOOL_MODE_TOADVANCE, toadvanceArgs);
@@ -284,8 +300,4 @@
     PXOPT_ADD_MODE("-pendingdest",        "", DISTTOOL_MODE_PENDINGDEST, pendingdestArgs);
 
-    PXOPT_ADD_MODE("-definedsproduct",    "", DISTTOOL_MODE_DEFINEDSPRODUCT, definedsproductArgs);
-    PXOPT_ADD_MODE("-updatedsproduct",    "", DISTTOOL_MODE_UPDATEDSPRODUCT, updatedsproductArgs);
-//  PXOPT_ADD_MODE("-listdsproduct",      "", DISTTOOL_MODE_LISTDSPRODUCT, updatedsproductArgs);
-
     PXOPT_ADD_MODE("-definedestination",  "", DISTTOOL_MODE_DEFINEDESTINATION, definedestinationArgs);
     PXOPT_ADD_MODE("-updatedestination",  "", DISTTOOL_MODE_UPDATEDESTINATION, updatedestinationArgs);
@@ -298,5 +310,5 @@
     PXOPT_ADD_MODE("-defineinterest",     "", DISTTOOL_MODE_DEFINEINTEREST, defineinterestArgs);
     PXOPT_ADD_MODE("-updateinterest",     "", DISTTOOL_MODE_UPDATEINTEREST, updateinterestArgs);
-//  PXOPT_ADD_MODE("-listinterest",       "", DISTTOOL_MODE_LISTINTEREST, listinterestArgs);
+    PXOPT_ADD_MODE("-listinterests",       "", DISTTOOL_MODE_LISTINTERESTS, listinterestsArgs);
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
Index: branches/eam_branches/20090820/ippTools/src/faketool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/faketool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/faketool.c	(revision 25766)
@@ -52,4 +52,5 @@
 static bool tofullimfileMode(pxConfig *config);
 static bool topurgedimfileMode(pxConfig *config);
+static bool toscrubbedimfileMode(pxConfig *config);
 static bool exportrunMode(pxConfig *config);
 static bool importrunMode(pxConfig *config);
@@ -91,4 +92,5 @@
         MODECASE(FAKETOOL_MODE_TOFULLIMFILE,            tofullimfileMode);
         MODECASE(FAKETOOL_MODE_TOPURGEDIMFILE,          topurgedimfileMode);
+	MODECASE(FAKETOOL_MODE_TOSCRUBBEDIMFILE,        toscrubbedimfileMode);
         MODECASE(FAKETOOL_MODE_EXPORTRUN,               exportrunMode);
         MODECASE(FAKETOOL_MODE_IMPORTRUN,               importrunMode);
@@ -1251,4 +1253,8 @@
     return change_imfile_data_state(config, "purged", "goto_purged");
 }
+static bool toscrubbedimfileMode(pxConfig *config)
+{
+     return change_imfile_data_state(config, "scrubbed", "goto_scrubbed");
+}
 
 bool exportrunMode(pxConfig *config)
Index: branches/eam_branches/20090820/ippTools/src/faketool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/faketool.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/faketool.h	(revision 25766)
@@ -45,4 +45,5 @@
     FAKETOOL_MODE_TOFULLIMFILE,
     FAKETOOL_MODE_TOPURGEDIMFILE,
+    FAKETOOL_MODE_TOSCRUBBEDIMFILE,
     FAKETOOL_MODE_EXPORTRUN,
     FAKETOOL_MODE_IMPORTRUN
Index: branches/eam_branches/20090820/ippTools/src/faketoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/faketoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/faketoolConfig.c	(revision 25766)
@@ -301,4 +301,9 @@
     psMetadataAddStr(topurgedimfileArgs, PS_LIST_TAIL, "-class_id",  0,        "class ID to update", NULL);
 
+    // -toscrubbedimfile
+    psMetadata *toscrubbedimfileArgs = psMetadataAlloc();
+    psMetadataAddS64(toscrubbedimfileArgs, PS_LIST_TAIL, "-fake_id", 0,         "fake ID to update", 0);
+    psMetadataAddStr(toscrubbedimfileArgs, PS_LIST_TAIL, "-class_id", 0,        "class ID to update", NULL);
+
     // -exportrun
     psMetadata *exportrunArgs = psMetadataAlloc();
@@ -337,4 +342,5 @@
     PXOPT_ADD_MODE("-tofullimfile",        "set imfile state to full",               FAKETOOL_MODE_TOFULLIMFILE,         tofullimfileArgs);
     PXOPT_ADD_MODE("-topurgedimfile",      "set imfile state to purged",             FAKETOOL_MODE_TOPURGEDIMFILE,       topurgedimfileArgs);
+    PXOPT_ADD_MODE("-toscrubbedimfile",    "set imfile state to scrubbed",           FAKETOOL_MODE_TOSCRUBBEDIMFILE,     toscrubbedimfileArgs);
     PXOPT_ADD_MODE("-exportrun",            "export run for import on other database", FAKETOOL_MODE_EXPORTRUN, exportrunArgs);
     PXOPT_ADD_MODE("-importrun",            "import run from metadata file",           FAKETOOL_MODE_IMPORTRUN, importrunArgs);
Index: branches/eam_branches/20090820/ippTools/src/magicdstool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/magicdstool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/magicdstool.c	(revision 25766)
@@ -37,12 +37,12 @@
 static bool todestreakMode(pxConfig *config);
 static bool adddestreakedfileMode(pxConfig *config);
+static bool advancerunMode(pxConfig *config);
 static bool revertdestreakedfileMode(pxConfig *config);
 static bool getskycellsMode(pxConfig *config);
 static bool toremoveMode(pxConfig *config);
-static bool torestoreMode(pxConfig *config);
 static bool torevertMode(pxConfig *config);
+static bool completedrevertMode(pxConfig *config);
 
 static bool setmagicDSRunState(pxConfig *config, psS64 magic_id, const char *state);
-static bool magicDSRunComplete(pxConfig *config, bool setmagicked);
 static bool magicDSGetIDs(pxConfig *config, psString stage, psS64 magic_id, psS64 *stage_id, psS64 *cam_id);
 
@@ -70,9 +70,10 @@
         MODECASE(MAGICDSTOOL_MODE_TODESTREAK,          todestreakMode);
         MODECASE(MAGICDSTOOL_MODE_ADDDESTREAKEDFILE,   adddestreakedfileMode);
+        MODECASE(MAGICDSTOOL_MODE_ADVANCERUN,          advancerunMode);
         MODECASE(MAGICDSTOOL_MODE_REVERTDESTREAKEDFILE,revertdestreakedfileMode);
         MODECASE(MAGICDSTOOL_MODE_GETSKYCELLS,         getskycellsMode);
         MODECASE(MAGICDSTOOL_MODE_TOREMOVE,            toremoveMode);
-        MODECASE(MAGICDSTOOL_MODE_TORESTORE,           torestoreMode);
         MODECASE(MAGICDSTOOL_MODE_TOREVERT,            torevertMode);
+        MODECASE(MAGICDSTOOL_MODE_COMPLETEDREVERT,     completedrevertMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -105,5 +106,5 @@
     PXOPT_LOOKUP_STR(workdir, config->args, "-workdir", false, false);
     PXOPT_LOOKUP_STR(recoveryroot, config->args, "-recoveryroot", false, false);
-    PXOPT_LOOKUP_BOOL(re_place, config->args, "-replace", false);
+    PXOPT_LOOKUP_BOOL(noreplace, config->args, "-noreplace", false);
     PXOPT_LOOKUP_STR(set_label, config->args, "-set_label", false, false);
     PXOPT_LOOKUP_BOOL(rerun, config->args, "-rerun", false);
@@ -119,5 +120,5 @@
     PXOPT_COPY_S64(config->args, where, "-warp_id", "warp_id", "==");
     PXOPT_COPY_S64(config->args, where, "-diff_id", "diff_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-magic_id","magic_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-magic_id","magicRun.magic_id", "==");
     PXOPT_COPY_S32(config->args, where, "-streaks_max","streaks", "<=");
 
@@ -268,5 +269,5 @@
                 outroot,
                 recoveryroot,
-                re_place,
+                noreplace ? 0 :1,   // re_place
                 0); // remove
 
@@ -396,23 +397,28 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
+    PXOPT_LOOKUP_STR(stage, config->args, "-stage", true, false);
+
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-magic_ds_id", "magic_ds_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-magic_ds_id", "magicDSRun.magic_ds_id", "==");
     PXOPT_COPY_S64(config->args, where, "-magic_id", "magic_id", "==");
-    pxAddLabelSearchArgs (config, where, "-label", "label", "==");
-    PXOPT_COPY_STR(config->args, where, "-stage", "stage", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "magicDSRun.label", "==");
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
-    // look for "inputs" that need to processed
-    psString query = pxDataGet("magicdstool_todestreak.sql");
+    psString sql_file = NULL;
+    psStringAppend(&sql_file, "magicdstool_todestreak_%s.sql", stage);
+
+    psString query = pxDataGet(sql_file);
     if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement from %s", sql_file);
+        psFree(sql_file);
+        return false;
+    }
+    psFree(sql_file);
 
     if (psListLength(where->list)) {
         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " WHERE %s", whereClause);
+        psStringAppend(&query, " AND %s", whereClause);
         psFree(whereClause);
     }
@@ -656,13 +662,4 @@
     }
 
-    if (!magicDSRunComplete(config, setmagicked)) {
-            // rollback
-        if (!psDBRollback(config->dbh)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-        }
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
     if (!psDBCommit(config->dbh)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -738,7 +735,13 @@
 }
 
-static bool magicDSRunComplete(pxConfig *config, bool setmagicked)
+static bool advancerunMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-magic_ds_id", "magicDSRun.magic_ds_id", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "magicDSRun.label", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
 
     // look for completed magicDSRuns
@@ -749,4 +752,10 @@
     }
 
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+        psStringAppend(&query, " WHERE %s", whereClause);
+        psFree(whereClause);
+    }
+
     if (!p_psDBRunQuery(config->dbh, query)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -766,4 +775,8 @@
         return true;
     }
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
     for (long i = 0; i < psArrayLength(output); i++) {
         psMetadata *row = output->data[i];
@@ -771,8 +784,12 @@
         psS64 magic_ds_id = psMetadataLookupS64(NULL, row, "magic_ds_id");
 
-        // if requested, set stageRun.magicked
+        // if re_place, set stageRun.magicked
+        bool setmagicked = psMetadataLookupBool(NULL, row, "re_place");
         if (setmagicked && !setRunMagicked(config, magic_ds_id)) {
             psError(PS_ERR_UNKNOWN, false, "failed to change stageRun.magicked for magic_ds_id: %" PRId64,
                 magic_ds_id);
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
             return false;
         }
@@ -783,8 +800,14 @@
                 magic_ds_id);
             psFree(output);
+            if (!psDBRollback(config->dbh)) {
+                psError(PS_ERR_UNKNOWN, false, "database error");
+            }
             return false;
         }
     }
-
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
 
     return true;
@@ -795,4 +818,10 @@
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
+
+    PXOPT_LOOKUP_BOOL(i_am_sure, config->args, "-i_am_sure", true);
+    if (!i_am_sure) {
+        psError(PS_ERR_UNKNOWN, true, "Reverting destreaked files must be done carefully. -i_am_sure is required.");
+        return false;
+    }
 
     psMetadata *where = psMetadataAlloc();
@@ -802,5 +831,5 @@
     pxAddLabelSearchArgs (config, where, "-label", "label", "==");
 
-    psString query = psStringCopy("DELETE FROM magicDSFile USING magicDSFile, magicDSRun  WHERE (magicDSRun.magic_ds_id = magicDSFile.magic_ds_id) AND magicDSFile.fault != 0");
+    psString query = pxDataGet("magicdstool_revertdestreakedfile.sql");
 
     if (psListLength(where->list)) {
@@ -808,4 +837,7 @@
         psStringAppend(&query, " AND %s", whereClause);
         psFree(whereClause);
+    } else {
+        psError(PS_ERR_UNKNOWN, true, "search arguments are required");
+        return false;
     }
     psFree(where);
@@ -813,40 +845,44 @@
     if (!p_psDBRunQuery(config->dbh, query)) {
         psError(PS_ERR_UNKNOWN, false, "failed to revert");
-        return false;
-    }
-    return true;
-}
-
-static bool getskycellsMode(pxConfig *config)
-{
-    // required
-    PXOPT_LOOKUP_S64(magic_ds_id, config->args, "-magic_ds_id", true, false);
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+    return true;
+}
+
+static bool completedrevertMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_STR(config->args, where, "-class_id",    "warpSkyCellMap.class_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-skycell_id",  "warpSkyCellMap.skycell_id", "==");
-
-    PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
-
-    psString query = pxDataGet("magicdstool_getskycells.sql");
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
-        return false;
-    }
-
+    PXOPT_COPY_S64(config->args, where, "-magic_ds_id", "magicDSRun.magic_ds_id", "==");
+    pxAddLabelSearchArgs (config, where, "-label", "label", "==");
+
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+
+    psString query = pxDataGet("magicdstool_completedrevert.sql");
+    // treat limit == 0 as "no limit"
+    if (limit) {
+        psString limitString = psDBGenerateLimitSQL(limit);
+        psStringAppend(&query, " %s", limitString);
+        psFree(limitString);
+    }
+
+    psString whereString = NULL;
     if (psListLength(where->list)) {
         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " AND %s", whereClause);
+        psStringAppend(&whereString, "\nAND %s", whereClause);
         psFree(whereClause);
     }
     psFree(where);
 
-    if (!p_psDBRunQueryF(config->dbh, query, magic_ds_id)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        return false;
-    }
+    if (!p_psDBRunQueryF(config->dbh, query, whereString ? whereString : "")) {
+        psFree(whereString);
+        psError(PS_ERR_UNKNOWN, false, "failed to revert");
+        return false;
+    }
+    psFree(whereString);
     psFree(query);
-
     psArray *output = p_psDBFetchResult(config->dbh);
     if (!output) {
@@ -868,14 +904,24 @@
         return true;
     }
-
-    if (psArrayLength(output)) {
-        // negative simple so the default is true
-        if (!ippdbPrintMetadatas(stdout, output, "magicDiffSkyfile", !simple)) {
-            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+    for (int i=0; i<psArrayLength(output); i++) {
+        psMetadata *row = output->data[i];
+        psS64 magic_ds_id = psMetadataLookupS64(NULL, row, "magic_ds_id"); 
+        psString old_state = psMetadataLookupStr(NULL, row, "state"); 
+        psString new_state;
+        if (!strcmp(old_state, "goto_censored")) {
+            new_state = "censored";
+        } else if (!strcmp(old_state, "goto_restored")) {
+            new_state = "restored";
+        } else {
+            psError(PXTOOLS_ERR_PROG, true, "unexpected state found: %s", old_state);
             psFree(output);
             return false;
         }
-    }
-
+        char *query2 = "UPDATE magicDSRun SET state = '%s' WHERE magic_ds_id = %" PRId64;
+        if (!p_psDBRunQueryF(config->dbh, query2, new_state, magic_ds_id)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to set run magicDSRun.state to %s", new_state);
+            return false;
+        }
+    }
     psFree(output);
 
@@ -883,43 +929,16 @@
 }
 
-static bool setmagicDSRunState(pxConfig *config, psS64 magic_ds_id, const char *state)
-{
-    PS_ASSERT_PTR_NON_NULL(state, false);
-
-    // check that state is a valid string value
-    if (!(
-            (strncmp(state, "new", 4) == 0)
-            || (strncmp(state, "full", 5) == 0)
-        )
-    ) {
-        psError(PS_ERR_UNKNOWN, false,
-                "invalid magicDSRun state: %s", state);
-        return false;
-    }
-
-    char *query = "UPDATE magicDSRun SET state = '%s' WHERE magic_ds_id = %" PRId64;
-    if (!p_psDBRunQueryF(config->dbh, query, state, magic_ds_id)) {
-        psError(PS_ERR_UNKNOWN, false,
-                "failed to change state for magic_id %" PRId64, magic_ds_id);
-        return false;
-    }
-
-    return true;
-}
-
-static bool toremoveMode(pxConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
+static bool getskycellsMode(pxConfig *config)
+{
+    // required
+    PXOPT_LOOKUP_S64(magic_ds_id, config->args, "-magic_ds_id", true, false);
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-magic_ds_id", "magic_ds_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-magic_id", "magic_id", "==");
-    pxAddLabelSearchArgs (config, where, "-label", "label", "==");
-
-    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+    PXOPT_COPY_STR(config->args, where, "-class_id",    "warpSkyCellMap.class_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-skycell_id",  "warpSkyCellMap.skycell_id", "==");
+
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
-    // look for "inputs" that need to processed
-    psString query = pxDataGet("magicdstool_toremove.sql");
+    psString query = pxDataGet("magicdstool_getskycells.sql");
     if (!query) {
         psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
@@ -929,17 +948,10 @@
     if (psListLength(where->list)) {
         psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
-        psStringAppend(&query, " WHERE %s", whereClause);
+        psStringAppend(&query, " AND %s", whereClause);
         psFree(whereClause);
     }
     psFree(where);
 
-    // treat limit == 0 as "no limit"
-    if (limit) {
-        psString limitString = psDBGenerateLimitSQL(limit);
-        psStringAppend(&query, " %s", limitString);
-        psFree(limitString);
-    }
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
+    if (!p_psDBRunQueryF(config->dbh, query, magic_ds_id)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(query);
@@ -970,5 +982,5 @@
     if (psArrayLength(output)) {
         // negative simple so the default is true
-        if (!ippdbPrintMetadatas(stdout, output, "toremove", !simple)) {
+        if (!ippdbPrintMetadatas(stdout, output, "magicDiffSkyfile", !simple)) {
             psError(PS_ERR_UNKNOWN, false, "failed to print array");
             psFree(output);
@@ -981,5 +993,35 @@
     return true;
 }
-static bool torestoreMode(pxConfig *config)
+
+static bool setmagicDSRunState(pxConfig *config, psS64 magic_ds_id, const char *state)
+{
+    PS_ASSERT_PTR_NON_NULL(state, false);
+
+    // check that state is a valid string value
+    if (!((strcmp(state, "new") == 0) ||
+          (strcmp(state, "full") == 0) ||
+          (strcmp(state, "restored") == 0) ||
+          (strcmp(state, "censored") == 0) ||
+          (strcmp(state, "purged") == 0) ||
+          (strcmp(state, "goto_restored") == 0) ||
+          (strcmp(state, "goto_censored") == 0) ||
+          (strcmp(state, "goto_purged") == 0))
+        ) {
+        psError(PS_ERR_UNKNOWN, false,
+                "invalid magicDSRun state: %s", state);
+        return false;
+    }
+
+    char *query = "UPDATE magicDSRun SET state = '%s' WHERE magic_ds_id = %" PRId64;
+    if (!p_psDBRunQueryF(config->dbh, query, state, magic_ds_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for magic_id %" PRId64, magic_ds_id);
+        return false;
+    }
+
+    return true;
+}
+
+static bool toremoveMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -994,5 +1036,5 @@
 
     // look for "inputs" that need to processed
-    psString query = pxDataGet("magicdstool_torestore.sql");
+    psString query = pxDataGet("magicdstool_toremove.sql");
     if (!query) {
         psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
@@ -1043,5 +1085,5 @@
     if (psArrayLength(output)) {
         // negative simple so the default is true
-        if (!ippdbPrintMetadatas(stdout, output, "torestore", !simple)) {
+        if (!ippdbPrintMetadatas(stdout, output, "toremove", !simple)) {
             psError(PS_ERR_UNKNOWN, false, "failed to print array");
             psFree(output);
@@ -1054,5 +1096,4 @@
     return true;
 }
-
 
 static bool torevertMode(pxConfig *config)
Index: branches/eam_branches/20090820/ippTools/src/magicdstool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/magicdstool.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/magicdstool.h	(revision 25766)
@@ -30,9 +30,10 @@
     MAGICDSTOOL_MODE_TODESTREAK,
     MAGICDSTOOL_MODE_ADDDESTREAKEDFILE,
+    MAGICDSTOOL_MODE_ADVANCERUN,
     MAGICDSTOOL_MODE_REVERTDESTREAKEDFILE,
     MAGICDSTOOL_MODE_GETSKYCELLS,
     MAGICDSTOOL_MODE_TOREMOVE,
-    MAGICDSTOOL_MODE_TORESTORE,
     MAGICDSTOOL_MODE_TOREVERT,
+    MAGICDSTOOL_MODE_COMPLETEDREVERT,
 } MAGICDStoolMode;
 
Index: branches/eam_branches/20090820/ippTools/src/magicdstoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/magicdstoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/magicdstoolConfig.c	(revision 25766)
@@ -52,5 +52,5 @@
     psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-workdir",     0, "define workdir", NULL);
     psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-recoveryroot", 0, "define recovery directory", NULL);
-    psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-replace", 0, "replace input files with the destreaked versions", false);
+    psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-noreplace", 0, "do not replace input files with the destreaked versions", false);
     psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-set_label",    0, "define label", NULL);
 
@@ -75,6 +75,6 @@
     psMetadataAddStr(definerunArgs, PS_LIST_TAIL, "-outroot", 0, "define output directory (required)", NULL);
     psMetadataAddStr(definerunArgs, PS_LIST_TAIL, "-recoveryroot", 0, "define recovery directory", NULL);
-    psMetadataAddBool(definerunArgs, PS_LIST_TAIL, "-replace", 0, "use the simple output format", false);
-    psMetadataAddBool(definerunArgs, PS_LIST_TAIL, "-remove", 0, "use the simple output format", false);
+    psMetadataAddBool(definerunArgs, PS_LIST_TAIL, "-noreplace", 0, "do not replace the input wit with the destreaked versions", false);
+//    psMetadataAddBool(definerunArgs, PS_LIST_TAIL, "-remove", 0, "use the simple output format", false);
     psMetadataAddStr(definerunArgs, PS_LIST_TAIL, "-label", 0, "define label", NULL);
     psMetadataAddBool(definerunArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
@@ -93,8 +93,8 @@
     // -todestreak
     psMetadata *todestreakArgs = psMetadataAlloc();
+    psMetadataAddStr(todestreakArgs, PS_LIST_TAIL, "-stage", 0, "limit query to stage (required)", NULL);
     psMetadataAddS64(todestreakArgs, PS_LIST_TAIL, "-magic_ds_id", 0, "search by magic Destreak ID", 0);
     psMetadataAddS64(todestreakArgs, PS_LIST_TAIL, "-magic_id", 0, "search by magic ID", 0);
     psMetadataAddStr(todestreakArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "define label", NULL);
-    psMetadataAddStr(todestreakArgs, PS_LIST_TAIL, "-stage", 0, "limit query to stage", NULL);
     psMetadataAddU64(todestreakArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
     psMetadataAddBool(todestreakArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
@@ -114,9 +114,10 @@
     psMetadataAddStr(revertdestreakedfileArgs, PS_LIST_TAIL, "-component", 0, "search by component", NULL);
     psMetadataAddS16(revertdestreakedfileArgs, PS_LIST_TAIL, "-fault", 0, "search by fault code", 0);
+    psMetadataAddBool(revertdestreakedfileArgs, PS_LIST_TAIL, "-i_am_sure", 0, "confirm that you know what you are doing", false);
     psMetadataAddStr(revertdestreakedfileArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "define label", NULL);
 
     // -getskycells
     psMetadata *getskycellsArgs = psMetadataAlloc();
-    psMetadataAddS64(getskycellsArgs, PS_LIST_TAIL, "-magic_ds_id", 0, "define magic de-streak ID (required)", 0);
+    psMetadataAddS64(getskycellsArgs, PS_LIST_TAIL, "-magic_ds_id", 0, "define magic de-streak ID", 0);
     psMetadataAddStr(getskycellsArgs, PS_LIST_TAIL, "-class_id", 0, "define class identifier", NULL);
     psMetadataAddStr(getskycellsArgs, PS_LIST_TAIL, "-skycell_id", 0, "define skycell identifier", NULL);
@@ -130,12 +131,4 @@
     psMetadataAddU64(toremoveArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
     psMetadataAddBool(toremoveArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
-
-    // -torestore
-    psMetadata *torestoreArgs = psMetadataAlloc();
-    psMetadataAddS64(torestoreArgs, PS_LIST_TAIL, "-magic_ds_id", 0, "search by magic Destreak ID", 0);
-    psMetadataAddS64(torestoreArgs, PS_LIST_TAIL, "-magic_id", 0, "search by magic ID", 0);
-    psMetadataAddStr(torestoreArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "define label", NULL);
-    psMetadataAddU64(torestoreArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
-    psMetadataAddBool(torestoreArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
 
     // -torevert
@@ -147,4 +140,16 @@
     psMetadataAddU64(torevertArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
     psMetadataAddBool(torevertArgs, PS_LIST_TAIL, "-simple", 0, "use the simple output format", false);
+
+    // -completedrevert
+    psMetadata *completedrevertArgs = psMetadataAlloc();
+    psMetadataAddS64(completedrevertArgs, PS_LIST_TAIL, "-magic_ds_id", 0, "search by magic Destreak ID", 0);
+    psMetadataAddStr(completedrevertArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "define label", NULL);
+    psMetadataAddU64(completedrevertArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
+
+    // -advancerun
+    psMetadata *advancerunArgs = psMetadataAlloc();
+    psMetadataAddS64(advancerunArgs, PS_LIST_TAIL, "-magic_ds_id", 0, "search by magic Destreak ID", 0);
+    psMetadataAddStr(advancerunArgs, PS_LIST_TAIL, "-label", PS_META_DUPLICATE_OK, "define label", NULL);
+    psMetadataAddU64(advancerunArgs, PS_LIST_TAIL, "-limit", 0, "limit result set to N items", 0);
 
     psFree(now);
@@ -163,4 +168,6 @@
     PXOPT_ADD_MODE("-adddestreakedfile",   "add a de-streaked file",
                     MAGICDSTOOL_MODE_ADDDESTREAKEDFILE, adddestreakedfileArgs);
+    PXOPT_ADD_MODE("-advancerun", "change state for runs that have finished destrreaking",
+                    MAGICDSTOOL_MODE_ADVANCERUN, advancerunArgs);
     PXOPT_ADD_MODE("-revertdestreakedfile", " revert a faulted de-streaked file",
                     MAGICDSTOOL_MODE_REVERTDESTREAKEDFILE, revertdestreakedfileArgs);
@@ -169,8 +176,10 @@
     PXOPT_ADD_MODE("-toremove", "backup images pending removal",
                     MAGICDSTOOL_MODE_TOREMOVE, toremoveArgs);
-    PXOPT_ADD_MODE("-torestore", "images pending restore of exicsed streak pixels",
-                    MAGICDSTOOL_MODE_TORESTORE, torestoreArgs);
-    PXOPT_ADD_MODE("-torevert", "faulted images to revert",
+    PXOPT_ADD_MODE("-torevert", "images to restore or revert",
                     MAGICDSTOOL_MODE_TOREVERT, torevertArgs);
+
+    PXOPT_ADD_MODE("-completedrevert", "change state for runs that have finished reverting",
+                    MAGICDSTOOL_MODE_COMPLETEDREVERT, completedrevertArgs);
+
 
     if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
Index: branches/eam_branches/20090820/ippTools/src/magictool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/magictool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/magictool.c	(revision 25766)
@@ -1393,46 +1393,25 @@
 }
 
-static bool censorStage(pxConfig *config, psString stage, psString whereClause)
-{
-    psString queryFile = NULL;
-    psStringAppend(&queryFile, "magictool_censor_%s.sql", stage);
-    psString query = pxDataGet(queryFile);
-    if (!query) {
-        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement from %s", queryFile);
-        psFree(queryFile);
-        if (!psDBRollback(config->dbh)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-        }
-        return false;
-    }
-    psFree(queryFile);
-
-    psStringAppend(&query, " WHERE %s",  whereClause);
-
-    if (!p_psDBRunQuery(config->dbh, query)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        psFree(query);
-        if (!psDBRollback(config->dbh)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-        }
-        return false;
-    }
-    psFree(query);
-
-    return true;
-}
-
 static bool censorrunMode(pxConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    psError(PS_ERR_PROGRAMMING, true, "-censorrun mode not ready yet");
-    return false;
-
     psMetadata *where = psMetadataAlloc();
+
+    PXOPT_LOOKUP_S64(magic_id, config->args, "-magic_id", false, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", false, false);
+    PXOPT_LOOKUP_STR(label, config->args, "-label", false, false);
+
+    if (!magic_id) {
+        if (!exp_id && !label) {
+            psError(PS_ERR_UNKNOWN, true, "either -magic_id or exp_id and label is required");
+            return false;
+        }
+    }
 
     // at least one of these required
     PXOPT_COPY_S64(config->args, where, "-magic_id", "magic_id", "==");
     PXOPT_COPY_S64(config->args, where, "-exp_id", "exp_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-label", "label", "==");
 
     if (!psListLength(where->list)) {
@@ -1470,22 +1449,22 @@
     // Now queue any destreaked files to be re-verted
 
-    // note: on failure censorStage issues the rollback
-    if (!censorStage(config, "raw", whereClause)) {
+    // note: on failure magicRestoreStage issues the rollback
+    if (!magicRestoreStage(config, "raw", whereClause, "goto_censored")) {
         psFree(whereClause);
         return false;
     }
-    if (!censorStage(config, "chip", whereClause)) {
+    if (!magicRestoreStage(config, "chip", whereClause, "goto_censored")) {
         psFree(whereClause);
         return false;
     }
-    if (!censorStage(config, "camera", whereClause)) {
+    if (!magicRestoreStage(config, "camera", whereClause, "goto_censored")) {
         psFree(whereClause);
         return false;
     }
-    if (!censorStage(config, "warp", whereClause)) {
+    if (!magicRestoreStage(config, "warp", whereClause, "goto_censored")) {
         psFree(whereClause);
         return false;
     }
-    if (!censorStage(config, "diff", whereClause)) {
+    if (!magicRestoreStage(config, "diff", whereClause, "goto_censored")) {
         psFree(whereClause);
         return false;
Index: branches/eam_branches/20090820/ippTools/src/magictoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/magictoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/magictoolConfig.c	(revision 25766)
@@ -165,4 +165,5 @@
     psMetadataAddS64(censorrunArgs, PS_LIST_TAIL, "-magic_id", 0, "define magictool ID", 0);
     psMetadataAddS64(censorrunArgs, PS_LIST_TAIL, "-exp_id", 0, "define exposure ID", 0);
+    psMetadataAddStr(censorrunArgs, PS_LIST_TAIL, "-label",       0, "define label", NULL);
 
     psFree(now);
Index: branches/eam_branches/20090820/ippTools/src/pstamptool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pstamptool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pstamptool.c	(revision 25766)
@@ -44,4 +44,5 @@
 static bool pendingjobMode(pxConfig *config);
 static bool updatejobMode(pxConfig *config);
+static bool revertjobMode(pxConfig *config);
 static bool addprojectMode(pxConfig *config);
 static bool projectMode(pxConfig *config);
@@ -80,4 +81,5 @@
         MODECASE(PSTAMPTOOL_MODE_PENDINGJOB, pendingjobMode);
         MODECASE(PSTAMPTOOL_MODE_UPDATEJOB, updatejobMode);
+        MODECASE(PSTAMPTOOL_MODE_REVERTJOB, revertjobMode);
         MODECASE(PSTAMPTOOL_MODE_ADDPROJECT, addprojectMode);
         MODECASE(PSTAMPTOOL_MODE_MODPROJECT, modprojectMode);
@@ -224,21 +226,21 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    PXOPT_LOOKUP_STR(uri,         config->args, "-uri",           true, false);
-    // PXOPT_LOOKUP_STR(outFileset,  config->args, "-out_fileset",   true, false);
-    PXOPT_LOOKUP_S64(ds_id,       config->args, "-ds_id",         false, false);
-
-    char *query ="INSERT INTO pstampRequest"
-                     " (state, uri, ds_id, fault)"
-                     " VALUES( 'new', '%s', %" PRId64 ", 0 )";
-    if (!p_psDBRunQueryF(config->dbh, query, uri, ds_id)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    psU64 affected = psDBAffectedRows(config->dbh);
-    if (affected != 1) {
-        psError(PS_ERR_UNKNOWN, false, 
-            "should have affected one row but %" PRIu64 " rows were modified",
-            affected);
+    PXOPT_LOOKUP_STR(uri,         config->args, "-uri",   true, false);
+    PXOPT_LOOKUP_STR(name,        config->args, "-name",  false, false);
+    PXOPT_LOOKUP_STR(label,       config->args, "-label",  false, false);
+    PXOPT_LOOKUP_S64(ds_id,       config->args, "-ds_id", false, false);
+
+    if (!pstampRequestInsert(config->dbh,
+        0,      // req_id
+        ds_id,
+        "new",  //state
+        name,
+        NULL,   // reqType
+        label,
+        NULL,   // outProduct
+        uri,    
+        0       // fault 
+        )) {
+        psError(PS_ERR_UNKNOWN, false, "failed to insert request");
         return false;
     }
@@ -317,4 +319,5 @@
     psMetadata *where = psMetadataAlloc();
     PXOPT_COPY_S64(config->args, where, "-req_id", "req_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-not_req_id", "req_id", "!=");
     PXOPT_COPY_STR(config->args, where, "-name", "name", "==");
 
@@ -381,8 +384,5 @@
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
-    psString query = 
-        "SELECT * FROM pstampRequest WHERE state = 'run' AND "
-            "(SELECT count(*) FROM pstampJob WHERE pstampJob.req_id = pstampRequest.req_id "
-            " AND pstampJob.state != 'stop') = 0" ;
+    psString query = pxDataGet("pstamptool_completedreq.sql");
 
     // treat limit == 0 as "no limit"
@@ -491,17 +491,40 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    PXOPT_LOOKUP_S64(req_id,     config->args, "-req_id",     true, false);
-
-    // printf("Revert request %" PRId64 "\n", req_id);
+    psMetadata *where = psMetadataAlloc();
+
+    PXOPT_COPY_S64(config->args, where, "-req_id", "req_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-fault", "req_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-state", "pstampRequest.state", "==");
+
+    if (!psListLength(where->list)) {
+        psFree(where);
+        psError(PXTOOLS_ERR_DATA, false, "search parameters are required");
+        return false;
+    }
+
+    psString whereClause = psDBGenerateWhereConditionSQL(where, NULL);
+    psFree(where);
+
+    // delete any jobs that were queued by requests that didn't complete parsing (pstampRequest.state = 'new'
+    // If state =  'run' was supplied this will be a no-op
+    psString query = pxDataGet("pstamptool_revertreq_deletejobs.sql");
+    psStringAppend(&query, " AND %s", whereClause);
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    psFree(query);
+
+    // clear fault for requests
+    query = pxDataGet("pstamptool_revertreq.sql");
+    psStringAppend(&query, " AND %s", whereClause);
     
-    if (!p_psDBRunQueryF(config->dbh, "DELETE FROM pstampJob where req_id = %" PRId64, req_id)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-    if (!p_psDBRunQueryF(config->dbh, 
-        "UPDATE pstampRequest set state ='new', name=NULL, reqType=NULL, fault=0 where req_id = %" PRId64, req_id)) {
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
+    psFree(whereClause);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    psFree(query);
 
     return true;
@@ -521,4 +544,5 @@
     PXOPT_LOOKUP_S16(fault,       config->args, "-fault",      false, false);
     PXOPT_LOOKUP_S64(exp_id,      config->args, "-exp_id",     false, false);
+    PXOPT_LOOKUP_S64(options,     config->args, "-options",     false, false);
 
     // unless the job is being inserted with stop state require outputBase
@@ -545,5 +569,6 @@
             fault, 
             exp_id, 
-            outputBase
+            outputBase,
+            options
             )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -569,34 +594,30 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    PXOPT_LOOKUP_S64(req_id, config->args, "-req_id", false, false);
-    PXOPT_LOOKUP_S64(job_id, config->args, "-job_id", false, false);
+    psMetadata *where = psMetadataAlloc();
+    PXOPT_COPY_S64(config->args, where, "-job_id", "job_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-req_id", "req_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-fault",  "fault", "==");
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
-    psString query = NULL;
-
-    if (!req_id && !job_id) {
-        fprintf(stderr, "either req_id or job_id must be specified\n");
+    if (!psListLength(where->list)) {
+        fprintf(stderr, "search arguments are required\n");
         exit (1);
     }
 
-    if (req_id) {
-        psStringAppend(&query,
-                "SELECT"
-                " pstampJob.*, pstampRequest.name, pstampRequest.outProduct"
-                " FROM pstampJob"
-                " JOIN pstampRequest USING(req_id)"
-                " WHERE req_id = %" PRId64, req_id
-            );
-    } else {
-        psStringAppend(&query,
-                "SELECT"
-                " pstampJob.*, pstampRequest.name, pstampRequest.outProduct"
-                " FROM pstampJob"
-                " JOIN pstampRequest USING(req_id)"
-                " WHERE job_id = %" PRId64, job_id
-            );
-    } 
+    psString query = pxDataGet("pstamptool_listjob.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    // use psDBGenerateWhereSQL because the SQL yields an intermediate table
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "pstampJob");
+        psStringAppend(&query, " WHERE %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
 
     // treat limit == 0 as "no limit"
@@ -729,4 +750,38 @@
         psError(PS_ERR_UNKNOWN, false, "should have affected one row but %" 
                                         PRIu64 " rows were modified", affected);
+        return false;
+    }
+
+    return true;
+}
+
+static bool revertjobMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    psMetadata *where = psMetadataAlloc();
+
+    PXOPT_COPY_S64(config->args, where, "-job_id", "job_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-req_id", "req_id", "==");
+    PXOPT_COPY_S64(config->args, where, "-fault",  "fault", "==");
+    PXOPT_COPY_S64(config->args, where, "-req_id_min",  "req_id", ">=");
+    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
+    PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
+
+    psString query = pxDataGet("pstamptool_revertjob.sql");
+    if (!psListLength(where->list) && !all) {
+        psFree(where);
+        psError(PXTOOLS_ERR_DATA, false, "search parameters or -all are required");
+        return false;
+    }
+    if (psListLength(where->list)) {
+        psString whereClause = psDBGenerateWhereConditionSQL(where, "pstampJob");
+        psStringAppend(&query, " AND %s", whereClause);
+        psFree(whereClause);
+    }
+    psFree(where);
+    
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
         return false;
     }
Index: branches/eam_branches/20090820/ippTools/src/pstamptool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pstamptool.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pstamptool.h	(revision 25766)
@@ -39,4 +39,5 @@
     PSTAMPTOOL_MODE_JOBRESULT,
     PSTAMPTOOL_MODE_UPDATEJOB,
+    PSTAMPTOOL_MODE_REVERTJOB,
     PSTAMPTOOL_MODE_ADDPROJECT,
     PSTAMPTOOL_MODE_MODPROJECT,
Index: branches/eam_branches/20090820/ippTools/src/pstamptoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pstamptoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pstamptoolConfig.c	(revision 25766)
@@ -63,7 +63,8 @@
     // -addreq
     psMetadata *addreqArgs = psMetadataAlloc();
-    psMetadataAddStr(addreqArgs, PS_LIST_TAIL, "-uri", 0,            "define request file uri (required)", NULL); 
-    psMetadataAddS64(addreqArgs, PS_LIST_TAIL, "-ds_id", 0,            "define request ds_id", 0); 
-    // psMetadataAddStr(addreqArgs, PS_LIST_TAIL, "-out_fileset", 0,            "define request output_fileset", NULL); 
+    psMetadataAddStr(addreqArgs, PS_LIST_TAIL, "-uri", 0,    "define request file uri (required)", NULL); 
+    psMetadataAddS64(addreqArgs, PS_LIST_TAIL, "-ds_id", 0,  "define request ds_id", 0); 
+    psMetadataAddStr(addreqArgs, PS_LIST_TAIL, "-name", 0,   "define request name", NULL); 
+    psMetadataAddStr(addreqArgs, PS_LIST_TAIL, "-label", 0,  "define request label", NULL); 
 
     // -pendingreq
@@ -77,6 +78,7 @@
     psMetadataAddS64(listreqArgs, PS_LIST_TAIL, "-req_id", 0,            "list by req_id", 0); 
     psMetadataAddStr(listreqArgs, PS_LIST_TAIL, "-name", 0,              "list by name", NULL); 
+    psMetadataAddS64(listreqArgs, PS_LIST_TAIL, "-not_req_id", 0,        "req_id to not list", 0); 
     psMetadataAddU64(listreqArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
-    psMetadataAddBool(listreqArgs, PS_LIST_TAIL, "-simple", 0,            "use the simple output format", false);
+    psMetadataAddBool(listreqArgs, PS_LIST_TAIL, "-simple", 0,           "use the simple output format", false);
 
     // -completedreq
@@ -97,22 +99,26 @@
     // -revertreq
     psMetadata *revertreqArgs = psMetadataAlloc();
-    psMetadataAddS64(revertreqArgs, PS_LIST_TAIL, "-req_id", 0,            "req_id for which to revert", 0); 
+    psMetadataAddS64(revertreqArgs, PS_LIST_TAIL, "-req_id", 0,     "req_id to revert", 0); 
+    psMetadataAddS16(revertreqArgs, PS_LIST_TAIL, "-fault",  0,     "fault to revert", 0); 
+    psMetadataAddStr(revertreqArgs, PS_LIST_TAIL, "-state", 0,      "state to revert", NULL); 
 
     // -addjob
     psMetadata *addjobArgs = psMetadataAlloc();
-    psMetadataAddS64(addjobArgs, PS_LIST_TAIL, "-req_id", 0,            "define job req_id", 0); 
-    psMetadataAddStr(addjobArgs, PS_LIST_TAIL, "-rownum", 0,            "define job rownum", NULL); 
-    psMetadataAddStr(addjobArgs, PS_LIST_TAIL, "-job_type", 0,            "define job job_type", "stamp"); 
-    psMetadataAddStr(addjobArgs, PS_LIST_TAIL, "-outputBase", 0,            "define job outputBase", NULL); 
-    psMetadataAddStr(addjobArgs, PS_LIST_TAIL, "-state", 0,            "new state", "run"); 
-    psMetadataAddS64(addjobArgs, PS_LIST_TAIL, "-exp_id", 0,           "exposure id", 0); 
-    psMetadataAddS16(addjobArgs, PS_LIST_TAIL, "-fault", 0,            "new result", 0); 
+    psMetadataAddS64(addjobArgs, PS_LIST_TAIL, "-req_id", 0,           "define job req_id", 0); 
+    psMetadataAddStr(addjobArgs, PS_LIST_TAIL, "-rownum", 0,           "define job rownum", NULL); 
+    psMetadataAddStr(addjobArgs, PS_LIST_TAIL, "-job_type", 0,         "define job job_type", "stamp"); 
+    psMetadataAddStr(addjobArgs, PS_LIST_TAIL, "-outputBase", 0,       "define job outputBase", NULL); 
+    psMetadataAddStr(addjobArgs, PS_LIST_TAIL, "-state", 0,            "define state", "run"); 
+    psMetadataAddS64(addjobArgs, PS_LIST_TAIL, "-exp_id", 0,           "define exposure id", 0); 
+    psMetadataAddS64(addjobArgs, PS_LIST_TAIL, "-options", 0,          "define options", 0); 
+    psMetadataAddS16(addjobArgs, PS_LIST_TAIL, "-fault", 0,            "define job result", 0); 
 
     // -listjob
     psMetadata *listjobArgs = psMetadataAlloc();
-    psMetadataAddS64(listjobArgs, PS_LIST_TAIL, "-req_id", 0,            "define request", 0); 
-    psMetadataAddS64(listjobArgs, PS_LIST_TAIL, "-job_id", 0,            "define job", 0); 
-    psMetadataAddU64(listjobArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
-    psMetadataAddBool(listjobArgs, PS_LIST_TAIL, "-simple", 0,            "use the simple output format", false);
+    psMetadataAddS64(listjobArgs, PS_LIST_TAIL, "-req_id", 0,          "select by request ID", 0); 
+    psMetadataAddS64(listjobArgs, PS_LIST_TAIL, "-job_id", 0,          "select by job ID", 0); 
+    psMetadataAddS16(listjobArgs, PS_LIST_TAIL, "-fault", 0,           "select by fault", 0); 
+    psMetadataAddU64(listjobArgs, PS_LIST_TAIL, "-limit",  0,          "limit result set to N items", 0);
+    psMetadataAddBool(listjobArgs, PS_LIST_TAIL, "-simple", 0,         "use the simple output format", false);
 
     // -pendingjob
@@ -128,4 +134,13 @@
     psMetadataAddStr(updatejobArgs, PS_LIST_TAIL, "-state", 0,            "new state", NULL); 
     psMetadataAddStr(updatejobArgs, PS_LIST_TAIL, "-fault", 0,            "new result", NULL); 
+
+    // -revertjob
+    psMetadata *revertjobArgs = psMetadataAlloc();
+    psMetadataAddS64(revertjobArgs, PS_LIST_TAIL, "-req_id", 0,     "req_id to revert", 0); 
+    psMetadataAddS64(revertjobArgs, PS_LIST_TAIL, "-req_id_min", 0, "minimum req_id to revert", 0); 
+    psMetadataAddS64(revertjobArgs, PS_LIST_TAIL, "-job_id", 0,     "job_id to revert", 0); 
+    psMetadataAddS16(revertjobArgs, PS_LIST_TAIL, "-fault",  0,     "fault to revert", 0); 
+    psMetadataAddBool(revertjobArgs, PS_LIST_TAIL, "-all", 0,       "revert all faulted jobs", false);
+    psMetadataAddU64(revertjobArgs, PS_LIST_TAIL, "-limit", 0,      "limit result set to N items", 0);
 
     // -addproject
@@ -159,5 +174,5 @@
     PXOPT_ADD_MODE("-addreq",          "", PSTAMPTOOL_MODE_ADDREQ,       addreqArgs);
     PXOPT_ADD_MODE("-pendingreq",      "", PSTAMPTOOL_MODE_PENDINGREQ,   pendingreqArgs);
-    PXOPT_ADD_MODE("-updatereq",    "", PSTAMPTOOL_MODE_UPDATEREQ, updatereqArgs);
+    PXOPT_ADD_MODE("-updatereq",       "", PSTAMPTOOL_MODE_UPDATEREQ, updatereqArgs);
     PXOPT_ADD_MODE("-listreq",         "", PSTAMPTOOL_MODE_LISTREQ,      listreqArgs);
     PXOPT_ADD_MODE("-completedreq",    "", PSTAMPTOOL_MODE_COMPLETEDREQ, completedreqArgs);
@@ -167,5 +182,6 @@
     PXOPT_ADD_MODE("-listjob",         "", PSTAMPTOOL_MODE_LISTJOB,      listjobArgs);
     PXOPT_ADD_MODE("-pendingjob",      "", PSTAMPTOOL_MODE_PENDINGJOB,   pendingjobArgs);
-    PXOPT_ADD_MODE("-updatejob",    "", PSTAMPTOOL_MODE_UPDATEJOB, updatejobArgs);
+    PXOPT_ADD_MODE("-updatejob",       "", PSTAMPTOOL_MODE_UPDATEJOB,    updatejobArgs);
+    PXOPT_ADD_MODE("-revertjob",       "", PSTAMPTOOL_MODE_REVERTJOB,    revertjobArgs);
 
     PXOPT_ADD_MODE("-adddatastore",    "", PSTAMPTOOL_MODE_ADDDATASTORE, adddatastoreArgs);
Index: branches/eam_branches/20090820/ippTools/src/pubtool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pubtool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pubtool.c	(revision 25766)
@@ -259,7 +259,9 @@
     // required
     PXOPT_LOOKUP_S64(pub_id, config->args, "-pub_id", true, false);
-    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base",  true, false);
+    PXOPT_LOOKUP_STR(path_base, config->args, "-path_base", true, false);
 
     // optional
+    PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
+    PXOPT_LOOKUP_F32(dtime_script, config->args, "-dtime_script", false, false);
     PXOPT_LOOKUP_S32(fault, config->args, "-fault", false, false);
 
@@ -269,5 +271,5 @@
     }
 
-    if (!publishDoneInsert(config->dbh, pub_id, path_base, fault)) {
+    if (!publishDoneInsert(config->dbh, pub_id, path_base, hostname, dtime_script, fault)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to add file");
         if (!psDBRollback(config->dbh)) {
Index: branches/eam_branches/20090820/ippTools/src/pubtoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pubtoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pubtoolConfig.c	(revision 25766)
@@ -68,4 +68,6 @@
     psMetadataAddS64(addArgs, PS_LIST_TAIL, "-pub_id", 0, "define pub_id (required)", 0);
     psMetadataAddStr(addArgs, PS_LIST_TAIL, "-path_base", 0, "define path_base (required)", NULL);
+    psMetadataAddStr(addArgs, PS_LIST_TAIL, "-hostname", 0, "define hostname", NULL);
+    psMetadataAddF32(addArgs, PS_LIST_TAIL, "-dtime_script", 0, "define time for script", NAN);
     psMetadataAddS32(addArgs, PS_LIST_TAIL, "-fault", 0, "define fault code", 0);
 
Index: branches/eam_branches/20090820/ippTools/src/pxadd.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pxadd.c	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/src/pxadd.c	(revision 25766)
@@ -0,0 +1,262 @@
+/*
+ * pxadd.c
+ *
+ * Copyright (C) 2007  Joshua Hoblitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <ippdb.h>
+#include <string.h>
+
+#include "pxtools.h"
+#include "pxadd.h"
+
+bool pxaddSetSearchArgs (psMetadata *md) {
+
+    psMetadataAddS64(md,  PS_LIST_TAIL, "-add_id",            0, "search by add_id", 0);
+    psMetadataAddS64(md,  PS_LIST_TAIL, "-cam_id",             0, "search by cam_id", 0);
+
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-exp_name",           0, "search by exp_name", NULL); */
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-inst",               0, "search for camera", NULL); */
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-telescope",          0, "search for telescope", NULL); */
+/*     psMetadataAddTime(md, PS_LIST_TAIL, "-dateobs_begin",      0, "search for exposures by time (>=)", NULL); */
+/*     psMetadataAddTime(md, PS_LIST_TAIL, "-dateobs_end",        0, "search for exposures by time (<)", NULL); */
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-exp_tag",            0, "search by exp_tag", NULL); */
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-exp_type",           0, "search by exp_type", NULL); */
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-comment",            0, "search by comment", NULL); */
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-filelevel",          0, "search by filelevel", NULL); */
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-filter",             0, "search for filter", NULL); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-airmass_min",        0, "define min airmass", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-airmass_max",        0, "define max airmass", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-ra_min",             0, "define min RA (degrees) ", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-ra_max",             0, "define max RA (degrees) ", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-decl_min",           0, "define min DEC (degrees)", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-decl_max",           0, "define max DEC (degrees)", NAN); */
+/*     psMetadataAddF32(md,  PS_LIST_TAIL, "-exp_time_min",       0, "define min exposure time", NAN); */
+/*     psMetadataAddF32(md,  PS_LIST_TAIL, "-exp_time_max",       0, "define max exposure time", NAN); */
+/*     psMetadataAddF32(md,  PS_LIST_TAIL, "-sat_pixel_frac_min", 0, "define max fraction of saturated pixels", NAN); */
+/*     psMetadataAddF32(md,  PS_LIST_TAIL, "-sat_pixel_frac_max", 0, "define max fraction of saturated pixels", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-bg_min",             0, "define min background", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-bg_max",             0, "define max background", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-bg_stdev_min",       0, "define min background standard deviation", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-bg_stdev_max",       0, "define max background standard deviation", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-bg_mean_stdev_min",  0, "define min background mean standard deviation (across imfiles)", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-bg_mean_stdev_max",  0, "define max background mean standard deviation (across imfiles)", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-alt_min",            0, "define min altitude", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-alt_max",            0, "define max altitude", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-az_min",             0, "define min azimuth ", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-az_max",             0, "define max azimuth ", NAN); */
+/*     psMetadataAddF32(md,  PS_LIST_TAIL, "-ccd_temp_min",       0, "define min ccd tempature", NAN); */
+/*     psMetadataAddF32(md,  PS_LIST_TAIL, "-ccd_temp_max",       0, "define max ccd tempature", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-posang_min",         0, "define min rotator position angle", NAN); */
+/*     psMetadataAddF64(md,  PS_LIST_TAIL, "-posang_max",         0, "define max rotator position angle", NAN); */
+/*     psMetadataAddStr(md,  PS_LIST_TAIL, "-object",             0, "search by exposure object", NULL); */
+/*     psMetadataAddF32(md,  PS_LIST_TAIL, "-sun_angle_min",      0, "define min solar angle", NAN); */
+/*     psMetadataAddF32(md,  PS_LIST_TAIL, "-sun_angle_max",      0, "define max solar angle", NAN); */
+
+    return true;
+}
+
+bool pxaddGetSearchArgs (pxConfig *config, psMetadata *where) {
+
+    PXOPT_COPY_S64(config->args,     where, "-add_id",             "addRun.add_id",        "==");
+/*     PXOPT_COPY_S64(config->args,     where, "-cam_id",             "camRun.cam_id",        "=="); */
+/*     PXOPT_COPY_S64(config->args,   where, "-chip_id",            "chipRun.chip_id", 	 "=="); */
+/*     PXOPT_COPY_S64(config->args,   where, "-exp_id",             "rawExp.exp_id",   	 "=="); */
+/*     PXOPT_COPY_STR(config->args,   where, "-exp_name",           "rawExp.exp_name", 	 "=="); */
+/*     PXOPT_COPY_STR(config->args,   where, "-inst",               "rawExp.camera",   	 "=="); */
+/*     PXOPT_COPY_STR(config->args,   where, "-telescope",          "rawExp.telescope",	 "=="); */
+/*     PXOPT_COPY_TIME(config->args,  where, "-dateobs_begin",      "rawExp.dateobs",  	 ">="); */
+/*     PXOPT_COPY_TIME(config->args,  where, "-dateobs_end",        "rawExp.dateobs",  	 "<="); */
+/*     PXOPT_COPY_STR(config->args,   where, "-exp_tag",            "rawExp.exp_tag",  	 "=="); */
+/*     PXOPT_COPY_STR(config->args,   where, "-exp_type",           "rawExp.exp_type", 	 "=="); */
+/*     PXOPT_COPY_STR(config->args,   where, "-comment",            "rawExp.comment",  	 "LIKE"); */
+/*     PXOPT_COPY_STR(config->args,   where, "-filelevel",          "rawExp.filelevel",	 "=="); */
+/*     PXOPT_COPY_STR(config->args,   where, "-filter",             "rawExp.filter",         "=="); */
+/*     PXOPT_COPY_F64(config->args,   where, "-airmass_min",        "rawExp.airmass",        ">="); */
+/*     PXOPT_COPY_F64(config->args,   where, "-airmass_max",        "rawExp.airmass",        "<"); */
+/*     PXOPT_COPY_RADEC(config->args, where, "-ra_min",             "rawExp.ra",             ">="); */
+/*     PXOPT_COPY_RADEC(config->args, where, "-ra_max",             "rawExp.ra",             "<"); */
+/*     PXOPT_COPY_RADEC(config->args, where, "-decl_min",           "rawExp.decl",           ">="); */
+/*     PXOPT_COPY_RADEC(config->args, where, "-decl_max",           "rawExp.decl",           "<"); */
+/*     PXOPT_COPY_F32(config->args,   where, "-exp_time_min",       "rawExp.exp_time",       ">="); */
+/*     PXOPT_COPY_F32(config->args,   where, "-exp_time_max",       "rawExp.exp_time",       "<"); */
+/*     PXOPT_COPY_F32(config->args,   where, "-sat_pixel_frac_min", "rawExp.sat_pixel_frac", ">="); */
+/*     PXOPT_COPY_F32(config->args,   where, "-sat_pixel_frac_max", "rawExp.sat_pixel_frac", "<"); */
+/*     PXOPT_COPY_F64(config->args,   where, "-bg_min",             "rawExp.bg",             ">="); */
+/*     PXOPT_COPY_F64(config->args,   where, "-bg_max",             "rawExp.bg",             "<"); */
+/*     PXOPT_COPY_F64(config->args,   where, "-bg_stdev_min",       "rawExp.bg_stdev",       ">="); */
+/*     PXOPT_COPY_F64(config->args,   where, "-bg_stdev_max",       "rawExp.bg_stdev",       "<"); */
+/*     PXOPT_COPY_F64(config->args,   where, "-bg_mean_stdev_min",  "rawExp.bg_mean_stdev",  ">="); */
+/*     PXOPT_COPY_F64(config->args,   where, "-bg_mean_stdev_max",  "rawExp.bg_mean_stdev",  "<"); */
+/*     PXOPT_COPY_F64(config->args,   where, "-alt_min",            "rawExp.alt",            ">="); */
+/*     PXOPT_COPY_F64(config->args,   where, "-alt_max",            "rawExp.alt",            "<"); */
+/*     PXOPT_COPY_F64(config->args,   where, "-az_min",             "rawExp.az",             ">="); */
+/*     PXOPT_COPY_F64(config->args,   where, "-az_max",             "rawExp.az",             "<"); */
+/*     PXOPT_COPY_F32(config->args,   where, "-ccd_temp_min",       "rawExp.ccd_temp",       ">="); */
+/*     PXOPT_COPY_F32(config->args,   where, "-ccd_temp_max",       "rawExp.ccd_temp",       "<"); */
+/*     PXOPT_COPY_F64(config->args,   where, "-posang_min",         "rawExp.posang",         ">="); */
+/*     PXOPT_COPY_F64(config->args,   where, "-posang_max",         "rawExp.posang",         "<"); */
+/*     PXOPT_COPY_STR(config->args,   where, "-object",             "rawExp.object",         "=="); */
+/*     PXOPT_COPY_F32(config->args,   where, "-sun_angle_min",      "rawExp.sun_angle",      ">="); */
+/*     PXOPT_COPY_F32(config->args,   where, "-sun_angle_max",      "rawExp.sun_angle",      "<"); */
+
+    return true;
+}
+
+bool pxaddRunSetState(pxConfig *config, psS64 add_id, const char *state, psS64 magicked)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(state, false);
+
+    // check that state is a valid string value
+    if (!pxIsValidState(state)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "invalid camRun state: %s", state);
+        return false;
+    }
+
+    char *query = "UPDATE addRun SET state = '%s', magicked = %" PRId64 " WHERE add_id = %" PRId64;
+    if (!p_psDBRunQueryF(config->dbh, query, state, magicked, add_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for add_id %" PRId64, add_id);
+        return false;
+    }
+
+    return true;
+}
+
+
+bool pxaddRunSetStateByQuery(pxConfig *config, psMetadata *where, const char *state)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(state, false);
+
+    // check that state is a valid string value
+    if (!pxIsValidState(state)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "invalid chipRun state: %s", state);
+        return false;
+    }
+
+    psString query = psStringCopy("UPDATE addRun JOIN camRun USING(cam_id) JOIN chipRun USING(chip_id) JOIN rawExp USING(exp_id) SET addRun.state = '%s'");
+
+    if (where) {
+        psString whereClause = psDBGenerateWhereSQL(where, NULL);
+        psStringAppend(&query, " %s", whereClause);
+        psFree(whereClause);
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, state)) {
+        psFree(query);
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    psFree(query);
+
+    return true;
+}
+
+
+bool pxaddRunSetLabel(pxConfig *config, psS64 add_id, const char *label)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    // note label == NULL should be explicitly allowed
+
+    char *query = "UPDATE addRun SET addRun.label = '%s' WHERE add_id = %" PRId64;
+    if (!p_psDBRunQueryF(config->dbh, query, label, add_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for add_id %" PRId64, add_id);
+        return false;
+    }
+
+    return true;
+}
+
+bool pxaddRunSetLabelByQuery(pxConfig *config, psMetadata *where, const char *label)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    // note label == NULL should be explicitly allowed
+
+    psString query = psStringCopy("UPDATE addRun JOIN camRun USING(cam_id) JOIN chipRun USING(chip_id) JOIN rawExp USING(exp_id) SET addRun.label = '%s'");
+
+    if (where) {
+        psString whereClause = psDBGenerateWhereSQL(where, NULL);
+        psStringAppend(&query, " %s", whereClause);
+        psFree(whereClause);
+    }
+
+    if (!p_psDBRunQueryF(config->dbh, query, label)) {
+        psFree(query);
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    psFree(query);
+
+    return true;
+}
+
+// Need to think more about this to see what we want it to do. BROKEN
+bool pxaddQueueByCamID(pxConfig *config,
+                       psS64 cam_id,
+		       char *workdir,
+		       char *label,
+		       char *recipe,
+		       char *dvodb)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // load the SQL to enqueue our exp_ids from disk once
+    static psString query = NULL;
+    if (!query) {
+        query = pxDataGet("addtool_queue_cam_id.sql");
+        psMemSetPersistent(query, true);
+        if (!query) {
+            psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+            return false;
+        }
+    }
+    //    fprintf(stderr,"%s",query);
+    // queue the exp
+    // XXX chip_id is being cast here work around psS64 have a different type
+    // different on 32/64
+    if (!p_psDBRunQueryF(config->dbh, query,
+			 "new", // state
+			 workdir  ? workdir  : "NULL",
+			 "dirty", //workdir_state
+			 label    ? label    : "NULL",
+			 dvodb    ? dvodb    : "NULL",
+			 (long long)cam_id
+    )) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    // just to be safe, we should have changed at least one row
+    if (psDBAffectedRows(config->dbh) < 1) {
+        psError(PS_ERR_UNKNOWN, false,
+                "no rows affected - should have changed at least one row");
+        return false;
+    }
+
+    return true;
+}
Index: branches/eam_branches/20090820/ippTools/src/pxadd.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pxadd.h	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/src/pxadd.h	(revision 25766)
@@ -0,0 +1,44 @@
+/*
+ * pxadd.h
+ *
+ * Copyright (C) 2009  Joshua Hoblitt, Chris Waters
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef PXADD_H
+#define PXADD_H 1
+
+#include <pslib.h>
+
+#include "pxtools.h"
+
+bool pxaddRunSetState(pxConfig *config, psS64 add_id, const char *state, psS64 magicked);
+bool pxaddRunSetStateByQuery(pxConfig *config, psMetadata *where, const char *state);
+bool pxaddRunSetLabel(pxConfig *config, psS64 add_id, const char *label);
+bool pxaddRunSetLabelByQuery(pxConfig *config, psMetadata *where, const char *label);
+
+bool pxaddSetSearchArgs (psMetadata *md);
+bool pxaddGetSearchArgs (pxConfig *config, psMetadata *where);
+
+// Likely BROKEN
+bool pxaddQueueByCamID(pxConfig *config,
+                        psS64 cam_id,
+                        char *workdir,
+                        char *label,
+                        char *recipe,
+       		        char *dvodb);
+
+
+#endif // PXADD_H
Index: branches/eam_branches/20090820/ippTools/src/pxinject.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pxinject.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pxinject.c	(revision 25766)
@@ -137,7 +137,9 @@
     PXOPT_LOOKUP_STR(tmp_class_id, config->args, "-tmp_class_id", true, false);
     PXOPT_LOOKUP_STR(uri, config->args, "-uri", true, false);
+    PXOPT_LOOKUP_S32(bytes, config->args, "-bytes", false, false);
+    PXOPT_LOOKUP_STR(md5sum, config->args, "-md5sum", false, false);
 
     // insert with error flag state set to 0 (no errors)
-    if (!newImfileInsert(config->dbh, exp_id, tmp_class_id, uri, NULL)) {
+    if (!newImfileInsert(config->dbh, exp_id, tmp_class_id, uri, NULL, bytes, md5sum)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         return false;
Index: branches/eam_branches/20090820/ippTools/src/pxinjectConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pxinjectConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pxinjectConfig.c	(revision 25766)
@@ -61,4 +61,6 @@
     psMetadataAddStr(newImfileArgs, PS_LIST_TAIL, "-tmp_class_id",  0,            "define the class ID (required)", NULL);
     psMetadataAddStr(newImfileArgs, PS_LIST_TAIL, "-uri",  0,            "define the URI (required)", NULL);
+    psMetadataAddS32(newImfileArgs, PS_LIST_TAIL, "-bytes",  0,            "define the size of the file", 0);
+    psMetadataAddStr(newImfileArgs, PS_LIST_TAIL, "-md5sum",  0,            "define the size of the file", NULL);
 
     // -updatenewExp
Index: branches/eam_branches/20090820/ippTools/src/pxmagic.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pxmagic.c	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/src/pxmagic.c	(revision 25766)
@@ -0,0 +1,67 @@
+/*
+ * pxmagic.c
+ *
+ * Copyright (C) 2009 IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <ippdb.h>
+#include <string.h>
+
+#include "pxtools.h"
+#include "pxmagic.h"
+
+bool magicRestoreStage(pxConfig *config, psString stage, psString whereClause, psString newState)
+{
+    psString queryFile = NULL;
+    psStringAppend(&queryFile, "magictool_restore_%s.sql", stage);
+    psString query_temp = pxDataGet(queryFile);
+    if (!query_temp) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement from %s", queryFile);
+        psFree(queryFile);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+    psFree(queryFile);
+
+    // psStringSubstittute fails on strings created by pxDataGet()
+    psString query = psStringCopy(query_temp);
+    // change the @NEW_STATE@ in the sql file to our state
+    if (!psStringSubstitute(&query, newState, "@NEW_STATE@")) {
+        psError(PS_ERR_UNKNOWN, false, "failed to substitute state string");
+        return false;
+    }
+
+    psStringAppend(&query, " AND %s",  whereClause);
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        return false;
+    }
+    psFree(query);
+
+    return true;
+}
Index: branches/eam_branches/20090820/ippTools/src/pxmagic.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pxmagic.h	(revision 25766)
+++ branches/eam_branches/20090820/ippTools/src/pxmagic.h	(revision 25766)
@@ -0,0 +1,29 @@
+/*
+ * pxmagic.h
+ *
+ * Copyright (C) 2009  IfA
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * program; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef PXMAGIC_H
+#define PXMAGIC_H 1
+
+#include <pslib.h>
+
+#include "pxtools.h"
+
+extern bool magicRestoreStage(pxConfig *config, psString stage, psString whereClause, psString newState);
+
+#endif // PXMAGIC_H
Index: branches/eam_branches/20090820/ippTools/src/pxtools.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pxtools.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pxtools.c	(revision 25766)
@@ -37,4 +37,6 @@
     if (!strcmp(state, "goto_cleaned")) return true;
     if (!strcmp(state, "error_cleaned")) return true;
+    if (!strcmp(state, "goto_purged")) return true;
+    if (!strcmp(state, "error_purged")) return true;
     if (!strcmp(state, "goto_scrubbed")) return true;
     if (!strcmp(state, "error_scrubbed")) return true;
@@ -42,12 +44,11 @@
     if (!strcmp(state, "update")) return true;
     if (!strcmp(state, "purged")) return true;
-    if (!strcmp(state, "goto_purged")) return true;
-    if (!strcmp(state, "error_purged")) return true;
-
+    if (!strcmp(state, "scrubbed")) return true;
     return false;
 }
 
-// 'scrubbed' is a virtual state equivalent to cleaned, but allows files to be removed
-// even if the config files is missing
+// 'scrubbed' is no longer a virtual state equivalent to cleaned, but allows files to be removed
+// even if the config files is missing.  This change was prompted as files that are cleaned can
+// be regenerated, but that is not certain after being scrubbed.
 
 
Index: branches/eam_branches/20090820/ippTools/src/pxtools.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pxtools.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pxtools.h	(revision 25766)
@@ -37,4 +37,5 @@
 #include "pxtoolsErrorCodes.h"
 
+#include "pxadd.h"
 #include "pxcam.h"
 #include "pxchip.h"
@@ -45,4 +46,5 @@
 #include "pxtag.h"
 #include "pxtree.h"
+#include "pxmagic.h"
 
 # define MAX_ROWS 10e9
Index: branches/eam_branches/20090820/ippTools/src/pztool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pztool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pztool.c	(revision 25766)
@@ -401,4 +401,6 @@
     PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
     PXOPT_LOOKUP_BOOL(row_lock, config->args, "-row_lock", false);
+    PXOPT_LOOKUP_S32(bytes, config->args, "-bytes", false, false);
+    PXOPT_LOOKUP_STR(md5sum, config->args, "-md5sum", false, false);
 
     // default values
@@ -457,5 +459,7 @@
             fault,
             NULL,    // epoch
-            hostname
+            hostname,
+            bytes,
+            md5sum
     )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -595,5 +599,7 @@
                 "       pzDownloadImfile.class_id," // tmp_class_id
                 "       pzDownloadImfile.uri,"      // uri
-                "       NULL"                       // epoch
+                "       NULL,"                       // epoch
+                "       pzDownloadImfile.bytes,"    // bytes
+                "       pzDownloadImfile.md5sum"    // md5sum
                 "   FROM pzDownloadImfile"
                 "   WHERE"
Index: branches/eam_branches/20090820/ippTools/src/pztoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/pztoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/pztoolConfig.c	(revision 25766)
@@ -95,4 +95,6 @@
     psMetadataAddStr(copydoneArgs, PS_LIST_TAIL, "-label",  0,        "define the label for the chip stage", NULL);
     psMetadataAddStr(copydoneArgs, PS_LIST_TAIL, "-hostname",  0,     "define the host that copied the image", NULL);
+    psMetadataAddS32(copydoneArgs, PS_LIST_TAIL, "-bytes",  0,     "define the size in bytes for the copied image", 0);
+    psMetadataAddStr(copydoneArgs, PS_LIST_TAIL, "-md5sum",  0,     "define the md5 sum for the copied image", NULL);
     psMetadataAddS16(copydoneArgs, PS_LIST_TAIL, "-fault",  0,            "set fault code", 0);
     psMetadataAddBool(copydoneArgs, PS_LIST_TAIL, "-row_lock", 0,     "lock pzDownImfile rows while advancing an exposure", false);
Index: branches/eam_branches/20090820/ippTools/src/regtool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/regtool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/regtool.c	(revision 25766)
@@ -224,4 +224,5 @@
     PXOPT_LOOKUP_F32(teltemp_extra, config->args, "-teltemp_extra", false, false);
     PXOPT_LOOKUP_F32(pon_time, config->args, "-pon_time", false, false);
+    PXOPT_LOOKUP_S16(burntool_state, config->args, "-burntool_state", false, false);
     PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
     PXOPT_LOOKUP_F64(user_2, config->args, "-user_2", false, false);
@@ -238,4 +239,6 @@
     PXOPT_LOOKUP_TIME(dateobs, config->args, "-dateobs", false, false);
     PXOPT_LOOKUP_STR(hostname, config->args, "-hostname", false, false);
+    PXOPT_LOOKUP_S32(bytes, config->args,  "-bytes", false, false);
+    PXOPT_LOOKUP_STR(md5sum, config->args, "-md5sum", false, false);
 
     PXOPT_LOOKUP_S16(fault, config->args, "-fault", false, false);
@@ -307,5 +310,8 @@
         quality,
         NULL,
-        0
+        0,
+        bytes,
+        md5sum,
+        0   // burntool_state
     )) {
         psError(PS_ERR_UNKNOWN, false, "database error");
@@ -327,8 +333,15 @@
     PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "dateobs",  ">=");
     PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "dateobs",  "<=");
+    PXOPT_COPY_STR(config->args, where,  "-filter",        "filter", "==");
+    PXOPT_COPY_S64(config->args, where,  "-magicked",      "magicked", "==");
+
+    PXOPT_LOOKUP_S64(magicked, config->args, "-magicked", false, false);
+    PXOPT_LOOKUP_BOOL(destreaked, config->args,     "-destreaked", false);
+    PXOPT_LOOKUP_BOOL(not_destreaked, config->args, "-not_destreaked", false);
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
     PXOPT_LOOKUP_BOOL(faulted, config->args, "-faulted", false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
+    PXOPT_LOOKUP_BOOL(ordered_by_date, config->args, "-ordered_by_date", false);
 
     psString query = pxDataGet("regtool_processedimfile.sql");
@@ -352,4 +365,25 @@
         // don't list faulted rows
         psStringAppend(&query, " %s", "AND rawImfile.fault = 0");
+    }
+
+    if (not_destreaked) {
+        if (destreaked) {
+            psError(PXTOOLS_ERR_DATA, true, "providing -not_destreaked and -destreaked makes no sense");
+            return false;
+        }
+        if (magicked) {
+            psError(PXTOOLS_ERR_DATA, true, "providing -not_destreaked and -magicked makes no sense");
+            return false;
+        }
+        psStringAppend(&query, " AND rawImfile.magicked = 0");
+    }
+    if (destreaked) {
+        psStringAppend(&query, " AND rawImfile.magicked != 0");
+    }
+
+
+    // add the ORDER BY statement if desired
+    if (ordered_by_date) {
+        psStringAppend(&query, " ORDER BY dateobs");
     }
 
@@ -456,12 +490,13 @@
 
     PXOPT_LOOKUP_S16(fault, config->args, "-fault",   false, false);
-    PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false);
-
-    if ((fault == INT16_MAX) && !isfinite(user_1)) { 
-        psError(PS_ERR_UNKNOWN, false, "one of -fault or -user_1 must be selected");
-        return false;
-    }
-    if ((fault != INT16_MAX) && isfinite(user_1)) { 
-        psError(PS_ERR_UNKNOWN, false, "only one of -fault or -user_1 must be selected");
+/*     PXOPT_LOOKUP_F64(user_1, config->args, "-user_1", false, false); */
+    PXOPT_LOOKUP_S16(burntool_state, config->args, "-burntool_state", false, false);
+    
+    if ((fault == INT16_MAX) && !isfinite(burntool_state)) { 
+        psError(PS_ERR_UNKNOWN, false, "one of -fault or -burntool_state must be selected");
+        return false;
+    }
+    if ((fault != INT16_MAX) && isfinite(burntool_state)) { 
+        psError(PS_ERR_UNKNOWN, false, "only one of -fault or -burntool_state must be selected");
         return false;
     }
@@ -480,5 +515,5 @@
     }
 
-    if (isfinite(user_1)) {
+    if (isfinite(burntool_state)) {
 	psString query = pxDataGet("regtool_updateprocessedimfile.sql");
 	if (!query) {
@@ -487,5 +522,5 @@
 	}
 
-	if (!p_psDBRunQueryF(config->dbh, query, user_1, exp_id, class_id)) {
+	if (!p_psDBRunQueryF(config->dbh, query, burntool_state, exp_id, class_id)) {
 	    psError(PS_ERR_UNKNOWN, false, "database error");
 	    psFree(query);
Index: branches/eam_branches/20090820/ippTools/src/regtoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/regtoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/regtoolConfig.c	(revision 25766)
@@ -125,4 +125,7 @@
     ADD_OPT(Time, addprocessedimfileArgs, "-dateobs",        "define observation time",         NULL);
     ADD_OPT(Str,  addprocessedimfileArgs, "-hostname",       "define host name",                NULL);
+    ADD_OPT(Str,  addprocessedimfileArgs, "-md5sum",         "define md5sum",                NULL);
+    ADD_OPT(S32,  addprocessedimfileArgs, "-bytes",          "define bytes",                0);
+    ADD_OPT(S16,  addprocessedimfileArgs, "-burntool_state",        "set burntool state", 0);
     ADD_OPT(S16,  addprocessedimfileArgs, "-fault",           "set fault code",                  0);
     ADD_OPT(S16,  addprocessedimfileArgs, "-quality",        "set quality flag", 0);
@@ -133,6 +136,10 @@
     ADD_OPT(Str,  processedimfileArgs, "-exp_name",  "search by exposure name",               NULL);
     ADD_OPT(Str,  processedimfileArgs, "-class_id",  "search by class ID",                    NULL);
+    ADD_OPT(Str,  processedimfileArgs, "-filter",  "search by filter",                        NULL);
     ADD_OPT(Time, processedimfileArgs, "-dateobs_begin", "search for exposures by time (>=)", NULL);
     ADD_OPT(Time, processedimfileArgs, "-dateobs_end", "search for exposures by time (<)", NULL);
+    ADD_OPT(S64,  processedimfileArgs, "-magicked",    "search by magicked value",            0);
+    ADD_OPT(Bool, processedimfileArgs, "-destreaked",   "only return imfiles that have been destreaked", false);
+    ADD_OPT(Bool, processedimfileArgs, "-not_destreaked", "only return imfiles that have not been destreaked", false);
     ADD_OPT(U64,  processedimfileArgs, "-limit",     "limit result set to N items",           0);
     ADD_OPT(Bool, processedimfileArgs, "-faulted",   "only return imfiles with a fault status set", false);
@@ -153,5 +160,5 @@
     ADD_OPT(S64, updateprocessedimfileArgs, "-exp_id",        "search by exposure ID", 0);
     ADD_OPT(Str, updateprocessedimfileArgs, "-class_id",      "search by class ID", NULL);
-    ADD_OPT(F64, updateprocessedimfileArgs, "-user_1",        "set user stat (1)", NAN);
+    ADD_OPT(S16, updateprocessedimfileArgs, "-burntool_state",        "set burntool state", 0);
     ADD_OPT(S16, updateprocessedimfileArgs, "-fault",          "set fault code", INT16_MAX);
 
Index: branches/eam_branches/20090820/ippTools/src/stacktool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/stacktool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/stacktool.c	(revision 25766)
@@ -139,4 +139,10 @@
     PXOPT_COPY_F32(config->args,  where, "-select_fwhm_minor_min",     "camProcessedExp.fwhm_minor", ">=");
     PXOPT_COPY_F32(config->args,  where, "-select_fwhm_minor_max",     "camProcessedExp.fwhm_minor", "<=");
+    PXOPT_COPY_F32(config->args,  where, "-select_iq_m2_max",     "camProcessedExp.iq_m2", "<=");
+    PXOPT_COPY_F32(config->args,  where, "-select_iq_m2_min",     "camProcessedExp.iq_m2", ">=");
+    PXOPT_COPY_F32(config->args,  where, "-select_iq_m3_max",     "camProcessedExp.iq_m3", "<=");
+    PXOPT_COPY_F32(config->args,  where, "-select_iq_m4_min",     "camProcessedExp.iq_m4", ">=");
+    PXOPT_COPY_F32(config->args,  where, "-select_iq_m4_max",     "camProcessedExp.iq_m4", "<=");
+    
     PXOPT_COPY_STR(config->args,  where, "-select_exp_type",           "rawExp.exp_type", "==");
     PXOPT_COPY_F32(config->args,  where, "-select_good_frac_min",      "warpSkyfile.good_frac", ">=");
@@ -853,10 +859,17 @@
 
     psMetadata *where = psMetadataAlloc();
-    PXOPT_COPY_S64(config->args, where, "-warp_id", "warpRun.warp_id", "==");
     PXOPT_COPY_S64(config->args, where, "-stack_id", "stackSumSkyfile.stack_id", "==");
-    PXOPT_COPY_S64(config->args, where, "-exp_id", "rawExp.exp_id", "==");
-    PXOPT_COPY_STR(config->args, where, "-exp_name", "rawExp.exp_name", "==");
     PXOPT_COPY_STR(config->args, where, "-tess_id", "stackRun.tess_id", "==");
     PXOPT_COPY_STR(config->args, where, "-skycell_id", "stackRun.skycell_id", "==");
+    PXOPT_COPY_STR(config->args, where, "-filter", "stackRun.filter", "LIKE");
+    PXOPT_COPY_STR(config->args, where, "-label", "stackRun.label", "==");
+    PXOPT_COPY_S16(config->args, where, "-fault", "stackSumSkyfile.fault", "==");
+
+//  The following three selectors are incompatible with the sql so omit them
+//    PXOPT_COPY_S64(config->args, where, "-warp_id", "warpRun.warp_id", "==");
+//     PXOPT_COPY_S64(config->args, where, "-exp_id", "rawExp.exp_id", "==");
+//    PXOPT_COPY_STR(config->args, where, "-exp_name", "rawExp.exp_name", "==");
+
+    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
@@ -873,5 +886,9 @@
         psStringAppend(&query, " WHERE %s", whereClause);
         psFree(whereClause);
-    }
+    } else if (!all) {
+        psError(PXTOOLS_ERR_DATA, true, "search parameters or -all are required");
+        return false;
+    }
+
     psFree(where);
 
Index: branches/eam_branches/20090820/ippTools/src/stacktoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/stacktoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/stacktoolConfig.c	(revision 25766)
@@ -77,4 +77,10 @@
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_fwhm_minor_min", 0, "define min fwhm (minor axis)", NAN);
     psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_fwhm_minor_max", 0, "define max fwhm (minor axis)", NAN);
+    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_iq_m2_min", 0, "define min iq_m2", NAN);
+    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_iq_m2_max", 0, "define max iq_m2", NAN);
+    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_iq_m3_min", 0, "define min iq_m3", NAN);
+    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_iq_m3_max", 0, "define max iq_m3", NAN);
+    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_iq_m4_min", 0, "define min iq_m4", NAN);
+    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_iq_m4_max", 0, "define max iq_m4", NAN);
     psMetadataAddS32(definebyqueryArgs, PS_LIST_TAIL, "-random", 0, "use this number of random elements", 0);
     psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-all", 0, "allow everything to be queued without search terms", false);
@@ -158,11 +164,18 @@
     psMetadata *sumskyfileArgs= psMetadataAlloc();
     psMetadataAddS64(sumskyfileArgs, PS_LIST_TAIL, "-stack_id", 0,            "search by stack ID", 0);
-    psMetadataAddS64(sumskyfileArgs, PS_LIST_TAIL, "-warp_id", 0,            "search by warp ID", 0);
     psMetadataAddStr(sumskyfileArgs, PS_LIST_TAIL, "-tess_id", 0,            "search by tess ID", 0);
     psMetadataAddStr(sumskyfileArgs, PS_LIST_TAIL, "-skycell_id", 0,         "search by skycell ID", 0);
+#ifdef notdef
+    // These don't work so omit (for now) We probably should create a different mode for this type of search.
+    psMetadataAddS64(sumskyfileArgs, PS_LIST_TAIL, "-warp_id", 0,            "search by warp ID", 0);
     psMetadataAddS64(sumskyfileArgs, PS_LIST_TAIL, "-exp_id", 0,            "search by exposure ID", 0);
     psMetadataAddStr(sumskyfileArgs, PS_LIST_TAIL, "-exp_name", 0,          "search by exposure name", NULL);
+#endif
+    psMetadataAddStr(sumskyfileArgs, PS_LIST_TAIL, "-label", 0,             "search by stackRun.label", NULL);
+    psMetadataAddStr(sumskyfileArgs, PS_LIST_TAIL, "-filter", 0,            "search by filter (LIKE comparison)", NULL);
+    psMetadataAddS16(sumskyfileArgs, PS_LIST_TAIL, "-fault",  0,            "search by fault code", 0);
     psMetadataAddU64(sumskyfileArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
     psMetadataAddBool(sumskyfileArgs, PS_LIST_TAIL, "-simple",  0,            "use the simple output format", false);
+    psMetadataAddBool(sumskyfileArgs, PS_LIST_TAIL, "-all",  0,            "enable search without arguments", false);
 
     // -revertsumskyfile
Index: branches/eam_branches/20090820/ippTools/src/warptool.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/warptool.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/warptool.c	(revision 25766)
@@ -53,4 +53,5 @@
 static bool tocleanedskyfileMode(pxConfig *config);
 static bool topurgedskyfileMode(pxConfig *config);
+static bool toscrubbedskyfileMode(pxConfig *config);
 static bool tofullskyfileMode(pxConfig *config);
 static bool updateskyfileMode(pxConfig *config);
@@ -102,4 +103,5 @@
         MODECASE(WARPTOOL_MODE_TOCLEANEDSKYFILE,   tocleanedskyfileMode);
         MODECASE(WARPTOOL_MODE_TOPURGEDSKYFILE,    topurgedskyfileMode);
+	MODECASE(WARPTOOL_MODE_TOSCRUBBEDSKYFILE,  toscrubbedskyfileMode);
         MODECASE(WARPTOOL_MODE_TOFULLSKYFILE,      tofullskyfileMode);
         MODECASE(WARPTOOL_MODE_UPDATESKYFILE,      updateskyfileMode);
@@ -1196,4 +1198,15 @@
     PXOPT_COPY_STR(config->args, where, "-exp_name",   "rawExp.exp_name", "==");
     PXOPT_COPY_S64(config->args, where, "-fake_id",    "fakeRun.fake_id", "==");
+    PXOPT_COPY_TIME(config->args, where, "-dateobs_begin", "rawExp.dateobs",  ">=");
+    PXOPT_COPY_TIME(config->args, where, "-dateobs_end",   "rawExp.dateobs",  "<=");
+    PXOPT_COPY_STR(config->args, where, "-filter",    "rawExp.filter", "==");
+    PXOPT_COPY_S64(config->args, where, "-magicked", "warpSkyfile.magicked", "==");
+    pxAddLabelSearchArgs (config, where, "-label",   "warpRun.label", "LIKE");
+
+    PXOPT_LOOKUP_U64(magicked, config->args, "-magicked", false, false);
+    PXOPT_LOOKUP_BOOL(destreaked, config->args,     "-destreaked", false);
+    PXOPT_LOOKUP_BOOL(not_destreaked, config->args, "-not_destreaked", false);
+
+    PXOPT_LOOKUP_BOOL(all, config->args, "-all", false);
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
@@ -1211,6 +1224,24 @@
         psStringAppend(&query, " AND %s", whereClause);
         psFree(whereClause);
+    } else if (!all) {
+        psError(PXTOOLS_ERR_DATA, true, "search parameters or -all are required");
+        return false;
     }
     psFree(where);
+
+    if (not_destreaked) {
+        if (destreaked) {
+            psError(PXTOOLS_ERR_DATA, true, "providing -not_destreaked and -destreaked makes no sense");
+            return false;
+        }
+        if (magicked) {
+            psError(PXTOOLS_ERR_DATA, true, "providing -not_destreaked and -magicked makes no sense");
+            return false;
+        }
+        psStringAppend(&query, " AND warpSkyfile.magicked = 0");
+    }
+    if (destreaked) {
+        psStringAppend(&query, " AND warpSkyfile.magicked != 0");
+    }
 
     // treat limit == 0 as "no limit"
@@ -1668,4 +1699,8 @@
     return change_skyfile_data_state(config, "purged", "goto_purged");
 }
+static bool toscrubbedskyfileMode(pxConfig *config)
+{
+     return change_skyfile_data_state(config, "scrubbed", "goto_scrubbed");
+}
 
 static bool updateskyfileMode(pxConfig *config)
Index: branches/eam_branches/20090820/ippTools/src/warptool.h
===================================================================
--- branches/eam_branches/20090820/ippTools/src/warptool.h	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/warptool.h	(revision 25766)
@@ -49,4 +49,5 @@
     WARPTOOL_MODE_TOCLEANEDSKYFILE,
     WARPTOOL_MODE_TOPURGEDSKYFILE,
+    WARPTOOL_MODE_TOSCRUBBEDSKYFILE,
     WARPTOOL_MODE_TOFULLSKYFILE,
     WARPTOOL_MODE_UPDATESKYFILE,
Index: branches/eam_branches/20090820/ippTools/src/warptoolConfig.c
===================================================================
--- branches/eam_branches/20090820/ippTools/src/warptoolConfig.c	(revision 25206)
+++ branches/eam_branches/20090820/ippTools/src/warptoolConfig.c	(revision 25766)
@@ -215,4 +215,14 @@
     psMetadataAddStr(warpedArgs, PS_LIST_TAIL, "-exp_name", 0,          "search by exposure tag", 0);
     psMetadataAddS64(warpedArgs, PS_LIST_TAIL, "-fake_id", 0,           "search by phase 3 version of exposure tag", 0);
+    psMetadataAddTime(warpedArgs, PS_LIST_TAIL, "-dateobs_begin", 0,    "search for exposures by time (>=)", NULL);
+    psMetadataAddTime(warpedArgs, PS_LIST_TAIL, "-dateobs_end", 0,      "search for exposures by time (<=)", NULL);
+    psMetadataAddStr(warpedArgs, PS_LIST_TAIL,  "-filter", 0,           "search for exposures by filter", NULL);
+    psMetadataAddBool(warpedArgs, PS_LIST_TAIL, "-destreaked",  0,      "search for destreaked images", false);
+    psMetadataAddBool(warpedArgs, PS_LIST_TAIL, "-not_destreaked",  0,  "search for images that have not been destreaked", false);
+    psMetadataAddS64(warpedArgs, PS_LIST_TAIL,  "-magicked", 0,         "search by magicked value", 0);
+    psMetadataAddS16(warpedArgs, PS_LIST_TAIL,  "-fault",  0,           "search by fault code", 0);
+    psMetadataAddStr(warpedArgs, PS_LIST_TAIL,  "-label",  PS_META_DUPLICATE_OK, "search by warpRun label", NULL);
+
+    psMetadataAddBool(warpedArgs, PS_LIST_TAIL, "-all",  0,             "search without arguments", false);
     psMetadataAddU64(warpedArgs, PS_LIST_TAIL, "-limit",  0,            "limit result set to N items", 0);
     psMetadataAddBool(warpedArgs, PS_LIST_TAIL, "-simple",  0,          "use the simple output format", false);
@@ -278,4 +288,9 @@
     psMetadataAddS64(topurgedskyfileArgs, PS_LIST_TAIL, "-warp_id", 0,    "warptool ID to update", 0);
     psMetadataAddStr(topurgedskyfileArgs, PS_LIST_TAIL, "-skycell_id", 0, "skycell ID to update", NULL);
+
+    // -toscrubbedskyfile
+    psMetadata *toscrubbedskyfileArgs = psMetadataAlloc();
+    psMetadataAddS64(toscrubbedskyfileArgs, PS_LIST_TAIL, "-warp_id", 0, "warptool ID to update", 0);
+    psMetadataAddStr(toscrubbedskyfileArgs, PS_LIST_TAIL, "-skycell_id", 0, "skycell ID to update", NULL);
 
     // -tofullskyfile
@@ -328,4 +343,5 @@
     PXOPT_ADD_MODE("-tocleanedskyfile", "set skyfile as cleaned", WARPTOOL_MODE_TOCLEANEDSKYFILE, tocleanedskyfileArgs);
     PXOPT_ADD_MODE("-topurgedskyfile", "set skyfile as purged", WARPTOOL_MODE_TOPURGEDSKYFILE, topurgedskyfileArgs);
+    PXOPT_ADD_MODE("-toscrubbedskyfile", "set skyfile as scrubbed", WARPTOOL_MODE_TOSCRUBBEDSKYFILE, toscrubbedskyfileArgs);
     PXOPT_ADD_MODE("-tofullskyfile", "set skyfile as full (updated)", WARPTOOL_MODE_TOFULLSKYFILE, tofullskyfileArgs);
     PXOPT_ADD_MODE("-updateskyfile", "update fault code for skyfile", WARPTOOL_MODE_UPDATESKYFILE, updateskyfileArgs);
Index: branches/eam_branches/20090820/ippconfig/cfh12k/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/cfh12k/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/cfh12k/psphot.config	(revision 25766)
@@ -1,36 +1,10 @@
 
 # turn these on to see specific outputs
-SAVE.OUTPUT	BOOL 	TRUE
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
 SAVE.PLOTS	BOOL 	TRUE
-
-BACKGROUND.XBIN	    S32   128           # size of background superpixels
-BACKGROUND.YBIN	    S32   128           # size of background superpixels
-
-# image background parameters
-IMSTATS_NPIX        S32  10000    	 # number of pixels to use for sky estimate boxes:
-
-PSF_SN_LIM          F32  50              # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
-
-PEAKS_NSIGMA_LIMIT     F32   25.0            # peak significance threshold
-PEAKS_NSIGMA_LIMIT_2   F32   10.0            # peak significance threshold
 
 # PSF model parameters : choose the PSF model desired
 PSF_MODEL           STR  PS_MODEL_QGAUSS
 
-MOMENTS_SN_MIN       F32  20.0           # min S/N to measure moments
-EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  50.0
-AP_MIN_SN            F32  25.0
-MEASURE.APTREND	                    BOOL  FALSE
-
-# BREAK_POINT may be one of (PEAKS, MOMENTS, PSFMODEL, ENSEMBLE)
-# BREAK_POINT         STR ENSEMBLE
-
-OUTPUT.FORMAT       STR PS1_DEV_1
-
-# masking parameters (XXX EAM : rework this to use psRegion like ANALYSIS_REGION)
+# XXX are these needed?
 XMIN                F32   +10        	 # minimum valid x-coord
 XMAX                F32   -10        	 # maximum valid x-coord
@@ -38,3 +12,2 @@
 YMAX                F32   -10        	 # maximum valid y-coord
 
-USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
Index: branches/eam_branches/20090820/ippconfig/esowfi/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/esowfi/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/esowfi/psphot.config	(revision 25766)
@@ -1,30 +1,3 @@
 
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.BACKMDL.STDEV BOOL 	TRUE
-SAVE.BACKGND	BOOL 	TRUE
-SAVE.BACKSUB	BOOL 	TRUE
-SAVE.PLOTS      BOOL    FALSE
-SAVE.RESID	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
-LOAD.PSF	BOOL 	FALSE
-
-IMSTATS_NPIX        S32  3000    	 # number of pixels to use for sky estimate boxes:
-
-#PSPHOT_TEST METADATA
-# SAVE.BACKSUB	BOOL 	FALSE
-# SAVE.RESID	BOOL 	TRUE
-#END
-#
-#PEAKS_OUTPUT_FILE   STR  peaks.dat
-#MOMENTS_OUTPUT_FILE STR  moments.dat
-
-#PSF_SN_LIM          F32  20.0            # minimum S/N for stars used for PSF model
-MOMENTS_SN_MIN      F32  20.0            # min S/N to measure moments
-FULL_FIT_SN_LIM     F32  100.0
-EXT_MIN_SN          F32  100.0           # fit galaxies above this S/N limit
-
-PEAKS_NSIGMA_LIMIT  F32  10.0 	   	 # peak significance threshold
-BREAK_POINT         STR  ENSEMBLE        # limit total processing for now (for speed)
-
-
-SKY_STAT            STR  ROBUST_MEDIAN   # statistic used to measure background
+# choose the PSF model
+PSF_MODEL                           STR   PS_MODEL_QGAUSS
Index: branches/eam_branches/20090820/ippconfig/gpc1/Makefile.am
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/Makefile.am	(revision 25766)
@@ -20,5 +20,4 @@
 	psastro.config \
         pswarp.config \
-	ppStack.config \
 	rejections.config
 
Index: branches/eam_branches/20090820/ippconfig/gpc1/camera.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/camera.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/camera.config	(revision 25766)
@@ -132,4 +132,5 @@
   CMF.XSRC STR {CHIP.NAME}.xsrc # use .PSF and .EXT?
   CMF.XFIT STR {CHIP.NAME}.xfit # use .PSF and .EXT?
+  CMF.DETEFF STR {CHIP.NAME}.deteff
 
   PSF.HEAD  STR	{CHIP.NAME}.hdr
@@ -146,2 +147,4 @@
 
 PHOTCODE.RULE           STR     {DETECTOR}.{FILTER.ID}.{CHIP.NAME}	# Rule for generating photcode
+
+BURNTOOL.STATE.GOOD     S16     13  # Value for burntool_state with the most recent bt version.
Index: branches/eam_branches/20090820/ippconfig/gpc1/format_20080925.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/format_20080925.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/format_20080925.config	(revision 25766)
@@ -222,4 +222,6 @@
         FPA.TELTEMP.TRUSS  STR  TELTEMTR # Mid truss temperatures (C
         FPA.TELTEMP.EXTRA  STR  TELTEMEX # Miscellaneous temperatures (C)     
+
+        FPA.BURNTOOL.APPLIED STR BTOOLAPP
 
         FPA.PON.TIME    STR     PONTIME
Index: branches/eam_branches/20090820/ippconfig/gpc1/format_20080929.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/format_20080929.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/format_20080929.config	(revision 25766)
@@ -217,4 +217,6 @@
         FPA.TELTEMP.TRUSS  STR  TELTEMTR # Mid truss temperatures (C
         FPA.TELTEMP.EXTRA  STR  TELTEMEX # Miscellaneous temperatures (C)     
+
+        FPA.BURNTOOL.APPLIED STR BTOOLAPP
 
         FPA.PON.TIME    STR     PONTIME
Index: branches/eam_branches/20090820/ippconfig/gpc1/format_20081011.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/format_20081011.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/format_20081011.config	(revision 25766)
@@ -208,4 +208,6 @@
         FPA.TELTEMP.TRUSS  STR  TELTEMTR # Mid truss temperatures (C
         FPA.TELTEMP.EXTRA  STR  TELTEMEX # Miscellaneous temperatures (C)     
+
+        FPA.BURNTOOL.APPLIED STR BTOOLAPP
 
         FPA.PON.TIME    STR     PONTIME
Index: branches/eam_branches/20090820/ippconfig/gpc1/format_20090120.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/format_20090120.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/format_20090120.config	(revision 25766)
@@ -207,4 +207,6 @@
         FPA.TELTEMP.TRUSS  STR  TELTEMTR # Mid truss temperatures (C
         FPA.TELTEMP.EXTRA  STR  TELTEMEX # Miscellaneous temperatures (C)     
+
+        FPA.BURNTOOL.APPLIED STR BTOOLAPP
 
         FPA.PON.TIME    STR     PONTIME
Index: branches/eam_branches/20090820/ippconfig/gpc1/format_20090220.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/format_20090220.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/format_20090220.config	(revision 25766)
@@ -185,5 +185,5 @@
         FPA.ALT         STR     ALT
         FPA.AZ          STR     AZ
-        FPA.TEMP        STR     DETTEM
+        # FPA.TEMP        STR     DETTEM
         FPA.M1X         STR     M1X
         FPA.M1Y         STR     M1Y   
@@ -207,4 +207,6 @@
         FPA.TELTEMP.TRUSS  STR  TELTEMTR # Mid truss temperatures (C
         FPA.TELTEMP.EXTRA  STR  TELTEMEX # Miscellaneous temperatures (C)     
+
+        FPA.BURNTOOL.APPLIED STR BTOOLAPP
 
         FPA.PON.TIME    STR     PONTIME
@@ -501,4 +503,6 @@
 # How to translation PS concepts into database lookups
 DATABASE        METADATA
+	# this rule is fragile : does not match the camera
+        FPA.TEMP        STR     SELECT ccd_temp FROM rawExp WHERE dateobs >= '{FPA.DATE}' and abs(timediff(dateobs, cast('{FPA.TIME}' as datetime))) < 2
 END
 
Index: branches/eam_branches/20090820/ippconfig/gpc1/format_orig.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/format_orig.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/format_orig.config	(revision 25766)
@@ -215,4 +215,6 @@
         FPA.TELTEMP.TRUSS  STR  TELTEMTR # Mid truss temperatures (C
         FPA.TELTEMP.EXTRA  STR  TELTEMEX # Miscellaneous temperatures (C)     
+
+        FPA.BURNTOOL.APPLIED STR BTOOLAPP
 
         FPA.PON.TIME    STR     PONTIME
Index: branches/eam_branches/20090820/ippconfig/gpc1/ppStack.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/ppStack.config	(revision 25206)
+++ 	(revision )
@@ -1,38 +1,0 @@
-# Recipe configuration for ppStack (image combination)
-
-ITER		S32	1		# Number of rejection iterations
-COMBINE.REJ	F32	4.0		# Rejection threshold in combination (sigma)
-MASK.VAL	STR	MASK.VALUE,CONV.BAD	# Mask value of input bad pixels
-MASK.BAD	STR	BLANK		# Mask value to give bad pixels
-MASK.POOR	STR	CONV.POOR	# Mask value to give poor pixels
-POOR.FRACTION	F32	0.1		# Maximum fraction of bad weight for poor pixels
-THRESHOLD.MASK	F32	0.8		# Threshold for mask deconvolution (0..1)
-IMAGE.REJ	F32	0.2		# Rejected pixel fraction threshold for rejecting entire image
-ROWS		S32	64		# Number of rows to read at once
-VARIANCE	BOOL	TRUE		# Use variance in rejection?
-SAFE		BOOL	FALSE		# Play safe when combining small number of values?
-
-RENORM		BOOL	FALSE		# Renormalise variance maps?
-RENORM.MEAN	STR	ROBUST_MEDIAN	# Statistic to use for mean in renormalisation
-RENORM.STDEV	STR	ROBUST_STDEV	# Statistic to use for stdev in renormalisation
-RENORM.WIDTH	S32	300		# Size of renormalisation boxes (pixels)
-
-SOURCE.RADIUS	F32	1.0		# Radius (pixels) for matching sources
-SOURCE.MIN	S32	15		# Minimum number of sources for merging source lists
-SOURCE.ITER	S32	2		# Number of rejection iterations for magnitude difference
-SOURCE.REJ	F32	2.0		# Rejection limit (sigma) for magnitude difference
-
-PSF.INSTANCES	S32	9		# Number of instances for PSF generation
-PSF.RADIUS	F32	20.0		# Radius for PSF generation
-PSF.ORDER	S32	2		# Order of spatial variation for PSF generation
-PSF.MODEL	STR	PS_MODEL_GAUSS	# Model for PSF generation
-
-TEMP.IMAGE	STR	conv.im.fits	# Suffix for convolved images
-TEMP.MASK	STR	conv.mk.fits	# Suffix for convolved masks
-TEMP.VARIANCE	STR	conv.var.fits	# Suffix for convolved variance maps
-TEMP.DELETE	BOOL	FALSE		# Delete temporary files on completion?
-
-PR	METADATA
-	CONVOLVE	BOOL	FALSE
-	IMAGE.REJ	F32	0.5
-END
Index: branches/eam_branches/20090820/ippconfig/gpc1/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/gpc1/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/gpc1/psphot.config	(revision 25766)
@@ -1,56 +1,31 @@
 
-# turn these on to see specific outputs
-SAVE.OUTPUT	BOOL 	TRUE
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
-SAVE.PLOTS     	BOOL    TRUE
+BACKGROUND.XBIN	                    S32   256           # size of background superpixels
+BACKGROUND.YBIN	                    S32   256           # size of background superpixels
 
-# for testing:
-# BREAK_POINT STR BACKMDL
+SOFTEN.VARIANCE                     BOOL  TRUE          # XXX drop? soften the errors for bright pixels
+SOFTEN.VARIANCE.FRACTION            F32   0.005
 
-BACKGROUND.XBIN	    S32  256            # size of background superpixels
-BACKGROUND.YBIN	    S32  256            # size of background superpixels
+PEAKS_SMOOTH_SIGMA                  F32   2.5           # smoothing kernel sigma in pixels
 
-# image background parameters
-IMSTATS_NPIX        S32  10000    	 # number of pixels to use for sky estimate boxes:
-SKY_STAT            STR  FITTED_MEAN_V4  # statistic used to measure background
-SKY_CLIP_SIGMA      F32  2.0             # statistic used to measure background
+PSF_CLUMP_NX                        S32   3             # subdivide image in to NX x NY regions for 
+PSF_CLUMP_NY                        S32   3             # selecting PSF stars
+PSF_CLUMP_GRID_SCALE                F32   2.5		# XXX too large? size of Sx,Sy image pixel
 
-PEAKS_SMOOTH_SIGMA  F32   2.5            # smoothing kernel sigma in pixels
-PEAKS_NMAX          S32   5000           # on first pass, only keep NMAX peaks (0 == all)
-PEAKS_NSIGMA_LIMIT  F32   25.0           # peak significance threshold
-PEAKS_NSIGMA_LIMIT_2 F32   5.0           # peak significance threshold
-
-PSF_SN_LIM          F32  25              # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
-PSF_CLUMP_NX        S32   3               # subdivide image in to NX x NY regions for 
-PSF_CLUMP_NY        S32   3               # selecting PSF stars
-PSF_MOMENTS_RADIUS  F32  12               # calculate initial source moments with this radius
-PSF_CLUMP_GRID_SCALE F32 2.5		# size of Sx,Sy image pixel
-
-PSF.RESIDUALS       BOOL  TRUE            # generate the residuals?
+PSF.RESIDUALS.RADIUS   		    F32   9.0           # keep this pixel if residual is more significant than this
+PSF.RESIDUALS.SPATIAL_ORDER 	    S32   1             # fit spatial variations of the residuals at this order (0,1)
 
 # PSF model parameters : choose the PSF model desired
-PSF_MODEL           STR  PS_MODEL_PS1_V1
-PSPHOT.CR.NSIGMA.SOFTEN             F32   0.0025            # Softening parameter for weights
+PSF_MODEL              	 	    STR   PS_MODEL_PS1_V1
+PSPHOT.CR.NSIGMA.SOFTEN             F32   0.0025        # Softening parameter for weights in CR stat
 
-PSF.TREND.MODE                      STR   MAP # other options: POLY_CHEB, POLY_ORD
 PSF.TREND.NX                        S32   3
 PSF.TREND.NY                        S32   3
 
-EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  25.0
-MOMENTS_SN_MIN      F32    5.0
-AP_MIN_SN            F32   5.0
+# rename NONLINEAR_FIT_SN_LIM?
+FULL_FIT_SN_LIM      		    F32   25.0
 
-OUTPUT.FORMAT        STR  PS1_V2
+APTREND.ORDER.MAX    		    S32   3
 
-PSF_SHAPE_NSIGMA     F32  3.0		 # max significance for shape variation
-PSF_MAX_CHI          F32  50.0		 # reject objects worse that this
-
-MEASURE.APTREND      BOOL TRUE           ### XXX for now, skip this (too many errors)
-APTREND.ORDER.MAX    S32  3
-
-DIAGNOSTIC.PLOTS                    METADATA
+DIAGNOSTIC.PLOTS METADATA
   IMAGE.BACKGROUND.CELL.HISTOGRAM   BOOL  FALSE
   IMAGE.BACKGROUND.CELL.HISTOGRAM.X S32   32
@@ -58,8 +33,6 @@
 END
 
-USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
-
-DIFF	METADATA
-	BACKGROUND.XBIN	    S32  32            # size of background superpixels
-	BACKGROUND.YBIN	    S32  32            # size of background superpixels
+DIFF METADATA
+  BACKGROUND.XBIN		    S32  32            # size of background superpixels
+  BACKGROUND.YBIN	    	    S32  32            # size of background superpixels
 END
Index: branches/eam_branches/20090820/ippconfig/isp/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/isp/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/isp/psphot.config	(revision 25766)
@@ -1,76 +1,13 @@
 
 # turn these on to see specific outputs
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.BACKGND	BOOL 	TRUE
-SAVE.BACKSUB	BOOL 	TRUE
-SAVE.RESID	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
 SAVE.PLOTS      BOOL    TRUE
 
-# image statistics parameters
-IMSTATS_NPIX        S32  5000    	 # number of pixels to use for sky estimate boxes:
-SKY_STAT            STR  FITTED_MEAN_V4  # statistic used to measure background
-
-PSF_SN_LIM          F32  30              # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
-
+# PSF model parameters : choose the PSF model
 PSF_MODEL           STR  PS_MODEL_PGAUSS
 
-MOMENTS_SN_MIN      F32   30.0
-MOMENTS_AR_MAX      F32   2.0		 # maximum axial ratio: 1 / AR < (sx / sy) < AR
-
-#EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-#FULL_FIT_SN_LIM      F32  50.0
-#AP_MIN_SN            F32  20.0
+# xxx check this:
 PSF_CLUMP_NSIGMA   F32  3.5             # region of Sx,Sy plane to use for selecting PSF stars
 
-# PSFTREND must be a 2D polynomial
-# the specified values are ignored but define the active components of the polynomial
-PSF.TREND.MASK  METADATA  
-   NORDER_X         S32       3                # number of x orders
-   NORDER_Y         S32       3                # number of y orders
-   VAL_X00_Y00      F64       1                # polynomial coefficient
-
-   VAL_X01_Y00      F64       1                # polynomial coefficient
-   VAL_X00_Y01      F64       1                # polynomial coefficient
-
-   VAL_X02_Y00      F64       1                # polynomial coefficient
-   VAL_X01_Y01      F64       1                # polynomial coefficient
-   VAL_X00_Y02      F64       1                # polynomial coefficient
-
-   VAL_X03_Y00      F64       1                # polynomial coefficient
-   VAL_X02_Y01      F64       1                # polynomial coefficient
-   VAL_X01_Y02      F64       1                # polynomial coefficient
-   VAL_X00_Y03      F64       1                # polynomial coefficient
-   NELEMENTS        S32       10               # number of unmasked components
-END  # folder for 4D polynomial
-
+# XXX set other 2D trends
 PSF.TREND.NX S32 4
 PSF.TREND.NY S32 4
-
-XMIN F32 15
-
-PSF.RESIDUALS       BOOL true
-PSF.RESIDUALS.SPATIAL_ORDER S32 1
-
-BREAK_POINT         STR  ENSEMBLE
-OUTPUT.FORMAT       STR  PS1_DEV_0
-
-PSPHOT.SUMMIT METADATA
- PEAKS_SMOOTH_SIGMA  F32  0.8 	   	 # peak significance threshold
- PEAKS_NSIGMA_LIMIT  F32  50.0 	   	 # peak significance threshold
- PEAKS_NMAX          S32  1000
- SAVE.RESID	BOOL 	FALSE
- PSF_SN_LIM          F32  25              # minimum S/N for stars used for PSF model
- MOMENTS_SN_MIN      F32   25.0
- PSF_MODEL         STR  PS_MODEL_PGAUSS
-END
-
-DIAGNOSTIC.PLOTS		METADATA
-  IMAGE.BACKGROUND.CELL.HISTOGRAM   BOOL FALSE
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.X S32  4
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.Y S32  7
-END
-
-SKY_BIAS F32 0.5
-AP_MIN_SN            F32  30.0
Index: branches/eam_branches/20090820/ippconfig/lbc_red/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/lbc_red/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/lbc_red/psphot.config	(revision 25766)
@@ -1,42 +1,6 @@
 
 # turn these on to see specific outputs
-SAVE.OUTPUT	BOOL 	TRUE
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
 SAVE.PLOTS     	BOOL    TRUE
-
-BACKGROUND.XBIN	    S32  128            # size of background superpixels
-BACKGROUND.YBIN	    S32  128            # size of background superpixels
-
-# image background parameters
-IMSTATS_NPIX        S32  10000    	 # number of pixels to use for sky estimate boxes:
-SKY_STAT            STR  FITTED_MEAN_V4  # statistic used to measure background
-SKY_CLIP_SIGMA      F32  2.0             # statistic used to measure background
-
-PSF_SN_LIM          F32  100             # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
 
 # PSF model parameters : choose the PSF model desired
 PSF_MODEL           STR  PS_MODEL_QGAUSS
-
-MOMENTS_SN_MIN      F32   30.0
-EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  50.0
-AP_MIN_SN            F32  50.0
-
-# OUTPUT.FORMAT       STR SMPDATA
-OUTPUT.FORMAT       STR PS1_DEV_1
-
-PSF_SHAPE_NSIGMA     F32  3.0		 # max significance for shape variation
-PSF_MAX_CHI          F32  50.0		 # reject objects worse that this
-
-#PSF.TREND.MODE STR MAP
-#PSF.TREND.NX   S32 1
-#PSF.TREND.NY   S32 1
-
-DIAGNOSTIC.PLOTS		METADATA
-  IMAGE.BACKGROUND.CELL.HISTOGRAM   BOOL FALSE
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.X S32 -1
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.Y S32 12
-END
-
Index: branches/eam_branches/20090820/ippconfig/lulin/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/lulin/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/lulin/psphot.config	(revision 25766)
@@ -1,43 +1,6 @@
 
 # turn these on to see specific outputs
-SAVE.OUTPUT	BOOL 	TRUE
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
 SAVE.PLOTS     	BOOL    TRUE
-
-BACKGROUND.XBIN	    S32  128            # size of background superpixels
-BACKGROUND.YBIN	    S32  128            # size of background superpixels
-
-# image background parameters
-IMSTATS_NPIX        S32  10000    	 # number of pixels to use for sky estimate boxes:
-SKY_STAT            STR  FITTED_MEAN_V4  # statistic used to measure background
-SKY_CLIP_SIGMA      F32  2.0             # statistic used to measure background
-
-PSF_SN_LIM          F32  100             # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
 
 # PSF model parameters : choose the PSF model desired
 PSF_MODEL           STR  PS_MODEL_QGAUSS
-
-MOMENTS_SN_MIN      F32   30.0
-EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  50.0
-AP_MIN_SN            F32  50.0
-
-# OUTPUT.FORMAT       STR SMPDATA
-OUTPUT.FORMAT       STR PS1_DEV_1
-
-PSF_SHAPE_NSIGMA     F32  3.0		 # max significance for shape variation
-PSF_MAX_CHI          F32  50.0		 # reject objects worse that this
-
-#PSF.TREND.MODE STR MAP
-#PSF.TREND.NX   S32 1
-#PSF.TREND.NY   S32 1
-
-DIAGNOSTIC.PLOTS		METADATA
-  IMAGE.BACKGROUND.CELL.HISTOGRAM   BOOL FALSE
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.X S32 -1
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.Y S32 12
-END
-
-USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
Index: branches/eam_branches/20090820/ippconfig/megacam/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/megacam/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/megacam/psphot.config	(revision 25766)
@@ -1,44 +1,10 @@
 
 # turn these on to see specific outputs
-SAVE.OUTPUT	BOOL 	TRUE
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
 SAVE.PLOTS     	BOOL    TRUE
-
-BACKGROUND.XBIN	    S32  128            # size of background superpixels
-BACKGROUND.YBIN	    S32  128            # size of background superpixels
-
-# image background parameters
-IMSTATS_NPIX        S32  10000    	 # number of pixels to use for sky estimate boxes:
-SKY_STAT            STR  FITTED_MEAN_V4  # statistic used to measure background
-SKY_CLIP_SIGMA      F32  2.0             # statistic used to measure background
-
-PSF_SN_LIM          F32  20             # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
 
 # PSF model parameters : choose the PSF model desired
 PSF_MODEL           STR  PS_MODEL_QGAUSS
 
-PSF_MOMENTS_RADIUS  F32   10.0           # calculate initial source moments with this radius
-
-MOMENTS_SN_MIN      F32    2.0
-EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  10.0
-AP_MIN_SN            F32   2.0
-
-PSF_SHAPE_NSIGMA     F32  3.0		 # max significance for shape variation
-PSF_MAX_CHI          F32  50.0		 # reject objects worse that this
-
 PSF.TREND.MODE STR MAP
 PSF.TREND.NX   S32 1
 PSF.TREND.NY   S32 1
-
-DIAGNOSTIC.PLOTS		METADATA
-  IMAGE.BACKGROUND.CELL.HISTOGRAM   BOOL FALSE
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.X S32 -1
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.Y S32 12
-END
-
-USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
-
-PEAKS_NSIGMA_LIMIT	F32	10.0
Index: branches/eam_branches/20090820/ippconfig/mosaic2/camera.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/mosaic2/camera.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/mosaic2/camera.config	(revision 25766)
@@ -90,4 +90,5 @@
   CMF.XSRC STR {CHIP.NAME}.xsrc # use .PSF and .EXT?
   CMF.XFIT STR {CHIP.NAME}.xfit # use .PSF and .EXT?
+  CMF.DETEFF STR {CHIP.NAME}.deteff
 
   PSF.HEAD  STR {CHIP.NAME}.hdr
Index: branches/eam_branches/20090820/ippconfig/mosaic2/format.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/mosaic2/format.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/mosaic2/format.config	(revision 25766)
@@ -90,5 +90,5 @@
 	CELL.TIMESYS		STR	UTC		# Header says "UTC approximate"
 	CELL.READDIR		S32	1		# Cell is read in x direction
-	CELL.BAD		S32	0
+	CELL.BAD		S32	-100
 	CELL.YPARITY		S32	1
 	CELL.Y0			S32	0
Index: branches/eam_branches/20090820/ippconfig/mosaic2/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/mosaic2/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/mosaic2/psphot.config	(revision 25766)
@@ -1,44 +1,32 @@
 	
-# turn these on to see specific outputs
-SAVE.RESID	BOOL 	TRUE
+IMSTATS_NPIX                         S32   10000    	 # number of pixels to use for sky estimate boxes:
 
-IMSTATS_NPIX        S32  1000    	 # number of pixels to use for sky estimate boxes:
+# robust vs fitted??  gpc1 uses fitted...  robust median gives better background stdev --> test with flat-field photometry
+SKY_STAT                             STR   ROBUST_MEDIAN    # statistic used to measure background
 
-PSF_SN_LIM          F32  20             # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
+PSF_MODEL                            STR   PS_MODEL_QGAUSS
+PSF_MAX_NSTARS                       S32   300              # limit number of stars used for PSF model
 
-# PSF model parameters : choose the PSF model
-# list as many PSF_MODEL options as desired
-# if you want to list multiple entries, uncomment 'MULTI' here
-# PSF_MODEL           MULTI
-PSF_MODEL           STR  PS_MODEL_QGAUSS
-# PSF_MODEL           STR  PS_MODEL_GAUSS
-# PSF_MODEL           STR  PS_MODEL_PGAUSS
-# PSF_MODEL           STR  PS_MODEL_TGAUSS  ## not well tested, not very successful
+# Mosaic 2 has substantial IQ variations in the y-direction
+PSF_CLUMP_NX                         S32   1               # subdivide image in to NX x NY regions for 
+PSF_CLUMP_NY                         S32   3               # selecting PSF stars
 
-MOMENTS_SN_MIN       F32  10.0           # min S/N to measure moments
-EXT_MIN_SN           F32  20.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  20.0
-AP_MIN_SN            F32  25.0
+# Mosaic 2 has substantial IQ variations in the y-direction
+PSF.TREND.NX                         S32   1
+PSF.TREND.NY                         S32   3
 
-USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
+PEAKS_NSIGMA_LIMIT                   F32   15.0            # peak significance threshold
+FOOTPRINT_NSIGMA_LIMIT               F32   14.0      	  # threshold for bright pmFootprint detection
 
-## gene's overrides for testing:
-PEAKS_NSIGMA_LIMIT_2 F32  10.0 	   	 # peak significance threshold
+PSF_SN_LIM                           F32   20.0            # minimum S/N for stars used for PSF model
+FULL_FIT_SN_LIM                      F32   10.0
+EXT_MIN_SN                           F32   10.0           # fit galaxies above this S/N limit
 
-EXT_MODEL           STR  PS_MODEL_QGAUSS
+EXT_MODEL                            STR   PS_MODEL_QGAUSS
 
-TEST_FIT            BOOL FALSE
-TEST_FIT_X          F32  781
-TEST_FIT_Y          F32  830
+EXTENDED_SOURCE_SN_LIM               F32   3.0
+#EXTENDED_SOURCE_ANALYSIS            BOOL  TRUE  # perform any of the aperture-like measurements?
+#EXTENDED_SOURCE_PETROSIAN           BOOL  TRUE
 
-TEST_FIT_MODE       STR  CONV
-#TEST_FIT_MODE       STR PSF
-#TEST_FIT_MODE       STR  EXT
-
-#TEST_FIT_MODEL      STR  PS_MODEL_SERSIC
-TEST_FIT_MODEL      STR  PS_MODEL_QGAUSS
-TEST_MOMENTS_RADIUS F32 9.0
-OUTPUT.FORMAT       STR PS1_DEV_1
-
-PSF_MOMENTS_RADIUS  F32    7               # calculate initial source moments with this radius
+# 3 to match PSF and Moments 2D variations
+APTREND.ORDER.MAX                    S32   3
Index: branches/eam_branches/20090820/ippconfig/recipes/filerules-mef.mdc
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/filerules-mef.mdc	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/filerules-mef.mdc	(revision 25766)
@@ -149,6 +149,6 @@
 PPIMAGE.OUT.WT.SPL      OUTPUT {OUTPUT}.{CHIP.NAME}.wt.fits      VARIANCE  NONE       CHIP       TRUE      SPLIT
 PPIMAGE.OUTPUT.DETMASK  OUTPUT {OUTPUT}.fits                     IMAGE     MASK       CHIP       TRUE      MEF
-PPIMAGE.OUTPUT.DETREND  OUTPUT {OUTPUT}.fits                     IMAGE     COMP_DET   CHIP       TRUE      MEF
-PPIMAGE.OUTPUT.RESID    OUTPUT {OUTPUT}.b0.fits                  IMAGE     COMP_SUB   CHIP       TRUE      MEF
+PPIMAGE.OUTPUT.DETREND  OUTPUT {OUTPUT}.fits                     IMAGE     NONE       CHIP       TRUE      MEF
+PPIMAGE.OUTPUT.RESID    OUTPUT {OUTPUT}.b0.fits                  IMAGE     NONE       CHIP       TRUE      MEF
 PPIMAGE.CONFIG          OUTPUT {OUTPUT}.{CHIP.NAME}.ppImage.mdc  TEXT      NONE       CHIP       TRUE      NONE
                                                                                              
Index: branches/eam_branches/20090820/ippconfig/recipes/filerules-split.mdc
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/filerules-split.mdc	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/filerules-split.mdc	(revision 25766)
@@ -119,6 +119,6 @@
 PPIMAGE.OUTPUT.VARIANCE OUTPUT {OUTPUT}.{CHIP.NAME}.wt.fits      VARIANCE  COMP_WT    CHIP       TRUE      NONE
 PPIMAGE.OUTPUT.DETMASK  OUTPUT {OUTPUT}.{CHIP.NAME}.fits         IMAGE     DET_MASK   CHIP       TRUE      NONE
-PPIMAGE.OUTPUT.DETREND  OUTPUT {OUTPUT}.{CHIP.NAME}.fits         IMAGE     COMP_DET   CHIP       TRUE      NONE
-PPIMAGE.OUTPUT.RESID    OUTPUT {OUTPUT}.{CHIP.NAME}.fits         IMAGE     COMP_SUB   CHIP       TRUE      NONE
+PPIMAGE.OUTPUT.DETREND  OUTPUT {OUTPUT}.{CHIP.NAME}.fits         IMAGE     NONE       CHIP       TRUE      NONE
+PPIMAGE.OUTPUT.RESID    OUTPUT {OUTPUT}.{CHIP.NAME}.fits         IMAGE     NONE       CHIP       TRUE      NONE
 PPIMAGE.CONFIG          OUTPUT {OUTPUT}.{CHIP.NAME}.ppImage.mdc  TEXT      NONE       CHIP       TRUE      NONE
 	        									        
@@ -127,5 +127,5 @@
 PPIMAGE.CHIP.MASK       OUTPUT {OUTPUT}.{CHIP.NAME}.ch.mk.fits   MASK      COMP_MASK  CHIP       TRUE      NONE
 PPIMAGE.CHIP.VARIANCE   OUTPUT {OUTPUT}.{CHIP.NAME}.ch.wt.fits   VARIANCE  COMP_WT    CHIP       TRUE      NONE
-PPIMAGE.CHIP.RESID      OUTPUT {OUTPUT}.{CHIP.NAME}.ch.fits      IMAGE     COMP_SUB   CHIP       TRUE      NONE
+PPIMAGE.CHIP.RESID      OUTPUT {OUTPUT}.{CHIP.NAME}.ch.fits      IMAGE     NONE       CHIP       TRUE      NONE
 		        									        
 PPIMAGE.OUTPUT.FPA1     OUTPUT {OUTPUT}.b1.fits                  IMAGE     NONE       FPA        TRUE      NONE
@@ -146,7 +146,7 @@
 PPMERGE.OUTPUT.SHUTTER  OUTPUT {OUTPUT}.{CHIP.NAME}.fits         IMAGE     NONE       CHIP       TRUE      NONE
 PPMERGE.OUTPUT.FLAT     OUTPUT {OUTPUT}.{CHIP.NAME}.fits         IMAGE     NONE       CHIP       TRUE      NONE
-PPMERGE.OUTPUT.FRINGE   OUTPUT {OUTPUT}.{CHIP.NAME}.fits         FRINGE    NONE       CHIP       TRUE      NONE
-PPMERGE.OUTPUT.SIGMA    OUTPUT {OUTPUT}.{CHIP.NAME}.sigma.fits   IMAGE     NONE       CHIP       TRUE      NONE
-PPMERGE.OUTPUT.COUNT    OUTPUT {OUTPUT}.{CHIP.NAME}.count.fits   IMAGE     NONE       CHIP       TRUE      NONE
+PPMERGE.OUTPUT.FRINGE   OUTPUT {OUTPUT}.{CHIP.NAME}.fits         FRINGE    NONE       CELL       TRUE      NONE
+PPMERGE.OUTPUT.SIGMA    OUTPUT {OUTPUT}.{CHIP.NAME}.sigma.fits   IMAGE     NONE       CELL       TRUE      NONE
+PPMERGE.OUTPUT.COUNT    OUTPUT {OUTPUT}.{CHIP.NAME}.count.fits   IMAGE     NONE       CELL       TRUE      NONE
 		        									        
 DVOCORR.OUTPUT          OUTPUT {OUTPUT}.{CHIP.NAME}.fc.fits      IMAGE     NONE       CHIP       TRUE      NONE
Index: branches/eam_branches/20090820/ippconfig/recipes/masks.16bit.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/masks.16bit.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/masks.16bit.config	(revision 25766)
@@ -20,4 +20,5 @@
 
 # Mask values which represent non-astronomical structures
+BURNTOOL        U16     0x0080          # Pixel may contain uncorrected streak.
 CR		U16	0x0100		# Pixel contains a cosmic ray
 SPIKE		U16	0x0200		# Pixel contains a diffraction spike
Index: branches/eam_branches/20090820/ippconfig/recipes/ppImage.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/ppImage.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/ppImage.config	(revision 25766)
@@ -16,4 +16,5 @@
 MASK.SATURATED     BOOL    TRUE            # Mask the saturated pixels
 MASK.LOW           BOOL    TRUE            # Mask pixels below valid range
+MASK.BURNTOOL      BOOL    FALSE           # Mask potential burntool trails
 VARIANCE.BUILD     BOOL    FALSE           # Build internal variance image
 PATTERN            BOOL    FALSE           # Fit and remove pattern noise?
@@ -25,4 +26,5 @@
 CHECK.CTE          BOOL    FALSE           # measure CTE errors?
 USE.DEBURNED.IMAGE BOOL    FALSE           # use burntool-repaired image?
+USE.BEST.BURNTOOL  BOOL    TRUE            # require the best burntooled data
 TILTYSTREAK.APPLY  BOOL    FALSE           # apply the 'tiltystreak' tool
 
@@ -55,4 +57,7 @@
 SCAN.ROWS        S32     100
 
+# Which regions identified by burntool to mask. 0x01 : only unfit trails, 0x02 "up" trails, 0x04 "down" trails
+BURNTOOL.TRAILS     U16 0x01
+
 # Non-linearity correction
 NONLIN.SOURCE           STR     CHIP.NAME       # How to determine the source
@@ -145,4 +150,5 @@
   FLAT               BOOL    TRUE            # Flat-field normalisation
   MASK               BOOL    TRUE            # Mask bad pixels
+  MASK.BURNTOOL      BOOL    TRUE            # Mask potential burntool trails
   FRINGE             BOOL    TRUE            # Fringe subtraction
   BIN1.FITS          BOOL    TRUE            # Save 1st binned chip image?
@@ -168,4 +174,5 @@
   FLAT               BOOL    TRUE            # Flat-field normalisation
   MASK               BOOL    TRUE            # Mask bad pixels
+  MASK.BURNTOOL      BOOL    TRUE            # Mask potential burntool trails
   FRINGE             BOOL    TRUE            # Fringe subtraction
   BIN1.FITS          BOOL    TRUE            # Save 1st binned chip image?
@@ -191,4 +198,5 @@
   FLAT               BOOL    TRUE            # Flat-field normalisation
   MASK               BOOL    TRUE            # Mask bad pixels
+  MASK.BURNTOOL      BOOL    TRUE            # Mask potential burntool trails
   FRINGE             BOOL    TRUE            # Fringe subtraction
   BIN1.FITS          BOOL    TRUE            # Save 1st binned chip image?
@@ -557,4 +565,5 @@
   FLAT               BOOL    TRUE            # Flat-field normalisation
   MASK               BOOL    TRUE            # Mask bad pixels
+  MASK.BURNTOOL      BOOL    TRUE            # Mask potential burntool trails
   FRINGE             BOOL    TRUE            # Fringe subtraction
   BIN1.FITS          BOOL    TRUE            # Save 1st binned chip image?
@@ -1717,4 +1726,5 @@
   FLAT               BOOL    TRUE            # Flat-field normalisation
   MASK               BOOL    TRUE            # Mask bad pixels
+  MASK.BURNTOOL      BOOL    TRUE            # Mask potential burntool trails
   PATTERN            BOOL    TRUE            # Subtract pattern noise?
   FRINGE             BOOL    TRUE            # Fringe subtraction
Index: branches/eam_branches/20090820/ippconfig/recipes/ppSim.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/ppSim.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/ppSim.config	(revision 25766)
@@ -50,7 +50,7 @@
 
 STARS.FAKE      BOOL    TRUE		# Add fake stars, randomly distributed?
-STARS.LUM	F32	0.6		# Stellar luminosity function slope (magnitude slope)
-STARS.MAG	F32	15.5		# Brightest magnitude for fake stars
-STARS.DENSITY	F32     50.0		# Stellar density (per square degree) at the brightest magnitude
+STARS.LUM	F32	0.35		# Stellar luminosity function slope (magnitude slope)
+STARS.MAG	F32	15.5		# Brightest magnitude for fake stars (choose based on real catalog limit)
+STARS.DENSITY	F32      1.0		# Stellar density (per square degree) at the brightest magnitude
 STARS.SIGMA.LIM F32      5.0            # significance of faintest sources
 
@@ -185,4 +185,10 @@
 END
 
+STACKTEST.MAKE  METADATA
+END
+
+STACKTEST.RUN  METADATA
+END
+
 # Overrides for creating large holes in the image
 LARGEHOLES	METADATA
Index: branches/eam_branches/20090820/ippconfig/recipes/ppStack.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/ppStack.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/ppStack.config	(revision 25766)
@@ -3,5 +3,5 @@
 CONVOLVE	BOOL	TRUE		# Convolve images when stacking?
 ITER		S32	1		# Number of rejection iterations
-COMBINE.REJ	F32	2.0		# Rejection threshold in combination (sigma)
+COMBINE.REJ	F32	2.5		# Rejection threshold in combination (sigma)
 COMBINE.SYS	F32	0.03		# Relative systematic error in combination
 COMBINE.DISCARD	F32	0.2		# Discard fraction for Olympic weighted mean
@@ -11,7 +11,7 @@
 POOR.FRACTION	F32	0.01		# Maximum fraction of bad variance for poor pixels
 THRESHOLD.MASK	F32	0.5		# Threshold for mask deconvolution (0..1)
-DECONV.LIMIT	F32	5.0		# Deconvolution fraction for rejecting entire image
+DECONV.LIMIT	F32	1.3		# Deconvolution fraction for rejecting entire image
 IMAGE.REJ	F32	0.1		# Rejected pixel fraction threshold for rejecting entire image
-MATCH.REJ	F32	5.0		# Rejection threshold for chi^2 values from matching
+MATCH.REJ	F32	3.0		# Rejection threshold for chi^2 values from matching
 ROWS		S32	64		# Number of rows to read at once
 VARIANCE	BOOL	TRUE		# Use variance in rejection?
@@ -19,11 +19,11 @@
 BIN1		S32	4		# Binning factor for first level
 BIN2		S32	4		# Binning factor for second level
+PHOTOMETRY      BOOL    TRUE            # Do basic photometry?
 SKIP.BG.SUB	BOOL	FALSE		# Bypass background subtraction?
 
-RENORM		BOOL	FALSE		# Renormalise variance maps?
-RENORM.NUM	S32	10000		# Number of samples for renormalisation
-RENORM.MEAN	STR	ROBUST_MEDIAN	# Statistic to use for mean in renormalisation
-RENORM.STDEV	STR	ROBUST_STDEV	# Statistic to use for stdev in renormalisation
-RENORM.WIDTH	F32	2.2		# Gaussian width for normalisation
+RENORM		BOOL	TRUE		# Renormalise weight maps?
+RENORM.NUM	S32	100000		# Number of samples for renormalisation
+RENORM.MIN	F32	NAN		# Minimum value for renormlisation
+RENORM.MAX	F32	NAN		# Maximum value for renormalisation
 
 ### The PHOT mode is intended as a quick and dirty stopgap; it should disappear soon.
Index: branches/eam_branches/20090820/ippconfig/recipes/ppStats.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/ppStats.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/ppStats.config	(revision 25766)
@@ -190,4 +190,6 @@
   CONCEPT       STR     FPA.TELTEMP.EXTRA  # Miscellaneous temperatures (C)     
 
+  CONCEPT       STR     FPA.BURNTOOL.APPLIED 
+
   CONCEPT       STR	FPA.PON.TIME    # time since last power on
 
Index: branches/eam_branches/20090820/ippconfig/recipes/ppStatsFromMetadata.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/ppStatsFromMetadata.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/ppStatsFromMetadata.config	(revision 25766)
@@ -44,4 +44,5 @@
   ENTRY  VAL  FPA.TELTEMP.EXTRA   F32  CONSTANT          -teltemp_extra       # Miscellaneous temperatures (C)
   ENTRY  VAL  FPA.PON.TIME     	  F32  CONSTANT          -pon_time            # time since last power on
+#  ENTRY  VAL  FPA.BURNTOOL.APPLIED S32 CONSTANT          -burntool_state      # 
   ENTRY  VAL  CHIP.TEMP        	  F32  SAMPLE_MEAN       -ccd_temp            # CCD temperature
   ENTRY  VAL  CELL.EXPOSURE    	  F32  SAMPLE_MEAN       -exp_time            # Exposure time
Index: branches/eam_branches/20090820/ippconfig/recipes/ppSub.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/ppSub.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/ppSub.config	(revision 25766)
@@ -21,5 +21,5 @@
 POOR.FRACTION	F32	0.10		# Maximum fraction of bad weight for poor pixels
 BADFRAC		F32	0.95		# Maximum fraction of bad pixels
-@ISIS.WIDTHS	F32	1 3 5 7		# Gaussian FWHMs for ISIS kernels
+@ISIS.WIDTHS	F32	3 5 7 10	# Gaussian FWHMs for ISIS kernels
 @ISIS.ORDERS	S32	2 2 2 2		# Polynomial orders for ISIS kernels
 SPAM.BINNING	S32	2		# Binning in outer region for SPAM kernels
@@ -37,16 +37,10 @@
 OPTIMUM.ORDER	S32	2		# Maximum polynomial order for optimum search
 
-RENORM		BOOL	FALSE		# Renormalise weight maps?
-RENORM.NUM	S32	10000		# Number of samples for renormalisation
-RENORM.MEAN	STR	ROBUST_MEDIAN	# Statistic to use for mean in renormalisation
-RENORM.STDEV	STR	ROBUST_STDEV	# Statistic to use for stdev in renormalisation
-RENORM.WIDTH	F32	2.2		# Gaussian width for normalisation
+RENORM		BOOL	TRUE		# Renormalise weight maps?
+RENORM.NUM	S32	100000		# Number of samples for renormalisation
+RENORM.MIN	F32	0.6		# Minimum value for renormlisation
+RENORM.MAX	F32	1.5		# Maximum value for renormalisation
 
 INTERPOLATION	STR	LANCZOS3	# Interpolation mode for bad pixels
-
-VARIANCE.RESCALE           BOOL FALSE	# empirically rescale the variance?
-VARIANCE.RESCALE.NSAMPLE   S32  100000	# number of pixels to select from image for measurement
-VARIANCE.RESCALE.MIN.VALID F32  0.66	# do not rescale the variance if the measured sigma less than this value (where 1.0 is expected)
-VARIANCE.RESCALE.MAX.VALID F32  1.50	# do not rescale the variance if the measured sigma more than this value (where 1.0 is expected)
 
 DUAL		BOOL	FALSE		# Dual convolution?
Index: branches/eam_branches/20090820/ippconfig/recipes/psastro.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/psastro.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/psastro.config	(revision 25766)
@@ -3,4 +3,7 @@
 PSASTRO.ONLY.REFSTARS      BOOL FALSE  # skip all but refstar matches
 PSASTRO.SAVE.REFMATCH      BOOL FALSE  # save refstar matches as table in output smf file
+
+# select which WCS style to use on output images.
+PSASTRO.WCS.USECDKEYS	 BOOL FALSE
 
 # perform single-chip astrometry?
Index: branches/eam_branches/20090820/ippconfig/recipes/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/psphot.config	(revision 25766)
@@ -2,12 +2,12 @@
 # these options turn on different inputs and/or outputs
 SAVE.OUTPUT                         BOOL  TRUE
-SAVE.BACKMDL                        BOOL  FALSE
+SAVE.BACKMDL                        BOOL  TRUE
 SAVE.BACKMDL.STDEV                  BOOL  FALSE
 SAVE.BACKGND                        BOOL  FALSE
 SAVE.BACKSUB                        BOOL  FALSE
 SAVE.RESID                          BOOL  FALSE
+SAVE.PLOTS                          BOOL  FALSE
 SAVE.PSF                            BOOL  TRUE
 LOAD.PSF                            BOOL  FALSE
-SAVE.PLOTS                          BOOL  FALSE
 
 # format for output CMF files
@@ -15,7 +15,5 @@
 
 # the zero point is used to set a basic scale for DVO
-# XXX it may not currently be read : double check this (EAM)
-ZERO_POINT                          F32   25.000          # zero point used by DVO
-ZERO_PT                             F32   25.000          # zero point used by DVO
+ZERO_PT                             F32   25.000          # zero point used by DVO XXX deprecate this
 
 # these parameter govern how the background is measured
@@ -23,4 +21,8 @@
 BACKGROUND.YBIN                     S32   128             # size of background superpixels
 IMSTATS_NPIX                        S32   10000           # number of pixels to use for sky estimate boxes:
+
+# soften the errors for bright pixels:
+SOFTEN.VARIANCE                     BOOL  FALSE
+SOFTEN.VARIANCE.FRACTION            F32   0.0
 
 SKY_BIAS                            F32   0.0             # offset applied to measured sky (FOR TESTING)
@@ -43,26 +45,38 @@
 PEAKS_SMOOTH_SIGMA                  F32   1.0             # smoothing kernel sigma in pixels
 PEAKS_SMOOTH_NSIGMA                 F32   2.0             # smoothing kernel width in sigmas
-PEAKS_NSIGMA_LIMIT                  F32   25.0            # peak significance threshold
+PEAKS_NSIGMA_LIMIT                  F32   20.0            # peak significance threshold
 PEAKS_NSIGMA_LIMIT_2                F32   5.0             # peak significance threshold
-PEAKS_NMAX                          S32   0               # on first pass, only keep NMAX peaks (0 == all)
-PEAKS_MIN_GAUSS                     F32   0.5             # Minimum valid fraction of kernel
+PEAKS_NMAX                          S32   5000            # on first pass, only keep NMAX peaks (0 == all)
+PEAKS_MIN_GAUSS                     F32   0.5             # On quick convolution, mask pixels for which the 
+				    	  		  # input pixels contribute less than this fraction of the flux
+# parameters which adjust the footprint analysis
+USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
+FOOTPRINT_NPIXMIN                   S32   5       	  # Minimum size of a pmFootprint
+FOOTPRINT_GROW_RADIUS               S32   3       	  # How much to grow bright footprints
+FOOTPRINT_GROW_RADIUS_2             S32   5       	  # How much to grow faint footprints
+FOOTPRINT_CULL_NSIGMA_DELTA         F32   4       	  # Cull peaks that aren't nsigma above coll to neighbour
+FOOTPRINT_CULL_NSIGMA_MIN           F32   1       	  # Minimum height of colls in units of skyStdev
+FOOTPRINT_CULL_NSIGMA_PAD           F32   0.01       	  # Fractional Padding for stdev
+
+# parameter for the simple deblending
+DEBLEND_PEAK_FRACTION               F32   0.1
+DEBLEND_SKY_NSIGMA                  F32   10.0
 
 # parameters to control the selection of the peak in the Sx,Sy plane
 MOMENTS_SCALE                       F32   0.25       
-MOMENTS_SN_MIN                      F32   10.0           # min S/N to measure moments
+MOMENTS_SN_MIN                      F32   0.0             # min S/N to measure moments (default: measure all objects)
 MOMENTS_SX_MAX                      F32   50.0
 MOMENTS_SY_MAX                      F32   50.0
 MOMENTS_AR_MAX                      F32   1.5             # maximum axial ratio: 1 / AR < (sx / sy) < AR
-MOMENTS_MIN_PIXEL_SN		    F32	  0.0		  # XXX caution on this: too high and we will excessively clip
-MOMENTS_GAUSS_SIGMA		    F32	  4.0		  # XXX TEST THIS: sigma in pixels (should be >> seeing equiv)
+MOMENTS_GAUSS_SIGMA		    F32	  4.0		  # XXX this is now autoscaled
 
 # basic object statistics
 SKY_INNER_RADIUS                    F32   15              # square annulus for local sky measurement
 SKY_OUTER_RADIUS                    F32   25              # square annulus for local sky measurement
-PSF_MOMENTS_RADIUS                  F32   3               # calculate initial source moments with this radius
-PSF_SN_LIM                          F32   50              # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS                      S32   200             # limit number of stars used for PSF model
+PSF_MOMENTS_RADIUS                  F32   3               # XXX this is now autoscaled
+PSF_SN_LIM                          F32   20              # minimum S/N for stars used for PSF model
+PSF_MAX_NSTARS                      S32   500             # limit number of stars used for PSF model
 PSF_CLUMP_NSIGMA                    F32   1.5             # region of Sx,Sy plane to use for selecting PSF stars
-PSF_CLUMP_GRID_SCALE                F32   0.5             # size of Sx,Sy image pixel
+PSF_CLUMP_GRID_SCALE                F32   0.2             # size of Sx,Sy image pixel
 
 PSF_CLUMP_NX                        S32   1               # subdivide image in to NX x NY regions for 
@@ -80,6 +94,4 @@
 PSF_MODEL                           STR   PS_MODEL_GAUSS
 # PSF_MODEL                         STR   PS_MODEL_PGAUSS
-# PSF_MODEL                         STR   PS_MODEL_QGAUSS
-# PSF_MODEL                         STR   PS_MODEL_TGAUSS # not well tested, not very successful
 
 # PSF.TREND.MASK must be a 2D polynomial
@@ -98,13 +110,16 @@
 PSF.FAKE.ALLOW                      BOOL  FALSE           # Allow use of fake PSFs when having trouble?
 
-PSF_FIT_RADIUS                      F32   15.0            # fitting radius for test PSF model
+PSF_FIT_RADIUS                      F32   15.0            # XXX this is now autoscaled
 PSF_REF_RADIUS                      F32   25.0            # aperture magnitudes are scaled via 
-                                         # curve-of-growth to this radius
+                                                          # curve-of-growth to this radius
+
+PSF_FIT_RADIUS_SCALE                F32   7.0            # fitting radius for test PSF model
+PSF_APERTURE_SCALE                  F32   4.5            # fitting radius for test PSF model
+
 # PSF-like source model parameters
 PSF_FIT_NSIGMA                      F32   1.0             # significance for pixel included in fit
 PSF_FIT_PADDING                     F32   2.0             # extra annulus to use for fit 
-PSF_SHAPE_NSIGMA                    F32   3.0             # max significance for shape variation
 PSF_MIN_SN                          F32   2.0             # reject objects below this significance
-PSF_MAX_CHI                         F32   50.0            # reject objects worse that this
+PSF_MAX_CHI                         F32   50.0            # reject objects worse than this
 FULL_FIT_SN_LIM                     F32   50.0
 
@@ -117,12 +132,13 @@
 PSF.RESIDUALS.STATISTIC             STR   ROBUST_MEDIAN   # statistic to use for generating the residual
 PSF.RESIDUALS.SPATIAL_ORDER         S32   0               # fit spatial variations of the residuals at this order (0,1)
-PSF.RESIDUALS.PIX.SN                F32   5.0             # keep this pixel if residual is more significant than this
+PSF.RESIDUALS.PIX.SN                F32   0.0             # keep this pixel if residual is more significant than this
+PSF.RESIDUALS.RADIUS                F32   8.0             # keep this pixel if residual is more significant than this
  
 # this model is used for approximate subtraction in the main object analysis step
 EXT_MODEL                           STR   PS_MODEL_QGAUSS
-EXT_MIN_SN                          F32   50.0            # fit galaxies above this S/N limit
 EXT_FIT_NSIGMA                      F32   1               # significance for pixel included in fit
 EXT_FIT_PADDING                     F32   5               # extra annulus to use for fit 
 EXT_MOMENTS_RADIUS                  F32   31
+EXT_FIT_MAX_RADIUS                  F32   128             # non-sensical to fit objects larger than the background mesh
 
 EXT_FIT_ITER                        S32   20              # Maximum number of fitting iterations for EXT
@@ -172,12 +188,8 @@
 PETROSIAN_FLUX_RATIO                F32    0.1 # we measure out to where flux = R0 * FLUX_RATIO
 
-FITMODE                             STR   BLEND  
-DEBLEND_PEAK_FRACTION               F32   0.1
-DEBLEND_SKY_NSIGMA                  F32   10.0
-
 # APTREND                           STR   NONE, CONSTANT, SKYBIAS, SKYSAT, XY_LIN, SKY_XY_LIN, SKYSAT_XY_LIN, ALL
-MEASURE.APTREND	                    BOOL  FALSE		### Gene says there's bugs in this part
+MEASURE.APTREND	                    BOOL  TRUE
 APTREND                             STR   CONSTANT
-AP_MIN_SN                           F32   25.0
+AP_MIN_SN                           F32   0.0 # measure apMags for all sources by default
 APTREND.NSTAR.MIN                   S32   5
 APTREND.ORDER.MAX                   S32   5
@@ -196,5 +208,5 @@
 
 IGNORE_GROWTH                       BOOL  FALSE
-CONSTANT_PHOTOMETRIC_WEIGHTS        BOOL  TRUE 		  # Should the photometric code [currently only ensemblePSF] refuse to weight each pixel by it's significance?
+CONSTANT_PHOTOMETRIC_WEIGHTS        BOOL  FALSE 
 INTERPOLATE_AP                      BOOL  TRUE
 
@@ -207,14 +219,4 @@
 NOISE.FACTOR                        F32   5.0
 NOISE.SIZE                          F32   2.0
-
-USE_FOOTPRINTS                      BOOL  F       	  # use new pmFootprint peak packaging
-FOOTPRINT_NPIXMIN                   S32   5       	  # Minimum size of a pmFootprint
-FOOTPRINT_NSIGMA_LIMIT              F32   20      	  # threshold for bright pmFootprint detection
-FOOTPRINT_NSIGMA_LIMIT_2            F32   4       	  # threshold for faint pmFootprint detection
-FOOTPRINT_GROW_RADIUS               S32   3       	  # How much to grow bright footprints
-FOOTPRINT_GROW_RADIUS_2             S32   5       	  # How much to grow faint footprints
-FOOTPRINT_CULL_NSIGMA_DELTA         F32   4       	  # Cull peaks that aren't nsigma above coll to neighbour
-FOOTPRINT_CULL_NSIGMA_MIN           F32   1       	  # Minimum height of colls in units of skyStdev
-FOOTPRINT_CULL_NSIGMA_PAD           F32   0.01       	  # Fractional Padding for stdev
 
 # alternate PSPHOT-type recipes
@@ -261,8 +263,12 @@
 
 PSPHOT.CR.NSIGMA.LIMIT              F32   3.0  # sources with crNsigma greater that this get tagged as likely cosmic rays
-PSPHOT.EXT.NSIGMA.LIMIT             F32   4.0  # sources with extNsigma greater that this get tagged as likely extended sources
+PSPHOT.EXT.NSIGMA.LIMIT             F32   3.0  # sources with extNsigma greater that this get tagged as likely extended sources
+PSPHOT.EXT.NSIGMA.MOMENTS           F32   2.0  # sources with extNsigma greater that this get tagged as likely extended sources
 PSPHOT.CR.GROW                      S32   1               # Number of pixels to grow CR mask
 PSPHOT.CR.NSIGMA.SOFTEN             F32   0.0025          # Softening parameter for weights
 
+# Detection efficiency
+EFF.NUM                             S32   500			# Number of fake sources per bin
+@EFF.MAG			    F32	  -2.0 -1.0 -0.5 -0.25 -0.1 -0.05 0.0 0.05 0.1 0.25 0.5 1.0 2.0	# Magnitude of fake sources relative to limit
 
 # Recipe overrides for CHIP
Index: branches/eam_branches/20090820/ippconfig/recipes/pswarp.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/pswarp.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/pswarp.config	(revision 25766)
@@ -10,6 +10,12 @@
 ACCEPT.FRAC		F32	0.1		# Minimum fraction of good pixels to accept result
 INTERPOLATION.NUM	S32	1000		# Number of interpolation kernels to pre-calculate
+PSF			BOOL	TRUE		# Measure PSF for warped image?
 
 # Default recipe for warping
 WARP	METADATA
 END
+
+#PR recipe for faster processing
+PR METADATA
+	PSF	BOOL	FALSE
+END
Index: branches/eam_branches/20090820/ippconfig/recipes/reductionClasses.mdc
===================================================================
--- branches/eam_branches/20090820/ippconfig/recipes/reductionClasses.mdc	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/recipes/reductionClasses.mdc	(revision 25766)
@@ -307,5 +307,5 @@
 	CHIP_PPIMAGE  	STR	PR
 	CHIP_PSPHOT	STR	PR
-	WARP_PSWARP	STR	WARP
+	WARP_PSWARP	STR	PR
 	STACK_PPSTACK	STR	PR
 	STACK_PPSUB	STR	PR
@@ -324,5 +324,5 @@
 	CHIP_PPIMAGE  	STR	PR_DARKTEST_NOSUB
 	CHIP_PSPHOT	STR	PR
-	WARP_PSWARP	STR	WARP
+	WARP_PSWARP	STR	PR
 	STACK_PPSTACK	STR	PR
 	STACK_PPSUB	STR	PR
Index: branches/eam_branches/20090820/ippconfig/sdss/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/sdss/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/sdss/psphot.config	(revision 25766)
@@ -1,61 +1,8 @@
-
-# turn these on to see specific outputs
-SAVE.BACKMDL	BOOL 	TRUE
-#SAVE.BACKGND	BOOL 	TRUE
-#SAVE.BACKSUB	BOOL 	TRUE
-#SAVE.RESID	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
-SAVE.PLOTS      BOOL    TRUE
-
-# image statistics parameters
-IMSTATS_NPIX        S32  3000    	 # number of pixels to use for sky estimate boxes:
-
-PSF_SN_LIM          F32  10              # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
 
 PSF_MODEL         STR  PS_MODEL_QGAUSS
 
-MOMENTS_SN_MIN      F32   10.0
-#EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-#FULL_FIT_SN_LIM      F32  50.0
-#AP_MIN_SN            F32  20.0
+# check:
 PSF_CLUMP_NSIGMA   F32  2.5             # region of Sx,Sy plane to use for selecting PSF stars
 
-# PSFTREND must be a 2D polynomial
-# the specified values are ignored but define the active components of the polynomial
-PSF.TREND.MASK  METADATA  
-   NORDER_X         S32       3                # number of x orders
-   NORDER_Y         S32       3                # number of y orders
-   VAL_X00_Y00      F64       1                # polynomial coefficient
-
-   VAL_X01_Y00      F64       1                # polynomial coefficient
-   VAL_X00_Y01      F64       1                # polynomial coefficient
-
-   VAL_X02_Y00      F64       1                # polynomial coefficient
-   VAL_X01_Y01      F64       1                # polynomial coefficient
-   VAL_X00_Y02      F64       1                # polynomial coefficient
-
-   VAL_X03_Y00      F64       1                # polynomial coefficient
-   VAL_X02_Y01      F64       1                # polynomial coefficient
-   VAL_X01_Y02      F64       1                # polynomial coefficient
-   VAL_X00_Y03      F64       1                # polynomial coefficient
-   NELEMENTS        S32       10               # number of unmasked components
-END  # folder for 4D polynomial
-
+# is this needed to mask bad regions?
 XMIN F32 15
-
-PSF.RESIDUALS       BOOL true
-PSF.RESIDUALS.SPATIAL_ORDER S32 1
-
-# BREAK_POINT         STR  ENSEMBLE
-OUTPUT.FORMAT       STR  PS1_DEV_0
-
-PSPHOT.SUMMIT METADATA
- PEAKS_SMOOTH_SIGMA  F32  0.8 	   	 # peak significance threshold
- PEAKS_NSIGMA_LIMIT  F32  50.0 	   	 # peak significance threshold
- PEAKS_NMAX          S32  1000
- SAVE.RESID	BOOL 	FALSE
- PSF_SN_LIM          F32  25              # minimum S/N for stars used for PSF model
- MOMENTS_SN_MIN      F32   25.0
- PSF_MODEL         STR  PS_MODEL_PGAUSS
-END
Index: branches/eam_branches/20090820/ippconfig/sdssmosaic/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/sdssmosaic/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/sdssmosaic/psphot.config	(revision 25766)
@@ -1,42 +1,15 @@
-
-# turn these on to see specific outputs
-SAVE.OUTPUT	BOOL 	TRUE
-SAVE.BACKMDL	BOOL 	TRUE
-#SAVE.RESID	BOOL 	TRUE
-#SAVE.BACKGND	BOOL 	TRUE
-SAVE.BACKSUB	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
-#LOAD.PSF	BOOL 	FALSE
-#SAVE.PLOTS     	BOOL    TRUE
-
-# for testing:
-# BREAK_POINT STR BACKMDL
-
 
 BACKGROUND.XBIN	    S32  256            # size of background superpixels
 BACKGROUND.YBIN	    S32  256            # size of background superpixels
 
-# image background parameters
-IMSTATS_NPIX        S32  10000    	 # number of pixels to use for sky estimate boxes:
-SKY_STAT            STR  FITTED_MEAN_V4  # statistic used to measure background
-SKY_CLIP_SIGMA      F32  2.0             # statistic used to measure background
-
-PEAKS_SMOOTH_SIGMA  F32   2.5            # smoothing kernel sigma in pixels
-PEAKS_NMAX          S32   5000           # on first pass, only keep NMAX peaks (0 == all)
-PEAKS_NSIGMA_LIMIT  F32   25.0           # peak significance threshold
-PEAKS_NSIGMA_LIMIT_2 F32   5.0           # peak significance threshold
-
-PSF_SN_LIM          F32  25              # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
+# what is the 2D variation of the SDSS PSF?
 PSF_CLUMP_NX        S32   3               # subdivide image in to NX x NY regions for 
 PSF_CLUMP_NY        S32   3               # selecting PSF stars
-PSF_MOMENTS_RADIUS  F32  12               # calculate initial source moments with this radius
+
+# test this:
 PSF_CLUMP_GRID_SCALE F32 2.5		# size of Sx,Sy image pixel
-
-PSF.RESIDUALS       BOOL  TRUE            # generate the residuals?
 
 # PSF model parameters : choose the PSF model desired
 PSF_MODEL           STR  PS_MODEL_PS1_V1
-PSPHOT.CR.NSIGMA.SOFTEN             F32   0.0025            # Softening parameter for weights
 
 # Use same default setting as in 2.6.1 (MAP is now global default)
@@ -45,32 +18,8 @@
 PSF.TREND.NY                        S32   0
 
-EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  25.0
-MOMENTS_SN_MIN      F32    5.0
-AP_MIN_SN            F32   5.0
-
-OUTPUT.FORMAT        STR  PS1_V1
-
-PSF_SHAPE_NSIGMA     F32  3.0		 # max significance for shape variation
-PSF_MAX_CHI          F32  50.0		 # reject objects worse that this
-
-MEASURE.APTREND      BOOL TRUE           ### XXX for now, skip this (too many errors)
-APTREND.ORDER.MAX    S32  3
-
-# BREAK_POINT STR PASS1
-
+# match the SDSS radius:
 PSF_REF_RADIUS      F32  18.7            # aperture magnitudes are scaled via 
 					 # curve-of-growth to this radius
-
-DIAGNOSTIC.PLOTS                    METADATA
-  IMAGE.BACKGROUND.CELL.HISTOGRAM   BOOL  FALSE
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.X S32   32
-  IMAGE.BACKGROUND.CELL.HISTOGRAM.Y S32   15
-END
-
-USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
-
-# Default is noap, nopsf; following recipes turn on one or both of these
-
+# for tests: Default is noap, nopsf; following recipes turn on one or both of these
 PSPHOT_NOAP_PSF METADATA
  PSF.TREND.MODE		STR	MAP
@@ -96,4 +45,5 @@
 END
 
+# put these values in the master?
 DIFF	METADATA
 	BACKGROUND.XBIN	    S32  32            # size of background superpixels
Index: branches/eam_branches/20090820/ippconfig/simmosaic/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/simmosaic/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/simmosaic/psphot.config	(revision 25766)
@@ -1,40 +1,3 @@
 
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.BACKGND	BOOL 	TRUE
-SAVE.BACKSUB	BOOL 	TRUE
-SAVE.PLOTS      BOOL    FALSE
-SAVE.RESID	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
-LOAD.PSF	BOOL 	FALSE
-
-IMSTATS_NPIX        S32  3000    	 # number of pixels to use for sky estimate boxes:
-SKY_INNER_RADIUS    F32    10            # square annulus for local sky measurement
-
-PSF_MOMENTS_RADIUS  F32    7               # calculate initial source moments with this radius
-
-
-
-#PSPHOT_TEST METADATA
-# SAVE.BACKSUB	BOOL 	FALSE
-# SAVE.RESID	BOOL 	TRUE
-#END
-#
-#PEAKS_OUTPUT_FILE   STR  peaks.dat
-#MOMENTS_OUTPUT_FILE STR  moments.dat
-
-#PSF_SN_LIM          F32  20.0            # minimum S/N for stars used for PSF model
-MOMENTS_SN_MIN      F32  10.0            # min S/N to measure moments
-FULL_FIT_SN_LIM     F32  100.0
-EXT_MIN_SN          F32  100.0           # fit galaxies above this S/N limit
-
-MOMENTS_SX_MAX                      F32   25.0
-MOMENTS_SY_MAX                      F32   25.0
-
-
-PEAKS_NSIGMA_LIMIT  F32  25.0 	   	 # peak significance threshold
-PEAKS_NSIGMA_LIMIT_2 F32  10.0 	   	 # peak significance threshold
-
-BREAK_POINT         STR  ENSEMBLE        # limit total processing for now (for speed)
-
-
-SKY_STAT            STR  ROBUST_MEDIAN   # statistic used to measure background
+# ppSim currently uses PS_MODEL_GAUSS
+PSF_MODEL                           STR   PS_MODEL_PGAUSS
Index: branches/eam_branches/20090820/ippconfig/simple/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/simple/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/simple/psphot.config	(revision 25766)
@@ -1,17 +1,2 @@
 
-SAVE.BACKMDL	BOOL 	FALSE
-SAVE.BACKGND	BOOL 	FALSE
-SAVE.BACKSUB	BOOL 	FALSE
-SAVE.PLOTS      BOOL    TRUE
 SAVE.RESID	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
-LOAD.PSF	BOOL 	FALSE
-
-IMSTATS_NPIX        S32  3000    	 # number of pixels to use for sky estimate boxes:
-
-MOMENTS_SN_MIN      F32  20.0           # min S/N to measure moments
-FULL_FIT_SN_LIM     F32  100.0
-EXT_MIN_SN          F32  100.0           # fit galaxies above this S/N limit
-
-PEAKS_NSIGMA_LIMIT  F32  10.0 	   	 # peak significance threshold
-USE_FOOTPRINTS      BOOL  T       	  # use new pmFootprint peak packaging
Index: branches/eam_branches/20090820/ippconfig/simtest/camera.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/simtest/camera.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/simtest/camera.config	(revision 25766)
@@ -64,4 +64,5 @@
   CMF.XSRC STR {CHIP.NAME}.xsrc # use .PSF and .EXT?
   CMF.XFIT STR {CHIP.NAME}.xfit # use .PSF and .EXT?
+  CMF.DETEFF STR {CHIP.NAME}.deteff
 
   PSF.HEAD  STR	{CHIP.NAME}.hdr
Index: branches/eam_branches/20090820/ippconfig/simtest/format.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/simtest/format.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/simtest/format.config	(revision 25766)
@@ -69,6 +69,6 @@
 	CELL.X0		S32	0
 	CELL.Y0		S32	0
-	CELL.XSIZE	S32	2048
-	CELL.YSIZE	S32	2048
+	CELL.XSIZE	S32	1024
+	CELL.YSIZE	S32	1024
 	CELL.XWINDOW	S32	0
 	CELL.YWINDOW	S32	0
Index: branches/eam_branches/20090820/ippconfig/simtest/ppSim.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/simtest/ppSim.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/simtest/ppSim.config	(revision 25766)
@@ -3,4 +3,49 @@
 # for a quick test, we are going to skip shutter and dark corrections
 TESTDATA  METADATA
+ PSF.MODEL       STR     PS_MODEL_PGAUSS
+ SHUTTER.TIME	 F32	 0.0
+ DARK.RATE       F32     0.0         
+ SCATTER.FRAC    F32     0.0
+ BIAS            BOOL    FALSE
+ FLAT            BOOL    FALSE
+ BIAS.LEVEL	 F32	 1000.0		# Bias level (e)
+ BIAS.RANGE	 F32	 20.0		# Range of bias values (e)
+ BIAS.ORDER	 S32 	 7		# Order for overscan polynomial
+
+ STARS.MAG	 F32	 10.0		# Brightest magnitude for fake stars
+ STARS.DENSITY	 F32     100.0		# Stellar density (per square degree) at the brightest magnitude
+ STARS.SIGMA.LIM F32     5.0            # significance of faintest sources
+ STARS.LUM	 F32	 0.35		# Stellar luminosity function slope (magnitude slope)
+END
+
+# for a quick test, we are going to skip shutter and dark corrections
+STACKTEST.MAKE  METADATA
+ PSF.MODEL       STR     PS_MODEL_PGAUSS
+ SHUTTER.TIME	 F32	 0.0
+ DARK.RATE       F32     0.0         
+ SCATTER.FRAC    F32     0.0
+ BIAS            BOOL    FALSE
+ FLAT            BOOL    FALSE
+ BIAS.LEVEL	 F32	1000.0		# Bias level (e)
+ BIAS.RANGE	 F32	20.0		# Range of bias values (e)
+ BIAS.ORDER	 S32	7		# Order for overscan polynomial
+
+ # generate a set of fake stars
+ STARS.REAL	 BOOL	FALSE		# Add stars from a catalogue?
+ STARS.FAKE      BOOL   TRUE		# Add fake stars, randomly distributed?
+ MATCH.DENSITY   BOOL   TRUE            # significance of faintest sources
+
+ EXPTIME     	 F32    10.0
+ RA          	 F32    5.0
+ DEC         	 F32    5.0
+ PA          	 F32    0.0
+ SEEING      	 F32    1.0
+ SCALE       	 F32    0.25
+ ZEROPOINT   	 F32    25.0
+ SKY.MAGS    	 F32    22.0
+END
+
+# for a quick test, we are going to skip shutter and dark corrections
+STACKTEST.RUN  METADATA
  PSF.MODEL       STR     PS_MODEL_GAUSS
  SHUTTER.TIME	 F32	 0.0
@@ -8,7 +53,22 @@
  SCATTER.FRAC    F32     0.0
  BIAS            BOOL    FALSE
+ FLAT            BOOL    FALSE
  BIAS.LEVEL	 F32	1000.0		# Bias level (e)
  BIAS.RANGE	 F32	20.0		# Range of bias values (e)
  BIAS.ORDER	 S32	7		# Order for overscan polynomial
+
+ # generate a set of fake stars
+ STARS.REAL	 BOOL	TRUE		# Add stars from a catalogue?
+ STARS.FAKE      BOOL   FALSE		# Add fake stars, randomly distributed?
+ MATCH.DENSITY   BOOL   TRUE            # significance of faintest sources
+
+ EXPTIME     	 F32    10.0
+ RA          	 F32    5.0
+ DEC         	 F32    5.0
+ PA          	 F32    0.0
+ SEEING      	 F32    1.0
+ SCALE       	 F32    0.25
+ ZEROPOINT   	 F32    25.0
+ SKY.MAGS    	 F32    22.0
 END
 
Index: branches/eam_branches/20090820/ippconfig/simtest/psastro.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/simtest/psastro.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/simtest/psastro.config	(revision 25766)
@@ -3,5 +3,5 @@
 
 PSASTRO.GRID.OFFSET    F32    500.
-PSASTRO.GRID.SCALE     F32     50.
+PSASTRO.GRID.SCALE     F32     10.
 
 PSASTRO.IGNORE         STR    CRLIMIT,SATURATED,DEFECT,BLEND
@@ -9,5 +9,5 @@
 PSASTRO.CATDIR		STR	SYNTH.SIMTEST
 DVO.GETSTAR.PHOTCODE	STR	r
-PSASTRO.MAX.NSTAR	S32	50	# max stars accepted for fitting
+PSASTRO.MAX.NSTAR	S32	200	# max stars accepted for fitting
 DVO.GETSTAR.MAX.RHO     F32    10000.0
 DVO.GETSTAR.MIN.MAG     F32      10.0
@@ -34,2 +34,3 @@
   PHOTCODE STR z_SYNTH
 END
+
Index: branches/eam_branches/20090820/ippconfig/simtest/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/simtest/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/simtest/psphot.config	(revision 25766)
@@ -1,36 +1,4 @@
 
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.BACKGND	BOOL 	TRUE
-SAVE.BACKSUB	BOOL 	TRUE
-SAVE.PLOTS      BOOL    TRUE
-SAVE.RESID	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
-LOAD.PSF	BOOL 	FALSE
-
-IMSTATS_NPIX        S32  3000    	 # number of pixels to use for sky estimate boxes:
-SKY_INNER_RADIUS    F32    10            # square annulus for local sky measurement
-
-PSF_MOMENTS_RADIUS  F32    7               # calculate initial source moments with this radius
-
-#PSPHOT_TEST METADATA
-# SAVE.BACKSUB	BOOL 	FALSE
-# SAVE.RESID	BOOL 	TRUE
-#END
-#
-#PEAKS_OUTPUT_FILE   STR  peaks.dat
-#MOMENTS_OUTPUT_FILE STR  moments.dat
-
-#PSF_SN_LIM          F32  20.0            # minimum S/N for stars used for PSF model
-MOMENTS_SN_MIN      F32  10.0            # min S/N to measure moments
-FULL_FIT_SN_LIM     F32  100.0
-EXT_MIN_SN          F32  100.0           # fit galaxies above this S/N limit
-
-MOMENTS_SX_MAX                      F32   25.0
-MOMENTS_SY_MAX                      F32   25.0
-
-PEAKS_NSIGMA_LIMIT   F32  25.0 	 	 # peak significance threshold
-PEAKS_NSIGMA_LIMIT_2 F32  10.0 	   	 # peak significance threshold
-BREAK_POINT         STR  NONE            # limit total processing for now (for speed)
-
-
-SKY_STAT            STR  ROBUST_MEDIAN   # statistic used to measure background
+# same as ppSim.config (if YES, <apResid> should be 0.0)
+# ppSim currently uses PS_MODEL_GAUSS
+PSF_MODEL                           STR   PS_MODEL_PGAUSS
Index: branches/eam_branches/20090820/ippconfig/tek/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/tek/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/tek/psphot.config	(revision 25766)
@@ -1,57 +1,3 @@
-
-# turn these on to see specific outputs
-#SAVE.BACKMDL	BOOL 	TRUE
-#SAVE.BACKGND	BOOL 	TRUE
-#SAVE.BACKSUB	BOOL 	TRUE
-SAVE.RESID	BOOL 	TRUE
-#SAVE.PSF	BOOL 	TRUE
-
-# image statistics parameters
-IMSTATS_NPIX        S32  3000    	 # number of pixels to use for sky estimate boxes:
-
-PSF_SN_LIM          F32  10              # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
 
 PSF_MODEL         STR  PS_MODEL_QGAUSS
 
-MOMENTS_SN_MIN      F32   10.0
-#EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-#FULL_FIT_SN_LIM      F32  50.0
-#AP_MIN_SN            F32  20.0
-PSF_CLUMP_NSIGMA   F32  2.5             # region of Sx,Sy plane to use for selecting PSF stars
-
-# PSFTREND must be a 2D polynomial
-# the specified values are ignored but define the active components of the polynomial
-PSF.TREND.MASK  METADATA  
-   NORDER_X         S32       3                # number of x orders
-   NORDER_Y         S32       3                # number of y orders
-   VAL_X00_Y00      F64       1                # polynomial coefficient
-
-   VAL_X01_Y00      F64       1                # polynomial coefficient
-   VAL_X00_Y01      F64       1                # polynomial coefficient
-
-   VAL_X02_Y00      F64       1                # polynomial coefficient
-   VAL_X01_Y01      F64       1                # polynomial coefficient
-   VAL_X00_Y02      F64       1                # polynomial coefficient
-
-   VAL_X03_Y00      F64       1                # polynomial coefficient
-   VAL_X02_Y01      F64       1                # polynomial coefficient
-   VAL_X01_Y02      F64       1                # polynomial coefficient
-   VAL_X00_Y03      F64       1                # polynomial coefficient
-   NELEMENTS        S32       10               # number of unmasked components
-END  # folder for 4D polynomial
-
-XMIN F32 15
-PSF.RESIDUALS       BOOL false
-BREAK_POINT         STR  ENSEMBLE
-OUTPUT.FORMAT       STR  PS1_DEV_0
-
-PSPHOT.SUMMIT METADATA
- PEAKS_SMOOTH_SIGMA  F32  0.8 	   	 # peak significance threshold
- PEAKS_NSIGMA_LIMIT  F32  50.0 	   	 # peak significance threshold
- PEAKS_NMAX          S32  1000
- SAVE.RESID	BOOL 	FALSE
- PSF_SN_LIM          F32  25              # minimum S/N for stars used for PSF model
- MOMENTS_SN_MIN      F32   25.0
- PSF_MODEL         STR  PS_MODEL_PGAUSS
-END
Index: branches/eam_branches/20090820/ippconfig/ucam/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/ucam/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/ucam/psphot.config	(revision 25766)
@@ -1,27 +1,2 @@
 
-# turn these on to see specific outputs
-#SAVE.BACKMDL	BOOL 	TRUE
-#SAVE.BACKGND	BOOL 	TRUE
-#SAVE.BACKSUB	BOOL 	TRUE
-SAVE.RESID	BOOL 	TRUE
-#SAVE.PSF	BOOL 	TRUE
-#LOAD.PSF	BOOL 	FALSE
-
-IMSTATS_NPIX        S32  1000    	 # number of pixels to use for sky estimate boxes:
-
-PSF_SN_LIM          F32  100             # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
-
-# PSF model parameters : choose the PSF model
-# list as many PSF_MODEL options as desired
-# if you want to list multiple entries, uncomment 'MULTI' here
-# PSF_MODEL           MULTI
 PSF_MODEL           STR  PS_MODEL_QGAUSS
-# PSF_MODEL           STR  PS_MODEL_GAUSS
-# PSF_MODEL           STR  PS_MODEL_PGAUSS
-# PSF_MODEL           STR  PS_MODEL_TGAUSS  ## not well tested, not very successful
-
-MOMENTS_SN_MIN      F32  20.0           # min S/N to measure moments
-EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  50.0
-AP_MIN_SN            F32  25.0
Index: branches/eam_branches/20090820/ippconfig/uh8k/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/uh8k/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/uh8k/psphot.config	(revision 25766)
@@ -1,37 +1,5 @@
-
-# turn these on to see specific outputs
-SAVE.OUTPUT	BOOL 	TRUE
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.PSF	BOOL 	TRUE
-SAVE.PLOTS     	BOOL    TRUE
-
-BACKGROUND.XBIN	    S32  128            # size of background superpixels
-BACKGROUND.YBIN	    S32  128            # size of background superpixels
-
-# image background parameters
-IMSTATS_NPIX        S32  10000    	 # number of pixels to use for sky estimate boxes:
-SKY_STAT            STR  FITTED_MEAN_V4  # statistic used to measure background
-SKY_CLIP_SIGMA      F32  2.0             # statistic used to measure background
-
-PSF_SN_LIM          F32  100             # minimum S/N for stars used for PSF model
-PSF_MAX_NSTARS      S32  300             # limit number of stars used for PSF model
 
 # PSF model parameters : choose the PSF model desired
 PSF_MODEL           STR  PS_MODEL_QGAUSS
-
-MOMENTS_SN_MIN      F32   30.0
-EXT_MIN_SN           F32  50.0           # fit galaxies above this S/N limit
-FULL_FIT_SN_LIM      F32  50.0
-AP_MIN_SN            F32  50.0
-
-# OUTPUT.FORMAT       STR SMPDATA
-OUTPUT.FORMAT       STR PS1_DEV_1
-
-PSF_SHAPE_NSIGMA     F32  3.0		 # max significance for shape variation
-PSF_MAX_CHI          F32  50.0		 # reject objects worse that this
-
-#PSF.TREND.MODE STR MAP
-#PSF.TREND.NX   S32 1
-#PSF.TREND.NY   S32 1
 
 DIAGNOSTIC.PLOTS		METADATA
@@ -40,4 +8,2 @@
   IMAGE.BACKGROUND.CELL.HISTOGRAM.Y S32 12
 END
-
-USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
Index: branches/eam_branches/20090820/ippconfig/vysos5/psastro.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/vysos5/psastro.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/vysos5/psastro.config	(revision 25766)
@@ -26,4 +26,5 @@
 # PSASTRO.GRID.MAX.ANGLE F32 360.0
 # PSASTRO.GRID.DEL.ANGLE F32  1.0
+
 PSASTRO.GRID.MIN.ANGLE F32 -20.0 # start angle (degrees)
 PSASTRO.GRID.MAX.ANGLE F32 +20.0
@@ -70,4 +71,5 @@
 PSASTRO.CATDIR              STR      SYNTH.BRIGHT
 DVO.GETSTAR.PHOTCODE        STR      r
+DVO.GETSTAR.MAX.RHO         F32      1000.0
 
 PHOTCODE.DATA MULTI
@@ -93,2 +95,5 @@
 # DVO.GETSTAR.MAG.MAX         F32      20.0
 # XXX need to be able to limit the density!
+
+# XXX this does not really make sense -- a single chip model cannot be inconsistent in rotation with the model!
+PSASTRO.ANGLE.TOLERANCE       F32      10.0
Index: branches/eam_branches/20090820/ippconfig/vysos5/psphot.config
===================================================================
--- branches/eam_branches/20090820/ippconfig/vysos5/psphot.config	(revision 25206)
+++ branches/eam_branches/20090820/ippconfig/vysos5/psphot.config	(revision 25766)
@@ -1,31 +1,16 @@
 
-SAVE.BACKMDL	BOOL 	TRUE
-SAVE.BACKGND	BOOL 	FALSE
-SAVE.BACKSUB	BOOL 	FALSE
-SAVE.PLOTS      BOOL    TRUE
-SAVE.RESID	BOOL 	FALSE
-SAVE.PSF	BOOL 	TRUE
-LOAD.PSF	BOOL 	FALSE
+# XXX check on this value
+PSF_CLUMP_NSIGMA                    F32   3.5             # region of Sx,Sy plane to use for selecting PSF stars
 
-PEAKS_NSIGMA_LIMIT                  F32   20.0            # peak significance threshold
-PEAKS_NSIGMA_LIMIT_2                F32   10.0             # peak significance threshold
-PSF_MOMENTS_RADIUS  		    F32    7               # calculate initial source moments with this radius
-PSF_CLUMP_NSIGMA                    F32   3.5             # region of Sx,Sy plane to use for selecting PSF stars
-PSF_MAX_NSTARS                      S32   400             # limit number of stars used for PSF model
-MEASURE.APTREND	                    BOOL  TRUE
-
+# do we want to do 2-pass analysis?
 BREAK_POINT                         STR   PASS1     
 
+# keep these large since psfs are so undersampled
 PSPHOT.CR.NSIGMA.LIMIT              F32   5.0  # sources with crNsigma greater that this get tagged as likely cosmic rays
 PSPHOT.EXT.NSIGMA.LIMIT             F32   5.0  # sources with extNsigma greater that this get tagged as likely extended sources
 
-USE_FOOTPRINTS                      BOOL  TRUE       	  # use new pmFootprint peak packaging
-FOOTPRINT_NPIXMIN                   S32   5       	  # Minimum size of a pmFootprint
-FOOTPRINT_NSIGMA_LIMIT              F32   10      	  # threshold for bright pmFootprint detection
-FOOTPRINT_NSIGMA_LIMIT_2            F32   10       	  # threshold for faint pmFootprint detection
+# small psfs so small grow radius
 FOOTPRINT_GROW_RADIUS               S32   1       	  # How much to grow bright footprints
 FOOTPRINT_GROW_RADIUS_2             S32   2       	  # How much to grow faint footprints
-FOOTPRINT_CULL_NSIGMA_DELTA         F32   4       	  # Cull peaks that aren't nsigma above coll to neighbour
-FOOTPRINT_CULL_NSIGMA_MIN           F32   1       	  # Minimum height of colls in units of skyStdev
 
 PSF_MODEL                           STR   PS_MODEL_PGAUSS
Index: branches/eam_branches/20090820/magic/README
===================================================================
--- branches/eam_branches/20090820/magic/README	(revision 25206)
+++ 	(revision )
@@ -1,18 +1,0 @@
-To build the DetectStreaks portion of magic
-
-tar xf ~sydney/magic.tgz
-tar xf ~sydney/ssa-core-cpp.tgz
-
-cd ssa-core-cpp
-make distclean
-./configure
-make
-
-cd ../magic
-make install
-
-# to build streaksremove and related tools
-
-cd ../remove/src
-make install
-
Index: branches/eam_branches/20090820/magic/configure.tcsh
===================================================================
--- branches/eam_branches/20090820/magic/configure.tcsh	(revision 25206)
+++ branches/eam_branches/20090820/magic/configure.tcsh	(revision 25766)
@@ -34,5 +34,4 @@
   case --enable-profile
   case --pedantic
-   shift
    breaksw;
   # key/value options passed by build systems which we ignore
Index: branches/eam_branches/20090820/magic/remove/src/streaksio.c
===================================================================
--- branches/eam_branches/20090820/magic/remove/src/streaksio.c	(revision 25206)
+++ branches/eam_branches/20090820/magic/remove/src/streaksio.c	(revision 25766)
@@ -288,8 +288,8 @@
         sfile->resolved_name = psStringCopy(sfile->pmfile->filename);
 
+        sfile->nHDU = psFitsGetSize(sfile->pmfile->fits);
+
         // copy header from fpu
         sfile->header = (psMetadata*) psMemIncrRefCounter(sfile->pmfile->fpa->hdu->header);
-
-        sfile->nHDU = psFitsGetSize(sfile->pmfile->fits);
 
         return sfile;
@@ -654,4 +654,15 @@
             streaksExit("", PS_EXIT_DATA_ERROR);
         }
+
+        // Ensure input is of the expected type
+        psDataType expected = isMask ? PS_TYPE_IMAGE_MASK : PS_TYPE_F32; // Expected type for image
+        for (int i = 0; i < in->imagecube->n; i++) {
+            psImage *image = in->imagecube->data[i]; // Image of interest
+            if (image->type.type != expected) {
+                psImage *temp = psImageCopy(NULL, image, expected);
+                psFree(image);
+                in->imagecube->data[i] = temp;
+            }
+        }
     }
     setDataExtent(stage, in, (stage == IPP_STAGE_RAW) && !isMask);
@@ -670,4 +681,5 @@
     sfile->fits->options = psFitsOptionsAlloc();
     sfile->fits->options->scaling = PS_FITS_SCALE_MANUAL;
+    sfile->fits->options->fuzz = false;
     sfile->fits->options->bitpix = bitpix;
     sfile->fits->options->bscale = bscale;
@@ -1114,12 +1126,12 @@
                 // these gets are not necessary, we could just set the pixels to nan
                 // but I want to get the counts
-                double imageVal  = psImageGet(image, x, y);
+                double imageVal  = image->data.F32[y][x];
                 psU32 maskVal;
                 if (sfiles->stage == IPP_STAGE_RAW) {
                     unsigned int xChip, yChip;
                     cellToChipInt(&xChip, &yChip, sfiles->astrom, x, y);
-                    maskVal = psImageGet(mask, xChip, yChip);
+                    maskVal = mask->data.PS_TYPE_IMAGE_MASK_DATA[yChip][xChip];
                 } else {
-                    maskVal = psImageGet(mask, x, y);
+                    maskVal = mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x];
                 }
                 if (maskVal & maskMask) {
@@ -1127,11 +1139,11 @@
                     if (!isExciseValue(imageVal, sfiles->inImage->exciseValue)) {
                         ++nandPixels;
-                        psImageSet(image, x, y, exciseValue);
+                        image->data.F32[y][x] = exciseValue;
                     }
                     if (weight) {
-                        double weightVal = weight ? psImageGet(weight, x, y) : 0;
+                        double weightVal = weight ? weight->data.F32[y][x] : 0;
                         if (!isnan(weightVal)) {
                             ++nandWeights;
-                            psImageSet(weight, x, y, NAN);
+                            weight->data.F32[y][x] = NAN;
                         }
                     }
@@ -1212,13 +1224,10 @@
         if (SFILE_IS_IMAGE(in)) {
             // Turn off compression (code adapted from pmFPAWrite)
-#ifdef SAVE_AND_RESTORE_COMPRESSION
             int bitpix = out->fits->options ? out->fits->options->bitpix : 0; // Desired bits per pixel
             psFitsCompression *compress = psFitsCompressionGet(out->fits); // Current compression options
-#endif
             if (!psFitsSetCompression(out->fits, PS_FITS_COMPRESS_NONE, NULL, 0, 0, 0)) {
                 psError(PM_ERR_UNKNOWN, false, "failed to turn off compression for extension %d\n", extnum);
                 streaksExit("", PS_EXIT_UNKNOWN_ERROR);
             }
-#ifdef SAVE_AND_RESTORE_COMPRESSION
             if (out->fits->options) {
                 out->fits->options->bitpix = 0;
@@ -1235,5 +1244,4 @@
                 streaksExit("", PS_EXIT_UNKNOWN_ERROR);
             }
-#endif
         } else {
             copyTable(out, in, extnum);
Index: branches/eam_branches/20090820/magic/remove/src/streaksremove.c
===================================================================
--- branches/eam_branches/20090820/magic/remove/src/streaksremove.c	(revision 25206)
+++ branches/eam_branches/20090820/magic/remove/src/streaksremove.c	(revision 25766)
@@ -12,10 +12,11 @@
 static pmConfig *parseArguments(int argc, char **argv);
 static bool readAndCopyToOutput(streakFiles *sf, bool exciseAll);
-static void exciseNonWarpedPixels(streakFiles *sfiles, double newMaskValue);
+static void exciseNonWarpedPixels(streakFiles *sfiles, psImageMaskType newMaskValue);
 static bool warpedPixel(streakFiles *sfiles, int x, int y);
-static void excisePixel(streakFiles *sfiles, unsigned int x, unsigned int y, bool streak, double newMaskValue);
+static void excisePixel(streakFiles *sfiles, unsigned int x, unsigned int y, bool streak, psImageMaskType newMaskValue);
 static void writeImages(streakFiles *sf, bool exciseImageCube);
 static void updateAstrometry(streakFiles *sfiles);
-static void censorSources(streakFiles *sfiles, psU32 maskStreak);
+static void censorSources(streakFiles *sfiles, psImageMaskType maskStreak);
+static long censorPixels(streakFiles *sfiles, psImage * pixels, bool checkNonWarpedPixels, psU16 maskStreak);
 
 int
@@ -146,22 +147,7 @@
                 }
 
-
                 psTimerStart("REMOVE_STREAKS");
 
-                for (int y=0 ; y < sfiles->inImage->numRows; y++) {
-                    for (int x = 0; x < sfiles->inImage->numCols; x++) {
-                        if (psImageGet(pixels, x, y)) {
-                            ++totalStreakPixels;
-                            if (!checkNonWarpedPixels || warpedPixel(sfiles, x, y)) {
-
-                                excisePixel(sfiles, x, y, true, maskStreak);
-
-                            } else {
-                                // This pixel was not included in any warp and has thus already excised
-                                // by exciseNonWarpedPixels
-                            }
-                        }
-                    }
-                }
+                totalStreakPixels += censorPixels(sfiles, pixels, checkNonWarpedPixels, maskStreak);
 
                 psLogMsg("streaksremove", PS_LOG_INFO, "time to remove streak pixels: %f\n", psTimerClear("REMOVE_STREAKS"));
@@ -254,4 +240,27 @@
 
     return 0;
+}
+
+static long
+censorPixels(streakFiles *sfiles, psImage *pixels, bool checkNonWarpedPixels, psU16 maskStreak)
+{
+    long streakPixels = 0;
+
+    for (int y=0 ; y < sfiles->inImage->numRows; y++) {
+        for (int x = 0; x < sfiles->inImage->numCols; x++) {
+            if (psImageGet(pixels, x, y)) {
+                ++streakPixels;
+                if (!checkNonWarpedPixels || warpedPixel(sfiles, x, y)) {
+
+                    excisePixel(sfiles, x, y, true, maskStreak);
+
+                } else {
+                    // This pixel was not included in any warp and has thus already excised
+                    // by exciseNonWarpedPixels
+                }
+            }
+        }
+    }
+    return streakPixels;
 }
 
@@ -665,5 +674,5 @@
 
 static void
-excisePixel(streakFiles *sfiles, unsigned int x, unsigned int y, bool streak, double newMaskValue)
+excisePixel(streakFiles *sfiles, unsigned int x, unsigned int y, bool streak, psImageMaskType newMaskValue)
 {
     double exciseValue = sfiles->inImage->exciseValue;
@@ -674,17 +683,17 @@
     }
 
-    double imageValue  = psImageGet (sfiles->inImage->image,  x, y);
+    float imageValue  = sfiles->inImage->image->data.F32[y][x];
     if (sfiles->recImage && !isExciseValue(imageValue, sfiles->inImage->exciseValue) ) {
-        psImageSet (sfiles->recImage->image,  x, y, imageValue);
+        sfiles->recImage->image->data.F32[y][x] = imageValue;
     }
 
     if (sfiles->transparentStreaks == 0) {
-        psImageSet (sfiles->outImage->image,  x, y, exciseValue);
+        sfiles->outImage->image->data.F32[y][x] = exciseValue;
     } else {
         if (streak) {
             // as a visualization aid don't mask the pixel, just change the intensity
-            psImageSet (sfiles->outImage->image,  x, y, imageValue + sfiles->transparentStreaks);
+            sfiles->outImage->image->data.F32[y][x] = imageValue + sfiles->transparentStreaks;
         } else {
-            psImageSet (sfiles->outImage->image,  x, y, exciseValue);
+            sfiles->outImage->image->data.F32[y][x] = exciseValue;
         }
     }
@@ -692,21 +701,21 @@
     if (sfiles->outWeight) {
         if (sfiles->recWeight) {
-            double weightValue = psImageGet (sfiles->inWeight->image, x, y);
-            psImageSet (sfiles->recWeight->image, x, y, weightValue);
+            sfiles->recWeight->image->data.F32[y][x] = sfiles->inWeight->image->data.F32[y][x];
         }
         // Assume that weight images are always a floating point type
-        psImageSet (sfiles->outWeight->image, x, y, NAN);
+        sfiles->outWeight->image->data.F32[y][x] = NAN;
     }
     if (sfiles->outMask) {
         if (sfiles->recMask) {
-            double maskValue   = psImageGet (sfiles->inMask->image,   x, y);
-            psImageSet (sfiles->recMask->image,   x, y, maskValue);
-        }
-        psImageSet (sfiles->outMask->image,   x, y, newMaskValue);
+            sfiles->recMask->image->data.PS_TYPE_IMAGE_MASK_DATA[y][x] =
+                sfiles->inMask->image->data.PS_TYPE_IMAGE_MASK_DATA[y][x];
+        }
+        sfiles->outMask->image->data.PS_TYPE_IMAGE_MASK_DATA[y][x] =
+            sfiles->inMask->image->data.PS_TYPE_IMAGE_MASK_DATA[y][x] | newMaskValue;
     }
 }
 
 static void
-exciseNonWarpedPixels(streakFiles *sfiles, double newMaskValue)
+exciseNonWarpedPixels(streakFiles *sfiles, psImageMaskType newMaskValue)
 {
     int cell_x0 = sfiles->astrom->cell_x0;
@@ -784,5 +793,5 @@
 // streak mask
 static void
-censorSources(streakFiles *sfiles, psU32 maskStreak)
+censorSources(streakFiles *sfiles, psImageMaskType maskStreak)
 {
     if ((!sfiles->inSources) || (!sfiles->outMask)) {
@@ -855,5 +864,10 @@
             psF32 y = psMetadataLookupF32(NULL, row, "Y_PSF");
 
-            psU32 mask = psImageGet(maskImage, x, y);
+            psImageMaskType mask;
+            if ((x >= maskImage->numCols) || (y >= maskImage->numRows) || (x <  0) || (y < 0)) {
+                mask = maskStreak;
+            } else {
+                mask = maskImage->data.PS_TYPE_IMAGE_MASK_DATA[(int)y][(int)x];
+            }
 
             // Key the source if the center pixel is not masked with maskStreak
Index: branches/eam_branches/20090820/operations/detrend/.mana
===================================================================
--- branches/eam_branches/20090820/operations/detrend/.mana	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/.mana	(revision 25766)
@@ -0,0 +1,2 @@
+echo {600*4}
+echo {datan(1/4)}
Index: branches/eam_branches/20090820/operations/detrend/.pantasks
===================================================================
--- branches/eam_branches/20090820/operations/detrend/.pantasks	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/.pantasks	(revision 25766)
@@ -0,0 +1,659 @@
+status
+server input input
+setup
+load.hosts wave.2
+load.hosts.wave.2
+load.hosts.wave2
+load.hosts.wave3
+run
+status
+add.label darktest.beaumont.1
+status
+status
+status
+status
+status
+status
+list.labels
+show.labels
+del.label darktest.beaumont.1
+status
+shutdown now
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+run
+add.label beaumont.darktest.2
+status
+show.labels
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+shutdown now
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+run
+status
+add.label beaumont.darktest.2
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+show.label
+status
+status
+status
+del.label beaumont.darktest.2
+show.label
+ls
+show.label
+add.label dummy
+status
+show.label
+status
+status
+status
+add.label beaumont.darktest.3
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+shutdown now
+eixt
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+run
+status
+status
+status
+status
+shutdown now
+ls
+ls
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+run
+status
+status
+status
+status
+status
+shutdown now
+status
+server input input
+server setup
+setup
+load.hosts.wave2
+load.hosts.wave3
+run
+status
+status
+shutdown now
+status
+server input input
+setup
+load.hosts.wave2
+run
+status
+status
+status
+shutdown now
+input input
+setup
+load.hosts.wave2
+run
+status
+status
+status
+status
+status
+status
+server input input
+setup
+load.hosts.wave2
+run
+status
+status
+status
+shutdown now
+status
+server input input
+setup
+load.wave.2
+load.hosts.wave.2
+load.hosts.wave2
+load.hosts.wave3
+status
+status
+run
+status
+status
+shutdown now
+status
+status
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+run
+status
+status
+status
+status
+flatcorr.off
+status
+status
+status
+status
+status
+status
+status
+status
+stat
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+shutdown now
+status
+server input input
+setup
+status
+flatcorr.off
+status
+load.hosts.wave2
+load.hosts.wave3
+run
+status
+status
+status
+status
+status
+status
+status
+status
+control status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+shutdown now
+status
+server input input
+setup
+status
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+run
+status
+status
+status -tasks
+stop
+status
+status
+status -taskstatsreset
+status
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+statu
+status -tasks
+echo {60*2}
+stop
+echo {60*2}
+status -tasks
+status -tasks
+control status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+control status
+status
+status
+status
+control status
+status
+status
+status
+status
+status
+run
+status
+status
+status
+status
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+control status
+status
+stop
+status -taskstats
+run
+status
+status
+status
+status
+!dettool -revertstacked -dbname gpc1 -det_id 221
+status
+status
+status
+status
+status
+!dettool -revertresidimfile -dbname gpc1 -det_id 221
+status
+!dettool -revertstacked -dbname gpc1 -det_id 221
+status
+status -taskstats
+status
+!dettool -revertresidimfile -dbname gpc1 -det_id 221
+status
+!dettool -revertresidexp -dbname gpc1 -det_id 221
+!dettool -revertprocessedexp -dbname gpc1 -det_id 221
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -task
+status
+stop
+run
+status
+status
+status -taskstats
+status -taskstats
+status
+control status
+control host off ipp049
+control status
+server input input
+setup
+status
+load.hosts.wave2
+load.hosts.wave3
+run
+status
+status
+status
+status -tasks
+status
+status -tasks
+status
+shutdown now
+server input input
+setup
+status
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+status
+control status
+run
+status
+status -tasks
+!dettool -revertprocessedimfile -det_id 223 -dbname gpc1
+!dettool -revertprocessedexp -det_id 223 -dbname gpc1
+status
+control status
+status
+status
+control status
+control status
+control status
+status
+status -taskstats
+status -taskstats
+control status
+control status
+status
+status
+status
+status -taskstats
+!dettool -dbname gpc1 -revertresidimfile -det_id 223
+!dettool -dbname gpc1 -revertstacked -det_id 223
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+!dettool -dbname gpc1 -revertresidexp -det_id 223
+status
+shutdown now
+server input iput
+server input input
+setup
+status
+load.hosts.wave2
+load.hosts.compute
+status
+control status
+run
+control status
+control host off ipp026
+control status
+status
+status
+status
+control status
+control status
+status
+shutdown onw
+shutdown now
+server input input
+setup
+status
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+status
+run
+status
+status -tasks
+status -tasks
+control status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+!dettool -dbname gpc1 -revertprocessedimfile -det_id 224
+status -tasks
+status -tasks
+status -tasks
+!dettool -dbname gpc1 -revertprocessedimfile -det_id 224
+status -tasks
+!dettool -dbname gpc1 -revertprocessedexp -det_id 224
+status -tasks
+status -taskstats
+control status
+control status
+status -tasks
+status
+status -tasks
+status -tasks
+status -taskstats
+!dettool -dbname gpc1 -revertresidimfile -det_id 224
+status -tasks
+control status
+status -tasks
+!dettool -dbname gpc1 -revertresidimfile -det_id 224
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -taskstats
+status -tasks
+!dettool -dbname gpc1 -revertprocessedimfile -det_id 225
+!dettool -dbname gpc1 -revertprocessedexp -det_id 225
+status -task
+status -task
+status -task
+status -tasks
+!dettool -dbname gpc1 -revertprocessedexp -det_id 225
+!dettool -dbname gpc1 -revertstacked -det_id 225
+!dettool -dbname gpc1 -revertresidimfile -det_id 225
+status -tasks
+status
+status
+status
+stop
+shutdown now
+server input input
+setup
+status
+load.hosts.wave3
+load.hosts.wave2
+load.hosts.compute
+status
+run
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+echo {50*60}
+!dettool -dbname gpc1 -revertprocessedimfile -det_id 226
+!dettool -dbname gpc1 -revertprocessedexp -det_id 226
+status -tasks
+status -tasks
+!dettool -dbname gpc1 -revertprocessedimfile -det_id 226
+!dettool -dbname gpc1 -revertprocessedexp -det_id 226
+status
+!dettool -dbname gpc1 -revertprocessedexp -det_id 226
+!ls
+!ls -lrt
+status
+!dettool -dbname gpc1 -revertprocessedimfile -det_id 226
+!dettool -dbname gpc1 -revertstacked -det_id 226
+status
+status
+status
+status
+status
+status
+!dettool -dbname gpc1 -revertstacked -det_id 226
+status
+!dettool -dbname gpc1 -revertresidimfile -det_id 226
+status
+status
+status
+status
+status
+status
+!dettool -dbname gpc1 -revertstacked -det_id 226
+status
+status
+status
+status
+status -tasks
+status -tasks
+!dettool -dbname gpc1 -revertresidimfile -det_id 226
+status -task
+status -task
+!dettool -dbname gpc1 -revertnorm -det_id 226
+!dettool -dbname gpc1 -revertnormalizedimfile -det_id 226
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+show.label
+status
+status -tasks
+shutdown now
+status
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+show.labels
+shutdown now
Index: branches/eam_branches/20090820/operations/detrend/dark.20090712.sh
===================================================================
--- branches/eam_branches/20090820/operations/detrend/dark.20090712.sh	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/dark.20090712.sh	(revision 25766)
@@ -0,0 +1,18 @@
+#!/bin/csh -f
+
+# 20090712
+# attempting a dark analysis using a range of temperatures.  
+
+dettool -pretend -dbname gpc1 -definebyquery \
+  -det_type DARKTEST \
+  -workdir neb://@HOST@.0/gpc1/detrend.20090712 \
+  -inst GPC1 \
+  -select_ccd_temp_min -76 \
+  -select_pon_time_min 160000 \
+  -select_dateobs_begin 2009-04-01T00:00:00 \
+  -select_dateobs_end 2009-07-15T10:00:00 \
+  -select_exp_type dark \
+  -comment 'darks_%' \
+  -use_begin 2009-01-01 \
+  -random_subset \
+  -random_limit 41
Index: branches/eam_branches/20090820/operations/detrend/dark.20090713.sh
===================================================================
--- branches/eam_branches/20090820/operations/detrend/dark.20090713.sh	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/dark.20090713.sh	(revision 25766)
@@ -0,0 +1,18 @@
+#!/bin/csh -f
+
+# 20090713
+# attempting a dark analysis using a range of temperatures.  
+
+dettool -dbname gpc1 -definebyquery \
+  -det_type DARKTEST \
+  -workdir neb://@HOST@.0/gpc1/detrend.20090712 \
+  -inst GPC1 \
+  -select_ccd_temp_min -76 \
+  -select_pon_time_min 160000 \
+  -select_dateobs_begin 2009-04-01T00:00:00 \
+  -select_dateobs_end 2009-07-15T10:00:00 \
+  -select_exp_type dark \
+  -comment 'darks_%' \
+  -use_begin 2009-01-01T00:00:00 \
+  -random_subset \
+  -random_limit 60
Index: branches/eam_branches/20090820/operations/detrend/dark.20090714.sh
===================================================================
--- branches/eam_branches/20090820/operations/detrend/dark.20090714.sh	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/dark.20090714.sh	(revision 25766)
@@ -0,0 +1,19 @@
+#!/bin/csh -f
+
+# 20090714
+# attempting a dark analysis using a smaller range of temperatures.  
+
+dettool -dbname gpc1 -definebyquery \
+  -det_type DARKTEST \
+  -workdir neb://@HOST@.0/gpc1/detrend.20090712 \
+  -inst GPC1 \
+  -select_ccd_temp_min -60 \
+  -select_pon_time_min 160000 \
+  -select_dateobs_begin 2009-04-01T00:00:00 \
+  -select_dateobs_end 2009-07-15T10:00:00 \
+  -select_exp_type dark \
+  -comment 'darks_%' \
+  -use_begin 2009-01-01T00:00:00 \
+  -time_begin 2009-01-01T00:00:00 \
+  -random_subset \
+  -random_limit 60
Index: branches/eam_branches/20090820/operations/detrend/dark.20090716.sh
===================================================================
--- branches/eam_branches/20090820/operations/detrend/dark.20090716.sh	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/dark.20090716.sh	(revision 25766)
@@ -0,0 +1,22 @@
+#!/bin/csh -f
+
+# 20090716 : EAM : It turns out that the camera reports bogus DARKTIME
+# value occasionally.  I've changed gpc1/ppMerge.config to use the
+# EXPTIME instead, and initial test show that does a much better job.
+# Here I am re-attempting a dark analysis using the full range of
+# temperatures.
+
+dettool -dbname gpc1 -definebyquery \
+  -det_type DARKTEST \
+  -workdir neb://@HOST@.0/gpc1/detrend.20090716 \
+  -inst GPC1 \
+  -select_ccd_temp_min -75 \
+  -select_pon_time_min 160000 \
+  -select_dateobs_begin 2009-04-01T00:00:00 \
+  -select_dateobs_end 2009-07-15T10:00:00 \
+  -select_exp_type dark \
+  -comment 'darks_%' \
+  -use_begin 2009-01-01T00:00:00 \
+  -time_begin 2009-01-01T00:00:00 \
+  -random_subset \
+  -random_limit 60
Index: branches/eam_branches/20090820/operations/detrend/fringe.20090717.sh
===================================================================
--- branches/eam_branches/20090820/operations/detrend/fringe.20090717.sh	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/fringe.20090717.sh	(revision 25766)
@@ -0,0 +1,23 @@
+#!/bin/csh -f
+
+# 20090717 : EAM : Generate a fringe frame selecting y-band images with the sun down > 30 degrees
+
+dettool -simple -dbname gpc1 -definebyquery \
+  -det_type FRINGE \
+  -workdir neb://@HOST@.0/gpc1/detrend.20090717 \
+  -inst GPC1 \
+  -select_pon_time_min 200000 \
+  -select_dateobs_begin 2009-04-01T00:00:00 \
+  -select_dateobs_end 2009-07-15T10:00:00 \
+  -select_exp_type object \
+  -select_exp_time_min 200.0 \
+  -select_filter y.00000 \
+  -select_sun_alt_max -30 \
+  -filter y \
+  -select_exp_type object \
+  -comment 'MD%' \
+  -use_begin 2009-01-01T00:00:00 \
+  -time_begin 2009-01-01T00:00:00 \
+  -random_subset \
+  -random_limit 60
+
Index: branches/eam_branches/20090820/operations/detrend/fringe.20090722.sh
===================================================================
--- branches/eam_branches/20090820/operations/detrend/fringe.20090722.sh	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/fringe.20090722.sh	(revision 25766)
@@ -0,0 +1,25 @@
+#!/bin/csh -f
+
+echo "done"
+exit 1
+# 20090722 : EAM : Generate a fringe frame selecting y-band images with the sun down > 30 degrees and moon phase > 0.75
+
+dettool -simple -dbname gpc1 -definebyquery \
+  -det_type FRINGE \
+  -workdir neb://@HOST@.0/gpc1/detrend.20090717 \
+  -inst GPC1 \
+  -select_pon_time_min 200000 \
+  -select_dateobs_begin 2009-04-01T00:00:00 \
+  -select_dateobs_end 2009-07-22T10:00:00 \
+  -select_exp_type object \
+  -select_exp_time_min 25.0 \
+  -select_filter y.00000 \
+  -select_sun_alt_max -30 \
+  -select_sun_alt_max -30 \
+  -select_moon_phase_min 0.75 \
+  -comment 'ThreePi%' \
+  -filter y \
+  -use_begin 2009-01-01T00:00:00 \
+  -time_begin 2009-01-01T00:00:00 \
+  -random_subset \
+  -random_limit 50
Index: branches/eam_branches/20090820/operations/detrend/input
===================================================================
--- branches/eam_branches/20090820/operations/detrend/input	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/input	(revision 25766)
@@ -0,0 +1,133 @@
+
+macro setup
+  module pantasks.pro
+  detrend.modules
+
+  module site.mhpcc.pro
+
+  init.copy.mhpcc on
+  queueload tmp -x "cat $MODULES:0/ipphosts.mhpcc.config"
+  ipptool2book tmp ipphosts -key camera
+
+  # XXX merge the above into init.site more cleanly (careful with summit copy stuff)
+  # init.site (we do not use init.site because it loads the hosts)
+
+  add.database gpc1
+  set.poll 100
+end
+
+macro set.poll
+  if ($0 != 2)
+    echo "USAGE:set.poll (value)"
+    break
+  end
+ 
+  $POLLLIMIT = $1
+end
+
+macro get.poll
+  echo "poll limit: $POLLLIMIT"
+end
+
+macro load.hosts.wave1
+  controller host add ipp005 -threads 4
+  controller host add ipp006 -threads 4
+# controller host add ipp007 -threads 4 (respawning?)
+# controller host add ipp008 -threads 4 (flaky)
+  controller host add ipp009 -threads 4
+  controller host add ipp010 -threads 4
+  controller host add ipp011 -threads 4
+  controller host add ipp012 -threads 4
+  controller host add ipp013 -threads 4
+# controller host add ipp014 -threads 4
+# controller host add ipp016 -threads 4 (flaky)
+  controller host add ipp017 -threads 4
+# controller host add ipp018 -threads 4 (flaky)
+# controller host add ipp019 -threads 4 (nebulous)
+  controller host add ipp020 -threads 4
+  controller host add ipp021 -threads 4
+end
+
+macro load.hosts.wave2
+  controller host add ipp015 -threads 4
+  controller host add ipp017 -threads 4
+  controller host add ipp023 -threads 4
+  controller host add ipp024 -threads 4
+  controller host add ipp026 -threads 4
+  controller host add ipp027 -threads 4
+  controller host add ipp028 -threads 4
+  controller host add ipp029 -threads 4
+  controller host add ipp030 -threads 4
+  controller host add ipp031 -threads 4
+  controller host add ipp032 -threads 4
+  controller host add ipp033 -threads 4
+  controller host add ipp034 -threads 4
+  controller host add ipp035 -threads 4
+  controller host add ipp036 -threads 4
+end
+
+macro load.hosts.wave3
+  controller host add ipp038 -threads 4
+  controller host add ipp039 -threads 4
+  controller host add ipp040 -threads 4
+  controller host add ipp041 -threads 4
+  controller host add ipp042 -threads 4
+  controller host add ipp043 -threads 4
+  controller host add ipp044 -threads 4
+  controller host add ipp045 -threads 4
+  controller host add ipp046 -threads 4
+  controller host add ipp047 -threads 4
+  controller host add ipp048 -threads 4
+  controller host add ipp049 -threads 4
+  controller host add ipp050 -threads 4
+  controller host add ipp051 -threads 4
+  controller host add ipp052 -threads 4
+  controller host add ipp053 -threads 4
+end
+
+macro load.hosts.compute
+  controller host add ippc00 -threads 4
+  controller host add ippc01 -threads 4
+  controller host add ippc02 -threads 4
+  controller host add ippc03 -threads 4
+  controller host add ippc04 -threads 4
+  controller host add ippc05 -threads 4
+  controller host add ippc06 -threads 4
+# controller host add ippc07 -threads 4 (pantasks - register)
+  controller host add ippc08 -threads 4
+  controller host add ippc09 -threads 4
+# controller host add ippc10 -threads 4 (pantasks - stdscience)
+  controller host add ippc11 -threads 4
+  controller host add ippc12 -threads 4
+  controller host add ippc13 -threads 4
+  controller host add ippc14 -threads 4
+  controller host add ippc15 -threads 4
+  controller host add ippc16 -threads 4
+  controller host add ippc17 -threads 4
+  controller host add ippc18 -threads 4
+  controller host add ippc19 -threads 4
+end
+
+macro show.book
+  if ($0 != 2)
+   echo "USAGE: show.book (book)"
+   break
+  end
+
+  book npages $1 -var npages
+  for i 0 $npages
+    book getpage $1 $i -var pagename
+    book listpage $1 $pagename
+  end
+
+  echo "npages: $npages"
+end
+
+macro del.page.from.book
+  if ($0 != 3)
+   echo "USAGE: show.book (book) (page)"
+   break
+  end
+
+  book delpage $1 $2
+end
Index: branches/eam_branches/20090820/operations/detrend/ptolemy.rc
===================================================================
--- branches/eam_branches/20090820/operations/detrend/ptolemy.rc	(revision 25766)
+++ branches/eam_branches/20090820/operations/detrend/ptolemy.rc	(revision 25766)
@@ -0,0 +1,5 @@
+
+PANTASKS_SERVER_STDOUT  pantasks.stdout.log
+PANTASKS_SERVER_STDERR  pantasks.stderr.log
+PANTASKS_SERVER         ippc06
+PASSWORD                foobar
Index: branches/eam_branches/20090820/operations/distribution/.pantasks
===================================================================
--- branches/eam_branches/20090820/operations/distribution/.pantasks	(revision 25766)
+++ branches/eam_branches/20090820/operations/distribution/.pantasks	(revision 25766)
@@ -0,0 +1,843 @@
+server input input
+status
+run
+status
+status -tasks
+status
+status -tas
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status -tasks
+halt
+run
+stop
+status
+run
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status
+status -tasks
+dist.status
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+show.labels
+del.label MD06.200904.v1
+add.label MD09.200906.v1
+add.label MD09.200907.v1
+del.label MD07.200904.v1
+del.label MD08.200904.v1
+del.label MD08.200905.v1
+del.label MD08.200904.v1
+show.labels
+del.label MD06.200905.v1
+del.label MD07.200905.v1
+status -tasks
+status
+controller status
+status
+status -tasks
+dist.status
+show.labels
+status -tasks
+status -tasks
+status
+status
+status
+status
+show.labels
+add.label MD06.200904.v1
+add.label MD06.200905.v1
+add.label MD07.200904.v1
+add.label MD07.200905.v1
+add.label MD08.200905.v1
+add.label MD08.200904.v1
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+statusquit
+status
+statua -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+controller status
+status -taskstats
+status -tasks
+status
+status
+dist.status
+show.labels
+add.label MD08.200906.v1
+status
+status
+status
+status -tasks
+status
+status
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status -tasks
+halt
+status -tasks
+controller status
+controller host off ipp053
+controller host off ipp053
+controller host delete ipp053
+controller host delete ipp053
+controller status
+run
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status
+status
+controller status
+controller status
+dist.status
+dist.status
+stop
+status
+status
+run
+status
+status
+status
+dist.off
+status
+status
+status
+controller tatus
+controller status
+run
+status
+status
+status
+status
+status
+status
+status
+status
+dist.status
+dist.reset
+run
+status
+status
+status
+status
+dist.on
+status
+status
+status
+status
+status
+controller status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+controller status
+controller status
+status -tasks
+status
+controller status
+stop
+status
+shutdown now
+server input input
+setup
+run
+status
+status
+show.labels
+add.label MD06.200906.v1
+add.label MD07.200906.v1
+add.label MD08.200906.v1
+add.label MD09.200906.v1
+add.label MD09.200907.v1
+status -tasks
+status
+controller status
+status -tasks
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status
+status
+status
+status
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+shutdown now
+server input input
+dist.off
+status
+status
+run
+status
+status
+status
+show.labels
+show.labels
+status
+status -tastks
+status -takss
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+halt
+server module dist.pro
+shutdown now
+server input input
+server input input
+del.label MD08.200904.v1
+del.label MD08.200905.v1
+del.label MD08.200906.v1
+add.label ThreePi_SouthernRegion.090724
+status
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+halt
+module rcserver.pro
+status
+server module rcserver.pro
+status
+dist.off
+status
+run
+status
+status
+halt
+status
+run
+status
+status
+status
+run
+status
+status
+dist.on
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status -taskstats
+controller status
+status -tasks
+halt
+run
+status
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -takss
+status -tasks
+status -tasks
+status -tasks
+status
+dist.off
+status
+status
+status
+status
+status
+status
+status
+status
+status
+dist.on
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status
+controller status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status
+status -taskstats
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+controller status
+status -tasks
+dist.off
+status
+status -tasks
+status -tasks
+status -tasks
+stop
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+run
+status
+run
+status
+dist.on
+status
+status
+status
+dist.off
+status
+status
+status
+dist.on
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+controller status
+status
+stop
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+stop
+status -tasks
+status
+!pgrep pclient | wc
+shutdown now
+status
+server input input
+shutdown now
+server input input
+shutdown now
+server input input
+status
+run
+run
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+halt
+server module rcserver.pro
+status
+status
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status
+add.label MD09.200906.v1
+status
+status -tasks
+status -tasks
+status -tasks
+status
+show.labels
+add.label MD09.200907.v1
+show.labels
+status
+status
+!hostname
+status
+shutdown now
+server input input
+status
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks ; !date
+status -tasks ; !date
+status -tasks ; !date
+show.labels
+show.labels
+show.labels
+status -tasks ; !date
+status -tasks ; !date
+status -tasks
+server module rcserver
+server module rcserver.pro
+status
+status
+status
+status
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status
+status -tasks
+status
+status -tasks
+!hostname
+status -tasks
+stattus
+status
+status
+status -tasks
+status -tasks
+si 0
+status
+status -tasks
+status -tasks
+status -tasks
+halt
+status
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+controller status;
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status
+add.label ThreePi_SouthernRegion.090724
+status
+status
+status
+status
+status
+controller status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status t-asks
+show.labels
+show.labels
+status -takss
+status -tasks
+halt
+run
+stop
+shutdown now
+server input input
+run
+status
+status
+status -tasks
+status
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+stop
+run
+status
+status
+status -taskststats
+status -taskstats
+server input /data/ipp004.0/home/bills/bump
+status
+status
+status
+status
+status
+status
+status
+status
+status -taskstats
+status -taskstats
+status
+status
+status
+status
+stop
+server module rcserver.pro
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+controller status
+controller status
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -taskstats
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status -taskstats
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+controller status
+show.labels
+stop
+status
+status
+status
+ex
+status
+status
+status
+status
+status
+halt
+runt
+run
+status
+status
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+dist.off
+rcserver.off
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+shutdown now
Index: branches/eam_branches/20090820/operations/distribution/input
===================================================================
--- branches/eam_branches/20090820/operations/distribution/input	(revision 25766)
+++ branches/eam_branches/20090820/operations/distribution/input	(revision 25766)
@@ -0,0 +1,71 @@
+module pantasks.pro
+
+module site.mhpcc.pro
+init.copy.mhpcc on
+queueload tmp -x "cat $MODULES:0/ipphosts.mhpcc.config"
+ipptool2book tmp ipphosts -key camera
+
+module dist.pro
+
+#module rcserver.pro
+
+add.database gpc1
+
+macro add.hosts
+    controller host add ipp021 -threads 4
+    controller host add ipp024 -threads 4
+    controller host add ipp026 -threads 4
+    controller host add ipp028 -threads 4
+    controller host add ipp029 -threads 4
+    controller host add ipp030 -threads 4
+    controller host add ipp031 -threads 4
+    controller host add ipp032 -threads 4
+    controller host add ipp033 -threads 4
+    controller host add ipp034 -threads 4
+    controller host add ipp035 -threads 4
+    controller host add ipp036 -threads 4
+    controller host add ipp038
+    controller host add ipp039
+    controller host add ipp040
+    controller host add ipp041
+    controller host add ipp042
+    controller host add ipp043
+    controller host add ipp044
+    controller host add ipp045
+    controller host add ipp046
+    controller host add ipp047
+    controller host add ipp048
+    controller host add ipp049
+    controller host add ipp050
+    controller host add ipp051
+    controller host add ipp052
+    controller host add ipp053
+end
+
+macro skycell.hosts
+    controller host add ipp024
+    controller host add ipp013
+    controller host add ipp026
+    controller host add ipp028
+    controller host add ipp029
+    controller host add ipp030
+    controller host add ipp031
+    controller host add ipp032
+    controller host add ipp033
+    controller host add ipp034
+    controller host add ipp035
+    controller host add ipp036
+end
+
+skycell.hosts
+#add.hosts
+
+#add.label MD08.200904.v1
+#add.label MD08.200905.v1
+#add.label MD08.200906.v1
+#add.label ThreePi_SouthernRegion.090724
+add.label STS.090724
+
+echo labels:
+show.labels
+
Index: branches/eam_branches/20090820/operations/distribution/ptolemy.rc
===================================================================
--- branches/eam_branches/20090820/operations/distribution/ptolemy.rc	(revision 25766)
+++ branches/eam_branches/20090820/operations/distribution/ptolemy.rc	(revision 25766)
@@ -0,0 +1,5 @@
+
+PANTASKS_SERVER_STDOUT  pantasks.stdout.log
+PANTASKS_SERVER_STDERR  pantasks.stderr.log
+PANTASKS_SERVER         ippc02
+PASSWORD                foobar
Index: branches/eam_branches/20090820/operations/home/.alias
===================================================================
--- branches/eam_branches/20090820/operations/home/.alias	(revision 25766)
+++ branches/eam_branches/20090820/operations/home/.alias	(revision 25766)
@@ -0,0 +1,27 @@
+### Aliases
+
+alias	.	pwd
+#alias	..	cd ..
+alias	-	cd -
+alias	/	cd /
+alias	more	less
+alias	h	"history | tail"
+alias	ff	'find . -name \!* -print'
+# alias   fg      'find . -name \!#:1 -exec grep -H \!#:2 {} \;'
+alias	df	df -k
+alias	ls	ls -F --color=auto
+alias   ll      ls -l
+alias	quota	quota -v
+alias	mv	mv -i
+alias	cp	cp -i
+alias	purge	'rm -f #*# *~ '
+alias	iraf	"xgterm -sb -sl 400 -bg white -fg black -geometry 80x24+10+30 -title IRAF -fn -adobe-courier-bold-r-normal--14-140-75-75-m-90-iso8859-1 -e /home/mithrandir/price/iraf/runiraf & "
+#alias	loads	'rup maestro majestic magus msokcf misfit mizar mork mindy marbles miniskirt magellan mistress | sort -k 8 -n'
+alias	rsync	rsync -e ssh
+alias	text2ps	'a2ps --columns=1 -L 70 -o \!#:2 \!#:1'
+alias	ds9	ds9 -zscale
+alias	make	make -j4
+alias	grep	grep --colour
+alias	cvs	cvs -q
+alias	lte	libtool --mode=execute
+alias	mmi	'make && make install'
Index: branches/eam_branches/20090820/operations/home/.bindkey
===================================================================
--- branches/eam_branches/20090820/operations/home/.bindkey	(revision 25766)
+++ branches/eam_branches/20090820/operations/home/.bindkey	(revision 25766)
@@ -0,0 +1,131 @@
+#bindkey -k up		history-search-backward		# Up
+#bindkey -k down		history-search-forward		# Down
+bindkey '\e[1~'		beginning-of-line		# Home
+#bindkey '\e[2~'	dabbrev-expand			# Insert
+bindkey '\e[2~'		overwrite-mode			# Insert
+bindkey '\e[3~'		delete-char			# Del
+bindkey '\e[4~'		end-of-line			# End
+bindkey '\e[5~'		history-search-backward		# Page up: search history backwards for line
+#bindkey '\e[5~'	complete-word-back		# page up
+bindkey '\e[6~'		history-search-forward		# Page down: search history forwards for line
+#bindkey '\e[6~'	complete-word-fwd		# page down
+bindkey '\e[20~'	complete-word-fwd		# F9
+bindkey '\e[21~'	complete-word-back		# F10
+bindkey ^[[3D		backward-word			# Alt-left arrow
+bindkey ^[[3C		forward-word			# Alt-right arrow
+bindkey -b M-\b		backward-delete-word		# Meta-backspace
+
+bindkey -b M-s		i-search-fwd
+bindkey -b M-r		i-search-back
+bindkey -b M-$		expand-variables
+#bindkey '\244'		expand-variables		# M-$ notation seems to be broken
+bindkey -b M-*		expand-glob
+bindkey -b M-8		expand-glob
+#bindkey '\e8'		expand-glob
+bindkey -b M-4		expand-variables
+#bindkey '\e4'		expand-variables
+bindkey -b M-_		insert-last-word
+bindkey ' '		magic-space
+
+bindkey -b M-b		backward-word
+bindkey -b M-c		capitalize-word
+bindkey -b M-d		delete-word
+bindkey -b M-f		forward-word
+bindkey -b M-h		run-help
+bindkey -b M-l		downcase-word
+bindkey -b M-n		history-search-forward
+bindkey -b M-p		history-search-backward
+bindkey -b M-r		toggle-literal-history
+bindkey -b M-u		upcase-word
+bindkey -b M-w		copy-region-as-kill
+bindkey -b M-y		yank				# Yank cut text
+bindkey -b C-space	set-mark-command		# Ctrl-space: mark text
+
+### Don't work, or I don't know what they do.
+#bindkey '\e[7~'	beginning-of-line		# rxvt home
+#bindkey '\e[8~'	end-of-line			# rxvt end
+#bindkey '\e[\304'	backward-word			# rxvt M-left
+#bindkey '\e[\303'	forward-word			# rxvt M-right
+#bindkey '\e[\301'	beginning-of-line		# rxvt M-up
+#bindkey '\e[\302'	end-of-line			# rxvt M-down
+#bindkey '\eOd'		backward-word			# rxvt C-left
+#bindkey '\eOc'		forward-word			# rxvt C-right
+#bindkey '\eOa'		upcase-word			# rxvt C-up
+#bindkey '\eOb'		downcase-word			# rxvt C-down
+#bindkey '\e[3\376'	delete-word		# rxvt M-delete
+
+
+### ESC-left-arrow : go to beginning of left word.
+### The second version is used to fix a strange bug where the binding
+### stops working after some usage. Did not manage to recreate.
+#bindkey    ^[^[[D vi-word-back
+#bindkey    \x{4420}vi-word-back
+
+### ESC-right-arrow : go to beginning of right word.
+### The second version is used to fix a strange bug where the binding
+### stops working after some usage. Did not manage to recreate.
+#bindkey    ^[^[[C vi-word-fwd
+#bindkey    \x{4320}vi-word-fwd
+
+### F1 : help on command currently typed(if 'ls passwd', help on 'ls').
+### first: while in console mode, second: while in X
+#bindkey    ^[[[A   run-help
+#bindkey    \x{5020}   run-help
+
+### F2 : set the mark command to cursor position.
+### first: while in console mode, second: while in X
+#bindkey  ^[[[B    set-mark-command
+#bindkey  \x{5120}    set-mark-command
+
+### F3 : move cursor to the marked position.
+### first: while in console mode, second: while in X
+#bindkey   ^[[[C   exchange-point-and-mark
+#bindkey   \x{5220}   exchange-point-and-mark
+
+### F4 : --empty--
+### first: while in console mode, second: while in X
+#bindkey   ^[[[D   undefined-key
+#bindkey   \x{5320}  undefined-key
+
+### F5 : check line for spelling and make changes.
+### first: while in console mode, second: while in X
+#bindkey    ^[[[E   spell-line
+#bindkey    [15~   spell-line
+
+### F6 : check current word for spelling and make changes.
+### same in both console and X modes
+#bindkey    ^[[17~  spell-word
+
+### F7 : insert last item of previous command.
+#bindkey    ^[[18~  insert-last-word
+
+### F8 : search in history backwards for line beginning as current.
+#bindkey   ^[[19~  history-search-backward
+
+### F9 : clear screen.
+### You may be in the middle of a command when you use this.
+### Does not affect what you are writing at the moment.
+#bindkey    ^[[20~  clear-screen
+
+### F10 : do an 'ls -l'.    (\16 is Ctrl-U on Linux(and Sun?))
+#bindkey -s ^[[21~  "\16ls -l\n"
+
+### F11 : display load average and current process status.
+#bindkey    ^[[23~  "/usr/bin/uptime ; ps"
+
+### F12 : do a ala-csh completion.
+#bindkey    ^[[24~  complete-word-raw
+
+### Thanks to Carlos Duarte <cgd@teleweb.pt>
+### Eazy edit of path, type Ctrl-X p
+bindkey -s '^Xp'        '. `echo $path`^X*)^A^Dset path = ( '
+
+### Ctrl-X *   Expand glob. example: ls *<^X*>  will expand the line
+bindkey -s ^[[21~  "\16ls -l\n"
+
+### F11 : display load average and current process status.
+#bindkey    ^[[23~  "/usr/bin/uptime ; ps"
+
+### F12 : do a ala-csh completion.
+#bindkey    ^[[24~  complete-word-raw
+
Index: branches/eam_branches/20090820/operations/home/.complete
===================================================================
--- branches/eam_branches/20090820/operations/home/.complete	(revision 25766)
+++ branches/eam_branches/20090820/operations/home/.complete	(revision 25766)
@@ -0,0 +1,507 @@
+### From Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
+    # updates by John Gotts <jgotts@engin.umich.edu>
+    # these from Tom Warzeka <tom@waz.cc>
+
+
+
+### This allows you to type "slogin price@", hit TAB and get a list of options
+set userhosts = (price@mithrandir.ifa.hawaii.edu price@hubble.ifa.hawaii.edu dph8pap@stargate.dur.ac.uk )
+set hostnames = `cat $HOME/.ssh/known_hosts | cut -f 1 -d ' ' | cut -f 1 -d ,` >& /dev/null
+set hosts = ( $userhosts $hostnames )
+
+#complete ssh		'p/*/$hosts/'
+complete ssh    	'p/1/$hosts/' 'c/-/(l n)/'   'n/-l/u/' 'N/-l/c/' 'n/-/c/' 'p/2/c/' 'p/*/f/'
+#complete slogin	'p/*/$hosts/'
+complete slogin		'p/1/$hosts/' 'c/-/(l 8 e)/' 'n/-l/u/'
+#complete scp		'p/1/f/' 'p/*/$hosts/:/'
+### This one will rsh to the file to fetch the list of files!
+complete scp		'p/1/f/' 'c%*@*:%`set filesonhost=$:-0;set filesonhost="$filesonhost:s/@/ /";set filesonhost="$filesonhost:s/:/ /";set filesonhost=($filesonhost " ");ssh $filesonhost[2] -l $filesonhost[1] ls -dp $filesonhost[3]\*`%' 'c%*:%`set filesonhost=$:-0;set filesonhost="$filesonhost:s/:/ /";set filesonhost=($filesonhost " ");ssh $filesonhost[1] ls -dp $filesonhost[2]\*`%' 'c%*@%$hosts%:' 'C@[./$~]*@f@'  'n/*/$hosts/:/'
+
+complete finger		'c/*@/$hosts/' 'n/*/u/@'
+complete ping		'p/1/$hosts/'
+complete traceroute	'p/1/$hosts/'
+ 
+complete ftp		'c/-/(d i g n v)/' 'n/-/$hosts/' 'p/1/$hosts/' 'n/*/n/'
+
+### Directory completion
+complete {c,push,p}d 'p/1/d/'
+
+### Common commands
+complete man		'p/*/c/'
+complete which		'p/*/c/'    
+complete where		'p/*/c/'
+complete printenv	'n/*/e/'
+complete setenv		'p/1/e/' 'c/*:/f/'
+complete set		'c/*=/f/' 'p/1/s/=' 'n/=/f/'
+complete unset		'n/*/s/'
+complete unalias	'n/*/a/'
+complete limit		'c/-/(h)/' 'n/*/l/'
+complete unlimit	'c/-/(h)/' 'n/*/l/'
+complete su		'c/--/(login fast preserve-environment command shell \
+				help version)/' 'c/-/(f l m p c s -)/' \
+			'n/{-c,--command}/c/' \
+			'n@{-s,--shell}@`cat /etc/shells`@' 'n/*/u/'
+
+complete grep		'c/-*A/x:<#_lines_after>/' 'c/-*B/x:<#_lines_before>/' \
+			'c/--/(extended-regexp fixed-regexp basic-regexp \
+			      regexp file ignore-case word-regexp line-regexp \
+			      no-messages revert-match version help byte-offset \
+			      line-number with-filename no-filename quiet silent \
+			      text directories recursive files-without-match \
+			      files-with-matches count before-context after-context \
+			      context binary unix-byte-offsets)/' \
+			'c/-/(A a B b C c d E e F f G H h i L l n q r s U u V \
+			     v w x)/' \
+			'p/1/x:<limited_regular_expression>/' 'N/-*e/f/' \
+			'n/-*e/x:<limited_regular_expression>/' 'n/-*f/f/' 'n/*/f/'
+
+complete egrep		'c/-*A/x:<#_lines_after>/' 'c/-*B/x:<#_lines_before>/' \
+			'c/--/(extended-regexp fixed-regexp basic-regexp \
+			      regexp file ignore-case word-regexp line-regexp \
+			      no-messages revert-match version help byte-offset \
+			      line-number with-filename no-filename quiet silent \
+			      text directories recursive files-without-match \
+			      files-with-matches count before-context after-context \
+			      context binary unix-byte-offsets)/' \
+			'c/-/(A a B b C c d E e F f G H h i L l n q r s U u V \
+			     v w x)/' \
+			'p/1/x:<full_regular_expression>/' 'N/-*e/f/' \
+			'n/-*e/x:<full_regular_expression>/' 'n/-*f/f/' 'n/*/f/'
+
+complete fgrep		'c/-*A/x:<#_lines_after>/' 'c/-*B/x:<#_lines_before>/' \
+			'c/--/(extended-regexp fixed-regexp basic-regexp \
+			      regexp file ignore-case word-regexp line-regexp \
+			      no-messages revert-match version help byte-offset \
+			      line-number with-filename no-filename quiet silent \
+			      text directories recursive files-without-match \
+			      files-with-matches count before-context after-context \
+			      context binary unix-byte-offsets)/' \
+			'c/-/(A a B b C c d E e F f G H h i L l n q r s U u V \
+			     v w x)/' \
+			'p/1/x:<fixed_string>/' 'N/-*e/f/' \
+			'n/-*e/x:<fixed_string>/' 'n/-*f/f/' 'n/*/f/'
+ 
+complete sed		'c/--/(quiet silent version help expression file)/'   \
+			'c/-/(n V e f -)/' 'n/{-e,--expression}/x:<script>/'  \
+			'n/{-f,--file}/f:*.sed/' 'N/-{e,f,-{file,expression}}/f/' \
+			'n/-/x:<script>/' 'N/-/f/' 'p/1/x:<script>/' 'p/2/f/'
+ 
+complete who		'c/--/(heading idle count mesg message writable help \
+			      version)/' 'c/-/(H i m q s T w u -)/' \
+			'p/1/x:<accounting_file>/' 'n/am/(i)/' 'n/are/(you)/'
+ 
+complete chown		'c/--/(changes dereference no-dereference silent \
+			      quiet reference recursive verbose help version)/' \
+			'c/-/(c f h R v -)/' 'C@[./$~]@f@' 'c/*[.:]/g/' \
+			'n/-/u/' 'p/1/u/' 'n/*/f/'
+
+complete chgrp		'c/--/(changes no-dereference silent quiet reference \
+			      recursive verbose help version)/' \
+			'c/-/(c f h R v -)/' 'n/-/g/' 'p/1/g/' 'n/*/f/'
+
+complete chmod		'c/--/(changes silent quiet verbose reference \
+			      recursive help version)/' 'c/-/(c f R v)/'
+
+complete df		'c/--/(all block-size human-readable si inodes \
+			      kilobytes local megabytes no-sync portability sync \
+			      type print-type exclude-type help version)/' \
+			'c/-/(a H h i k l m P T t v x)/'
+
+complete du		'c/--/(all block-size bytes total dereference-args \
+			      human-readable si kilobytes count-links dereference \
+			      megabytes separate-dirs summarize one-file-system \
+			      exclude-from exclude max-depth help version"/' \
+			'c/-/(a b c D H h k L l m S s X x)/'
+
+complete cat		'c/--/(number-nonblank number squeeze-blank show-all \
+			      show-nonprinting show-ends show-tabs help version)/' \
+			'c/-/(A b E e n s T t u v -)/' 'n/*/f/'
+
+complete mv		'c/--/(backup force interactive update verbose suffix \
+			      version-control help version)/' \
+			'c/-/(b f i S u V v -)/' \
+			'n/{-S,--suffix}/x:<suffix>/' \
+			'n/{-V,--version-control}/(t numbered nil existing \
+				never simple)/' 'n/-/f/' 'N/-/d/' 'n/*/f/'
+
+complete cp		'c/--/(archive backup no-dereference force \
+			      interactive link preserve parents sparse recursive \
+			      symbolic-link suffix update verbose version-control \
+			      one-file-system help version)/' \
+			'c/-/(a b d f i l P p R r S s u V v x -)/' \
+			'n/-*r/d/' 'n/{-S,--suffix}/x:<suffix>/' \
+			'n/{-V,--version-control}/(t numbered nil existing \
+			never simple)/' 'n/-/f/' 'N/-/d/' 'p/1/f/' 'p/2/d/' 'n/*/f/'
+
+complete ln		'c/--/(backup directory force no-dereference \
+			      interactive symbolic suffix verbose version-control \
+			      help version)/' \
+			'c/-/(b d F f i n S s V v -)/' \
+			'n/{-S,--suffix}/x:<suffix>/' \
+			'n/{-V,--version-control}/(t numbered nil existing \
+			never simple)/' 'n/-/f/' 'N/-/x:<link_name>/' \
+			'p/1/f/' 'p/2/x:<link_name>/'
+
+complete touch		'c/--/(date reference time help version)/' \
+			'c/-/(a c d f m r t -)/' \
+			'n/{-d,--date}/x:<date_string>/' \
+			'c/--time/(access atime mtime modify use)/' \
+			'n/{-r,--file}/f/' 'n/-t/x:<time_stamp>/' 'n/*/f/'
+
+complete mkdir		'c/--/(mode parents verbose help version)/' \
+			'c/-/(p m -)/' \
+			'n/{-m,--mode}/x:<mode>/' 'n/*/d/'
+
+complete rmdir		'c/--/(ignore-fail-on-non-empty parents verbose help \
+			      version)/' 'c/-/(p -)/' 'n/*/d/'
+
+
+### File handling
+complete rm		'c/--/(directory force interactive verbose \
+                        recursive help version)/' 'c/-/(d f i v r R -)/' \
+                        'n/*/f:^*.{c,cc,C,h,in}/' # Protect precious files
+
+complete find		'n/-fstype/(nfs 4.2)/' 'n/-name/f/' \
+			'n/-type/(c b d f p l s)/' 'n/-user/u/' 'n/-group/g/' \
+			'n/-exec/c/' 'n/-ok/c/' 'n/-cpio/f/' 'n/-ncpio/f/' 'n/-newer/f/' \
+			'c/-/(fstype name perm prune type user nouser \
+			      group nogroup size inum atime mtime ctime exec \
+			      ok print ls cpio ncpio newer xdev depth \
+			      daystart follow maxdepth mindepth noleaf version \
+			      anewer cnewer amin cmin mmin true false uid gid \
+			      ilname iname ipath iregex links lname empty path \
+			      regex used xtype fprint fprint0 fprintf \
+			      print0 printf not a and o or)/' \
+			'n/*/d/'
+
+complete tar		'c/-[Acru]*/(b B C f F g G h i l L M N o P \
+			            R S T v V w W X z Z)/' \
+			'c/-[dtx]*/( B C f F g G i k K m M O p P \
+				    R s S T v w x X z Z)/' \
+			'p/1/(A c d r t u x -A -c -d -r -t -u -x \
+			     --catenate --concatenate --create --diff --compare \
+			     --delete --append --list --update --extract --get \
+			     --help --version)/' \
+			'c/--/(catenate concatenate create diff compare \
+			      delete append list update extract get atime-preserve \
+			      block-size read-full-blocks directory checkpoint file \
+			      force-local info-script new-volume-script incremental \
+			      listed-incremental dereference ignore-zeros \
+			      ignore-failed-read keep-old-files starting-file \
+			      one-file-system tape-length modification-time \
+			      multi-volume after-date newer old-archive portability \
+			      to-stdout same-permissions preserve-permissions \
+			      absolute-paths preserve record-number remove-files \
+			      same-order preserve-order same-owner sparse \
+			      files-from null totals verbose label version \
+			      interactive confirmation verify exclude exclude-from \
+			      compress uncompress gzip ungzip use-compress-program \
+			      block-compress help version)/' \
+			'c/-/(b B C f F g G h i k K l L m M N o O p P R s S \
+			     T v V w W X z Z 0 1 2 3 4 5 6 7 -)/' \
+			'C@[/dev]@f@' \
+			'n/-c*f/x:<new_tar_file, device_file, or "-">/' \
+			'n/{-[Adrtux]*f,--file}/f:*.{tar,taz,tgz,tar.gz,tar.bz2}/' \
+#			'N/{-x*f,--file}/'`tar -tf $:-1`'/' \
+			'n/--use-compress-program/c/' \
+			'n/{-b,--block-size}/x:<block_size>/' \
+			'n/{-V,--label}/x:<volume_label>/' \
+			'n/{-N,--{after-date,newer}}/x:<date>/' \
+			'n/{-L,--tape-length}/x:<tape_length_in_kB>/' \
+			'n/{-C,--directory}/d/' \
+#			'N/{-C,--directory}/'`\ls $:-1`'/' \
+			'n/-[0-7]/(l m h)/'
+
+complete zcat		'c/--/(force help license quiet version)/' \
+			'c/-/(f h L q V -)/' 'n/*/f:*.{gz,Z,z,zip}/'
+
+complete gzip		'c/--/(stdout to-stdout decompress uncompress \
+			      force help list license no-name quiet recurse \
+			      suffix test verbose version fast best)/' \
+			      'c/-/(c d f h l L n q r S t v V 1 2 3 4 5 6 7 8 9 -)/' \
+			'n/{-S,--suffix}/x:<file_name_suffix>/' \
+			'n/{-d,--{de,un}compress}/f:*.{gz,Z,z,zip,taz,tgz}/' \
+			'N/{-d,--{de,un}compress}/f:*.{gz,Z,z,zip,taz,tgz}/' \
+			'n/*/f:^*.{gz,Z,z,zip,taz,tgz}/'
+
+complete {gunzip,ungzip}	'c/--/(stdout to-stdout force help list license \
+				no-name quiet recurse suffix test verbose version)/' \
+				'c/-/(c f h l L n q r S t v V -)/' \
+				'n/{-S,--suffix}/x:<file_name_suffix>/' \
+				'n/*/f:*.{gz,Z,z,zip,taz,tgz}/'
+
+complete unzip		'p/*/f:*.zip/'
+complete bunzip2	'p/*/f:*.bz2/'
+complete bzip2		'n/-9/f:^*.bz2/' 'n/-d/f:*.bz2/'
+complete compress	'c/-/(c f v b)/' 'n/-b/x:<max_bits>/' 'n/*/f:^*.Z/'
+complete uncompress	'c/-/(c f v)/' 'n/*/f:*.Z/'
+complete uuencode	'p/1/f/' 'p/2/x:<decode_pathname>/' 'n/*/n/'
+complete uudecode	'c/-/(f)/' 'n/-f/f:*.{uu,UU}/' 'p/1/f:*.{uu,UU}/' 'n/*/n/'
+complete gpg		'n/{--encrypt,--encrypt-files,--decrypt,--decrypt-files}/f/' \
+			'c/--/(sign clearsign detach-sign encrypt encrypt-files \
+			       store decrypt decrypt-files verify list-keys list-sigs \
+			       check-sigs fingerprint gen-key delete-keys sign-key \
+			       edit-key gen-revoke export send-keys recv-keys \
+			       search-keys import dearmor enarmor armor recipient \
+			       verbose quiet interactive keyring show-keyring \
+			       keyserver)/' \
+			'c/-/(-)//'
+
+
+### Documents
+complete xdvi		'c/-/(allowshell debug display expert gamma hushchars \
+			      hushchecksums hushspecials install interpreter keep \
+			      margins nogrey noinstall nomakepk noscan paper safer \
+			      shrinkbuttonn thorough topmargin underlink version)/' \
+			'n/-paper/(a4 a4r a5 a5r)/' 'p/*/f:*.dvi/'
+
+complete dvi{ps,pdf}	'n/*/f:*.dvi/'
+complete tex		'n/*/f:*.tex/'
+complete latex		'n/*/f:*.tex/'
+complete ghostview	'p/*/f:*.ps/'
+complete gv		'p/*/f:*.{ps,eps,ps.gz,eps.gz,pdf}/'
+complete ggv		'n/*/f:*.{ps,eps,ps.gz,eps.gz,pdf}/'
+complete xpdf 		'c/-/(z g remote raise quit cmap rgb papercolor       \
+                               eucjp t1lib freetype ps paperw paperh level1    \
+                               upw fullscreen cmd q v h help)/'                \
+                         'n/-z/x:<zoom (-5 .. +5) or "page" or "width">/'      \
+                         'n/-g/x:<geometry>/' 'n/-remote/x:<name>/'            \
+                         'n/-rgb/x:<number>/' 'n/-papercolor/x:<color>/'       \
+                         'n/-{t1lib,freetype}/x:<font_type>/'                  \
+                         'n/-ps/x:<PS_file>/' 'n/-paperw/x:<width>/'           \
+                         'n/-paperh/x:<height>/' 'n/-upw/x:<password>/'        \
+                         'n/-/f:*.{pdf,PDF}/'                                  \
+                         'N/-{z,g,remote,rgb,papercolor,t1lib,freetype,ps,paperw,paperh,upw}/f:*.{pdf,PDF}/' \
+                         'N/-/x:<page>/' 'p/1/f:*.{pdf,PDF}/' 'p/2/x:<page>/'
+
+complete gs		'c/-sDEVICE=/(x11 cdjmono cdj550 epson eps9high epsonc \
+				      dfaxhigh dfaxlow laserjet ljet4 sparc pbm \
+				      pbmraw pgm pgmraw ppm ppmraw bit)/' \
+			'c/-sOutputFile=/f/' 'c/-s/(DEVICE OutputFile)/=' \
+			'c/-d/(NODISPLAY NOPLATFONTS NOPAUSE)/' 'n/*/f/'
+
+ 
+
+### Editing
+complete {vi,vim}	'n/*/f:^*.[oa]/'
+complete xfig		'c/-/(display)/' 'p/*/f:*.fig/'
+### Emacs
+set _emacs_ver=`emacs --version | sed -e 's%GNU Emacs %%' -e q | cut -d . -f1-2`
+set _emacs_dir=`which emacs | sed s%/bin/emacs%%`
+complete emacs		'c/--/(batch terminal display no-windows no-init-file \
+			      user debug-init unibyte multibyte version help \
+			      no-site-file funcall load eval insert kill)/' \
+			'c/-/(t d nw q u f l -)/' 'c/+/x:<line_number>/' \
+			'n/{-t,--terminal}/x:<terminal>/' 'n/{-d,--display}/x:<display>/' \
+			'n/{-u,--user}/u/' 'n/{-f,--funcall}/x:<lisp_function>/' \
+			'n@{-l,--load}@F:$_emacs_dir/share/emacs/$_emacs_ver/lisp@' \
+			'n/--eval/x:<expression>/' 'n/--insert/f/' 'n/*/f:^*[\#~]/'
+unset _emacs_ver _emacs_dir
+
+
+### Programming
+complete ./configure	'c/--*=/f/' 'c/--{cache-file,prefix,exec-prefix,\
+					  bindir,sbindir,libexecdir,datadir,\
+					  sysconfdir,sharedstatedir,localstatedir,\
+					  libdir,includedir,oldincludedir,infodir,\
+					  mandir,srcdir}/(=)//' \
+			'c/--/(cache-file verbose prefix exec-prefix bindir \
+			       sbindir libexecdir datadir sysconfdir \
+			       sharedstatedir localstatedir libdir \
+			       includedir oldincludedir infodir mandir \
+			       srcdir)//'
+
+complete ./autogen.sh	'c/--*=/f/' 'c/--{cache-file,prefix,exec-prefix,\
+					  bindir,sbindir,libexecdir,datadir,\
+					  sysconfdir,sharedstatedir,localstatedir,\
+					  libdir,includedir,oldincludedir,infodir,\
+					  mandir,srcdir}/(=)//' \
+			'c/--/(cache-file verbose prefix exec-prefix bindir \
+			       sbindir libexecdir datadir sysconfdir \
+			       sharedstatedir localstatedir libdir \
+			       includedir oldincludedir infodir mandir \
+			       srcdir)//'
+
+complete gcc		'c/-[IL]/d/' \
+                        'c/-f/(caller-saves cse-follow-jumps delayed-branch \
+			       elide-constructors expensive-optimizations \
+			       float-store force-addr force-mem inline \
+			       inline-functions keep-inline-functions \
+			       memoize-lookups no-default-inline \
+			       no-defer-pop no-function-cse omit-frame-pointer \
+			       rerun-cse-after-loop schedule-insns \
+			       schedule-insns2 strength-reduce \
+			       thread-jumps unroll-all-loops \
+			       unroll-loops syntax-only all-virtual \
+			       cond-mismatch dollars-in-identifiers \
+			       enum-int-equiv no-asm no-builtin \
+			       no-strict-prototype signed-bitfields \
+			       signed-char this-is-variable unsigned-bitfields \
+			       unsigned-char writable-strings call-saved-reg \
+			       call-used-reg fixed-reg no-common \
+			       no-gnu-binutils nonnull-objects \
+			       pcc-struct-return pic PIC shared-data \
+			       short-enums short-double volatile)/' \
+                        'c/-W/(all aggregate-return cast-align cast-qual \
+			       comment conversion enum-clash error format \
+			       id-clash-len implicit missing-prototypes \
+			       no-parentheses pointer-arith return-type shadow \
+			       strict-prototypes switch uninitialized unused \
+			       write-strings)/' \
+                        'c/-m/(68000 68020 68881 bitfield fpa nobitfield rtd \
+			       short c68000 c68020 soft-float g gnu unix fpu \
+			       no-epilogue)/' \
+                        'c/-d/(D M N)/' \
+                        'c/-/(f W vspec v vpath ansi traditional \
+			      traditional-cpp trigraphs pedantic x o l c g L \
+			      I D U O O2 C E H B b V M MD MM i dynamic \
+			      nodtdlib static nostdinc undef)/' \
+                        'c/-l/f:*.a/' \
+                        'n/*/f:*.{c,C,cc,o,a,s,i}/'
+
+complete objdump	'c/--/(adjust-vma= all-headers architecture= \
+			       archive-headers debugging demangle disassemble \
+			       disassemble-all disassemble-zeroes dynamic-reloc \
+			       dynamic-syms endian= file-headers full-contents \
+			       headers help info line-numbers no-show-raw-insn \
+			       prefix-addresses private-headers reloc section-headers \
+			       section=source stabs start-address= stop-address= \
+			       syms target= version wide)/' \
+			'c/-/(a h i f C d D p r R t T x s S l w)/'
+
+complete ar		'c/[dmpqrtx]/(c l o u v a b i)/' 'p/1/(d m p q r t x)//' \
+			'p/2/f:*.a/' 'p/*/f:*.o/'
+ 
+complete make		'n/-f/f/' 'c/*=/f/' \
+			'n@*@`cat -s GNUmakefile Makefile makefile |& sed -n -e "/No such file/d" -e "/^[^     #].*:/s/:.*//p"`@'
+
+complete g++		'n/*/f:*.{C,cc,o,s,i}/'
+complete gdb		'p/2/f:core*/' 'n/-d/d/' 'n/*/c/'
+
+
+
+### Jobs
+complete -%*		'c/%/j/'
+complete kill		'c/-/S/' 'c/%/j/' 'p/*/`ps -u $USER -opid=`/'
+complete {fg,bg,stop}	'c/%/j/' 'p/1/(%)//'
+complete ps		'c/-t/x:<tty>/' 'c/-/(a c C e g k l S t u v w x)/' \
+			'n/-k/x:<kernel>/' 'N/-k/x:<core_file>/' 'n/-u/u/' 'n/*/x:<PID>/'
+
+
+### System
+complete xhost		'c/[+-]/$hosts/' 'n/*/$hosts/'
+complete xmodmap	'c/-/(display help grammar verbose quiet n e pm pk pke pp)/'
+complete netstat	'n@-I@`ifconfig -l`@'
+complete ifconfig	'p@1@`ifconfig -l`@' 'n/*/(range phase link netmask \
+						   mtu vlandev vlan metric \
+						   mediaopt down delete \
+						   broadcast arp debug)/'
+
+complete mixer		'p/1/(vol bass treble synth pcm speaker mic cd mix \
+			      pcm2 rec igain ogain line1 line2 line3)/' \
+			      p@2@'`mixer $:-1 | awk \{\ print\ $7\ \}`'@
+
+complete mount		'c/-/(a r t v)/' 'n/-t/(4.2 nfs)/' \
+			'n@*@''`grep -v "^#" /etc/fstab | tr -s " " "     " | cut -f 2`''@'
+complete umount		'c/-/(a h t v)/' 'n/-t/(4.2 nfs)/' \
+			'n/-h/''`df | cut -s -d ":" -f 1 | sort -u`''/' \
+			'n/*/''`mount | cut -d " " -f 3`''/'
+
+ 
+### Mail
+### Set _maildir to Post Office: /var/spool/mail or /usr/mail
+set _maildir = /var/spool/mail
+if (-r $HOME/.mailrc) then
+	complete mail	'c/-/(e i f n s u v)/' 'c/*@/$hosts/' \
+			'c@+@F:$HOME/Mail@' 'C@[./$~]@f@' 'n/-s/x:<subject>/' \
+			'n@-u@T:$_maildir@' 'n/-f/f/' \
+			'n@*@`sed -n s/alias//p $HOME/.mailrc | tr -s " " " " | cut -f 2`@'
+else
+	complete mail	'c/-/(e i f n s u v)/' 'c/*@/$hosts/' \
+			'c@+@F:$HOME/Mail@' 'C@[./$~]@f@' 'n/-s/x:<subject>/' \
+			'n@-u@T:$_maildir@' 'n/-f/f/' 'n/*/u/'
+endif
+unset  _maildir
+
+
+### Printing
+if ( -f /etc/printcap ) then
+	set _printers=(`sed -n -e "/^[^     #].*:/s/:.*//p" /etc/printcap`)
+	complete lpr		'c/-P/$printers/'
+	complete lpq		'c/-P/$printers/'
+	complete lprm		'c/-P/$printers/'
+	complete lpquota	'p/1/(-Qprlogger)/' 'c/-P/$printers/'
+	complete dvips		'c/-P/$printers/' 'n/-o/f:*.{ps,PS}/' 'n/*/f:*.dvi/'
+	complete dvilj		'p/*/f:*.dvi/'
+	unset _printers
+endif
+
+ 
+### Other applications
+complete perl		'n/-S/c/'
+complete cvs		'c/--/(help help-commands help-synonyms)/' \
+			'p/1/(add admin annotate checkout commit diff \
+			      edit editors export history import init log login \
+			      logout rdiff release remove rtag status tag unedit \
+			      update watch watchers)/' 'n/-a/(edit unedit commit \
+			      all none)/' 'n/watch/(on off add remove)/'
+
+complete links		'c/-/(assume-codepage async-dns download-dir \
+			      format-cache-size ftp-proxy help http-proxy \
+			      max-connections max-connections-to-host \
+			      memory-cache-size receive-timeout retries \
+			      unrestartable-receive-timeout version \
+			      source dump)/'
+
+complete wget		'c/--/(accept= append-output= background cache= \
+			      continue convert-links cut-dirs= debug \
+			      delete-after directory-prefix= domains= \
+			      dont-remove-listing dot-style= exclude-directories= \
+			      exclude-domains= execute= follow-ftp \
+			      force-directories force-html glob= header= help \
+			      http-passwd= http-user= ignore-length \
+			      include-directories= input-file= level= mirror \
+			      no-clobber no-directories no-host-directories \
+			      no-host-lookup no-parent non-verbose \
+			      output-document= output-file= passive-ftp \
+			      proxy-passwd= proxy-user= proxy= quiet quota= \
+			      recursive reject= relative retr-symlinks save-headers \
+			      server-response span-hosts spider timeout= \
+			      timestamping tries= user-agent= verbose version wait=)/' 
+
+complete mpg123		'c/--/(2to1 4to1 8bit aggressive au audiodevice \
+			       auth buffer cdr check doublespeed equalizer frames \
+			       gain halfspeed headphones left lineout list mix mono \
+			       proxy quiet random rate reopen resync right scale \
+			       shuffle single0 single1 skip speaker stdout stereo \
+			       test verbose wav)/' 'p/*/f:*.{mp2,mp3}/'
+
+complete ds9		'c/-/(2mass about bin blink blue catalog cmap contour crosshair datacube dss \
+				exit quit fits sfits frame geometry green grid height help histequ \
+				iconify invert linear lock log lower match medatacube minmax mode \
+				mosaicimage mosaicimagenext mosaic smosaic nameserver orient \
+				pagesetup pan pixeltable plot pow prefs preserve print private raise \
+				regions red rgb rgbarray rgbcube srgbcube rgbimage rotate saveimage \
+				savefits savempg scale shm single smooth squared sqrt source tile \
+				title url version view visual vo wcs web width xpa zmax zscale zoom)/' \
+			'n/-2mass/(name coord survey size)/' \
+			'N/-2mass/x:<object name, ra dec coordinates, survey (j|h|k) or size (arcsec)>/' \
+			'n/-analysis,-fits,-sfits,-mosaicimage,-mosaicimagenext,-mosaic,-medatacube,\
+				-rgbcube,-srgbcube,-rgbimage,-savefits,-savempeg,-source/f/' \
+			'N/-sfits,-srgbcube,-smosaic/f/' \
+			'n/-datacube/(play stop next prev first last)/' \
+			'n/-dss/(name coord size server survey)/' \
+			'N/-dss/x:<object name, coordinates, size, server (sao|stsci|eso) or survey>/' \
+			'n/-frame/(center clear new delete reset refresh hide show first next prev last)/' \
+			'n/-mode/(none pointer crosshair colorbar pan zoom rotate catalog examine)/' \
+			'n/-orient/(none x y xy)/' \
+			'n/-pixeltable/(yes no)/' \
+			'n/-preserve/(scale pan regions)/' 'N/-preserve/(yes no)/' \
+			'n/-regions/(load save move select delete format system sky skyformat strip wcs \
+				shape color width)/' \
+			'N/-regions/x:<Check the manual for the great variety of values>/' \
+			'n/-rgb/(red green blue channel view system lock)/' \
+			'n/-scale/(linear log pow sqrt squared histequ)/' \
+			'n/-smooth/(yes no function radius)/' \
+			'n/-tile/(yes no grid row column)/'
+
Index: branches/eam_branches/20090820/operations/home/.ptolemyrc
===================================================================
--- branches/eam_branches/20090820/operations/home/.ptolemyrc	(revision 25766)
+++ branches/eam_branches/20090820/operations/home/.ptolemyrc	(revision 25766)
@@ -0,0 +1,34 @@
+
+CONFDIR                 /home/panstarrs/ipp/psconfig/share/ippconfig
+CAMERA                  default
+
+# location of DVO database tables
+CATDIR			default
+
+# location of possible data sources
+2MASS_DIR_AS		NONE
+2MASS_DIR_DR2		NONE
+GSCDIR			NONE
+USNO_A_DIR		NONE
+USNO_B_DIR		NONE
+TYCHO_DIR		NONE
+
+PHOTCODE_FILE		$CONFDIR/dvo.photcodes
+GSCFILE			$CONFDIR/GSCregions.tbl
+CATMODE			MEF
+CATFORMAT		ELIXIR
+SKY_DEPTH
+# SKY_TABLE		this may be used to override GSCFILE
+ZERO_PT			25.0
+
+# access control for client/server addstar mode 
+PANTASKS_SERVER         alala
+PASSWORD                foobar
+
+# access control for client/server addstar mode 
+# PASSWORD
+# HOSTNAME
+# VALID_IP
+
+# load the camera-specific configuration files
+input                   $CONFDIR/$CAMERA/dvo.config
Index: branches/eam_branches/20090820/operations/home/.tcshrc
===================================================================
--- branches/eam_branches/20090820/operations/home/.tcshrc	(revision 25766)
+++ branches/eam_branches/20090820/operations/home/.tcshrc	(revision 25766)
@@ -0,0 +1,181 @@
+### .tcshrc
+### Paul A. Price, with help from many various sources.
+### Revised for use by Pan-STARRS IPP
+### 20 Feb 2009
+
+
+################################################################################
+#                                   Aliases                                    #
+################################################################################
+
+if ( -f ~/.alias ) source ~/.alias
+
+################################################################################
+#                           Environment variables                              #
+################################################################################
+
+### File creation mask
+### 022 --> u:rwx   g:r-x   o:r-x
+#umask 002
+
+### Program to use to edit text files
+setenv EDITOR vi
+### Program to use to display text files
+setenv PAGER less
+### C compiler
+setenv CC gcc
+### Default printer
+#setenv PRINTER duplaser
+
+### DS9 / xpans ( http://hea-www.harvard.edu/RD/xpa/ )
+setenv  XPA_METHOD local
+alias   shifttab  'xmodmap -e "keysym ISO_Left_Tab = Tab"'
+alias   ds9frame  'xpaset -p ds9 frame \!*'
+alias   ds9hide 'xpaset -p ds9 frame hide \!*'
+alias   ds9show 'xpaset -p ds9 frame show \!*'
+
+### Nebulous server
+setenv NEB_SERVER http://nebulous.mhpcc.ipp.ifa.hawaii.edu:80/nebulous
+
+#echo "Environment"
+
+###############################################################################
+#                         Pan-STARRS IPP psconfig                             #
+###############################################################################
+
+setenv PSCONFIG_MAKEOPTS -j4
+if (-e $HOME/psconfig/psconfig.csh) then
+    alias psconfig "source $HOME/psconfig/psconfig.csh"
+else
+    alias psconfig "echo psconfig not available"
+endif
+psconfig ipp-svn
+
+###############################################################################
+#                             Multiple Operating Systems                      #
+###############################################################################
+
+set OS = `/bin/sh -c '(/bin/uname||/usr/bin/uname) 2>/dev/null'`
+if (`expr $OS = SunOS`) then
+        if ( -d /usr/sbin ) then
+                set OS = solaris
+        endif
+endif
+
+if (`expr $OS = solaris`) then
+    # Solaris doesn't do colour, for some reason
+    alias ls ls -F
+    unalias more
+    setenv PATH ${PATH}:/usr/ccs/bin/
+endif
+
+if (`expr $OS = Darwin`) then
+    # Darwin doesn't do colour, for some reason
+    alias ls ls -F
+    # Fink puts stuff under /sw/bin
+    setenv PATH ${PATH}:/sw/bin/
+endif
+
+###############################################################################
+#                            Interactive sessions                             #
+###############################################################################
+
+if ($?prompt) then
+
+	### How to display result from the "time" command
+        set time=(10 "\
+        Time spent in user mode   (CPU seconds) : %Us\
+        Time spent in kernel mode (CPU seconds) : %Ss\
+        Total time                              : %Es\
+        CPU utilisation (percentage)            : %P")
+#        Times the process was swapped           : %W\
+#        Times of major page faults              : %F\
+#        Times of minor page faults              : %R")
+	### Immediately notify of background job changes
+	set notify
+	### Command history
+	set history=1000
+	set savehist=1000
+	### Don't allow ctrl-d to kill session
+	#set ignoreeof
+	### Prompt: "price@marauder:/home/price>"
+	set promptchars = ">#"
+	set prompt = "%n@%m:%/%#"
+	### Don't log out automatically
+	unset autologout
+	### Don't beep on command-line completion, only if nothing found
+	#set nobeep
+	set matchbeep = "nomatch"
+	### Only list files the second time TAB is pushed.
+	set autolist="ambiguous"
+	### Different characters for different types of symbolic links
+	set listlinks
+	### Quick filename completion
+	#set complete="enhance"
+	### No spell-checking of command line.
+	unset correct
+	### Check mail every 3 minutes
+	#set mail=(180 /var/mail/${USER})
+	### Ignore files ending in .o and tilde for filename completion.
+	set fignore = (.o \~)
+	### Colour directories
+	set color
+	### Be careful about deleting everything
+	set rmstar
+	### Stating a directory name is the same as changing to it (but let me know)
+	set implicitcd = "verbose"
+	### Don't allow output redirection to destroy files
+	set noclobber
+	### Use the history of commands to aid expansion.
+	set autoexpand
+	### After a 'Ctrl-Z', it lists all the jobs.
+	set listjobs=long
+	### Limit on core dump size
+	limit coredumpsize 0k
+
+	### Change the window title of X terminals
+        if (`expr $OS != solaris` && `expr $OS != Darwin`) then
+ 	    if ( $?TERM ) then
+		switch ( $TERM )
+		    case xterm*:
+		    case rxvt:
+		    case eterm:
+			alias cwdcmd 'echo -n "\033]0;${USER}@${HOST}: $cwd\007"'
+			breaksw
+		    case screen:
+			alias cwdcmd 'echo -n "\033_${USER}@${HOST}: $cwd\033\\"'
+			breaksw
+		    default:
+			alias cwdcmd 'echo "Directory: $cwd"'
+			breaksw
+		    endsw
+		cd .
+	    endif
+	endif
+	### Done with changing window title
+
+endif
+
+
+#echo "Setups"
+
+
+###############################################################################
+#                             Key bindings                                    #
+###############################################################################
+
+if (`expr $OS != solaris`) then
+    if ( -f ~/.bindkey ) source ~/.bindkey
+endif
+
+#echo "Bindkey"
+
+###############################################################################
+#                             Completions                                     #
+###############################################################################
+
+if ( -f ~/.complete ) source ~/.complete
+
+
+#echo "Complete"
+
Index: branches/eam_branches/20090820/operations/ippconfig/site.config
===================================================================
--- branches/eam_branches/20090820/operations/ippconfig/site.config	(revision 25206)
+++ branches/eam_branches/20090820/operations/ippconfig/site.config	(revision 25766)
@@ -9,5 +9,4 @@
 # List of tessellations, and their DVO CATDIR
 TESSELLATIONS	METADATA
-	FIXNS   STR     path://GPC1/scitest.200807/FIXNS/
 END
 
@@ -25,8 +24,8 @@
 
 # nebulous server
-NEB_SERVER	STR	http://ipp004:80/nebulous	# Nebulous server
+NEB_SERVER	STR	http://nebulous.mhpcc.ipp.ifa.hawaii.edu/nebulous   # Nebulous server
 
 # Database configuration
-DBSERVER	STR	ipp004			# Database host name (for psDBInit)
+DBSERVER	STR	ippdb01			# Database host name (for psDBInit)
 DBNAME		STR	NONE			# Database name (for psDBInit)
 DBUSER		STR	ipp			# Database user name (for psDBInit)
@@ -34,6 +33,2 @@
 DBPORT          S32     0                       # Database port (for psDBInit); 0 = default
 
-# other basic values:
-# XXX is TIME still needed / used?
-# XXX use autoconf to put this in a known location?
-# TIME		STR	psTime.config	# Time configuration file
Index: branches/eam_branches/20090820/operations/magic/.pantasks
===================================================================
--- branches/eam_branches/20090820/operations/magic/.pantasks	(revision 25766)
+++ branches/eam_branches/20090820/operations/magic/.pantasks	(revision 25766)
@@ -0,0 +1,1769 @@
+status
+status
+server input input
+status
+add.hosts
+run
+status
+magic.ds.off
+status
+status
+magic.ds.revert.on
+run
+status
+status
+status
+status
+status
+status
+status
+magic.off
+magic.ds.revert.on
+status
+status
+status
+magic.ds.revert.off
+magic.ds.on
+status
+controller status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+controller status
+status
+status
+status -tasks
+status
+status
+status -tasks
+status -taskstats
+status -taskstats
+status -tasks
+status -tasks
+halt
+halt
+run
+status -tasks
+status -tasks
+status -tasks
+halt
+magic.ds.off
+run
+status -tasks
+status
+status
+status
+status
+magic.ds.revert.on
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+server input bump
+stauts
+status
+status
+status
+status
+status
+status
+bump
+stauts
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+server input bump
+bumpdown
+magic.ds.revert.off
+magic.ds.on
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+stop
+shutdown now
+server input input
+load.hosts
+add.hosts
+magic.off
+magic.ds.revert.on
+status
+run
+status
+status
+status
+status
+bump
+server input bummp
+server input bump
+bummp
+bump
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+echo $LOADPOLL
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+halt
+shutdown now
+server input input
+add.hosts
+run
+magic.off
+magic.ds.on
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+halt
+shutdown now
+server input input
+del.label ThreePi_SouthernRegion.090724
+add.label ThreePi_NorthernRegion.090729
+show.labels
+add.hosts
+run
+status -tsaks
+magic.off
+magic.ds.on
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -taskstats
+status
+status -tasks
+status -tasks
+status -taskstats
+status -taskstats
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+magic.ds.off
+status -tasks
+status -tasks
+status -tasks
+status
+magic.status
+magic.reset
+magic.status
+magic.ds.on
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+halt
+stop
+status -tasks
+status
+status
+magic.reset
+status
+shutdown now
+server input input
+run
+status -tasks
+status -tasks
+magic.off
+magic.ds.on
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+show.labels
+add.label ThreePi_NorthernRegion.090729
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+server input bump
+extendexec
+extenedexec
+extenedexec
+extenedexec
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+magic.status
+magic.status
+magic.status
+magic.status
+magic.status
+status -taskstats
+status -taskstats
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status
+status -tasks
+status -tasks
+magic.ds.revert.on
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.revert.off
+magic.ds.revert.off
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status -tasks
+status -taskstats
+status
+status
+status
+status
+status
+status
+status
+server input bump
+extendexec
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+magic.status
+status
+status
+status -tasks
+halt
+add.hosts
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+server input bump
+extendexec
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -tasks
+server input bump
+extendexec
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status
+status -tasks
+status
+status -tasks
+status -taskstats
+status
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+status
+status -tasks
+status
+status -taskstats
+status
+status -tasks
+magic.ds.off
+status
+status
+shutdown now
+server input input
+show.labels
+status
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+server input bump
+bump
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -taskstats
+status -tasks
+show.labels
+status
+status -tasks
+!pwd
+!pwd
+status -tasks
+status -tasks
+halt
+status
+status
+run
+status
+halt
+status
+stop
+status
+status
+status
+run
+halt
+status
+status
+status
+status
+status
+magic.stats
+magic.status
+magic.status
+status
+magic.ds.off
+run
+status
+magic.reset
+magic.status
+magic.ds.on
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.off
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+halt
+magic.ds.revert.on
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+halt
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+magic.ds.revert.off
+magic.ds.on
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+halt
+status
+status -tasks
+halt
+run
+status -taks
+status -taks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.off
+status
+status
+magic.ds.off
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+halt
+magic.ds.revert.on
+run
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+halt
+magic.ds.revert.off
+magic.ds.on
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+controller status
+status
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+bumpdown
+status
+status
+status -taskstats
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.on
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.revert.on
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status -tasks
+magic.ds.revert.off
+status -tasks
+status
+status -tasks
+status -tasks
+magic.ds.off
+status
+status
+status
+magic.ds.revert.on
+magic.ds.revert.off
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+magic.ds.revert.on
+status
+status
+status
+status
+magic.status
+magic.revert.status
+magic.ds.revert.status
+magic.ds.status
+status
+status
+status
+status
+status
+status
+bump
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+magic.ds.revert.off
+magic.ds.on
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+magic.ds.off
+status
+status
+status
+status
+status -tasks
+status -tasks
+status
+magic.ds.on
+status
+status -takss
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -task
+status -tasks
+magic.ds.off
+status
+status
+status
+status
+status
+magic.ds.revert.on
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+status
+magic.ds.revert.off
+magic.ds.on
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+!date ; !status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+status -taskstats
+status -taskstats
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status -taskstats
+status -taskstats
+status
+status
+status
+status
+magic.ds.off
+status
+stop
+magic.ds.revert.on
+run
+status
+magic.status
+magic.status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+halt
+shutdown now
+server input input
+status
+run
+status
+status
+status
+status
+halt
+halt
+magic.ds.revert.on
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+server input bump
+bump
+stastus
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.revert.off
+magic.ds.on
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -takss
+status -tasks
+status -tasks
+show.labels
+ptc
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status
+magic.ds.off
+magic.ds.revert.on
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+magic.ds.revert.off
+magic.ds.on
+magic.ds.on
+status
+status
+status
+status
+status
+status
+shutdown now
+server input input
+status
+run
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+controller status
+status
+status -tasks
+!date ; status -tasks
+!date ; status -tasks
+!date ; status -tasks
+stop
+add.hosts
+run
+status
+status -tasks
+status -tasks
+status
+status
+controller status
+controller status
+status -tasks
+status -tasks ; !date
+status -tasks ; !date
+status -tasks ; !date
+status -taskstats
+status -taskstats
+status -taskstats
+magic.ds.off
+status
+status
+magic.status
+magic.status
+stop
+shutdown now
+server input input
+status
+run
+status -tasks ;!date
+status -tasks ;!date
+status -tasks ;!date
+status -tasks ;!date
+status -taskstats
+status -tasks ;!date
+controller status
+status -tasks ;!date
+status -tasks ;!date
+status -tasks ;!date
+status -tasks ;!date
+status -taskstats
+status -tasks ;!date
+status -tasks ;!date
+status -tasks
+status -tasks ; !date
+status -tasks ; !date
+status
+server input bump
+bump
+stats
+status
+status
+status
+status
+status -taskstats
+magic.status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks;!date
+status -tasks;!date
+status -tasks;!date
+status -tasks;!date
+status -tasks;!date
+status -tasks;!date
+status -tasks
+status
+show.labels
+show.labels
+status -tasks
+status
+status -tasks
+show.labels
+status -tasks ; !date
+status -tasks ; !date
+status -tasks ; !date
+status -tasks ; !date
+status -tasks ; !date
+status
+status -takss
+status -tasks
+status -tasks
+status
+status -tasks
+status
+status -tasks
+controller status
+status -tasks
+show.labels
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+controller status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+magic.ds.revert.on
+magic.ds.off
+status -taks
+status -taksstatus -tasks
+status -taksstatus -tasks
+status -tasks
+shutdown now
+server input input
+run
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -taskstas
+status -taskstats
+status -taskstats
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+magic.off
+status
+status
+status
+status
+status
+magic.ds.on
+run
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+halt
+run
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status
+controller status
+controller status
+status -tasks
+status -tasks
+status
+controller status
+shutdown now
+server input input
+run\
+status
+status
+status
+status
+status
+status
+controller status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+magic.off
+magic.off
+status
+shutdown now
+server input input
+magic.ds.off
+magic.ds.revert.on
+status -tasks
+run
+status -tasks
+server input bump
+bump
+status
+status -tasks
+status -tasks
+status
+controller status
+status -tasks
+status -tasks
+status
+status -tasks
+stop
+stop
+halt
+run
+status
+magic.ds.revert.off
+status
+status
+status
+status
+magic.reset
+magic.ds.status
+magic.ds.revert.on
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+show.labels
+!grep Three input
+add.label ThreePi_SouthernRegion.090724
+status
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+statis
+status
+status
+server input input
+add.label ThreePi_SouthernRegion.090724
+del.label STS.090724
+show.labels
+status
+status -tasks
+halt
+shutdown now
+shutdown now
+server input input
+add.label ThreePi_SouthernRegion.090724
+del.label STS.090724
+run
+status
+status
+status
+status
+status
+status
+status -tasks
+show.labels
+status
+status
+status
+status
+status
+status
+controller status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+controller status
+status -tasks
+status -tasks
+halt
+status -tasks
+show.labels
+stop
+run
+status
+status -taks
+status -tasks
+status -tasks
+status
+status -tasks
+status
+status -tasks
+magic.ds.off
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+magic.ds.on
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.off
+status -tasks
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+magic.ds.revert.on
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+magic.ds.off
+magic.ds.revert.off
+magic.ds.on
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+controller status
+controller status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+controller status
+status -tasks
+magic.status
+status -tasks
+status -tasks
+magic.status
+status
+magic.ds.off
+magic.ds.revert.on
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.revert.on
+magic.ds.on
+status -tasks
+magic.status
+magic.status
+status
+magic.status
+status -tasks
+status
+status -tasks
+magic.status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.revert.off
+status -tasks
+status -tasks
+status -tasks
+magic.status
+status
+status -tasks
+status -tasks
+status -tasks
+magic.status
+magic.ds.revert.on
+magic.ds.revert.off
+magic.status
+magic.ds.status
+magic.ds.status
+magic.ds.status
+magic.ds.status
+magic.status
+magic.ds.status
+status
+status
+controller status
+status
+status -tasks
+controller status
+controller status
+magic.ds.status
+status -tasks
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+magic.ds.off
+magic.ds.revert.on
+status
+status
+status
+status
+magic.ds.revert.off
+magic.ds.on
+run
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+halt
+magic.ds.revert
+magic.ds.revert.on
+run
+status -tasks
+status -tasks
+status
+magic.destreak.off
+magic.ds.off
+status -tasks
+magic.ds.revert.off
+magic.ds.on
+status
+status
+halt
+status
+shutdown now
+server input input
+status
+run
+status -tasks
+run
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasktats
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+halt
+stop
+run
+staus -tas
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+magic.ds.off
+status -tasks
+magic.ds.revert.off
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -tasks
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+magic.ds.reset
+magic.reset
+magic.ds.status
+halt
+magic.ds.revert.on
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+magic.status
+magic.ds.status
+shutdown now
+server input input
+status
+magic.ds.revert.off
+magic.ds.on
+run
+status -tasks
+halt
+status
+magic.ds.off
+status
+run
+status
+magic.ds.revert.on
+run
+status
+status
+status
+status
+status
+shutdown now
Index: branches/eam_branches/20090820/operations/magic/bump
===================================================================
--- branches/eam_branches/20090820/operations/magic/bump	(revision 25766)
+++ branches/eam_branches/20090820/operations/magic/bump	(revision 25766)
@@ -0,0 +1,20 @@
+macro bump
+	task magic.ds.revert.run
+		periods -exec .05
+	end
+        $POLLLIMIT=100
+end
+macro bumpdown
+	task magic.ds.revert.run
+		periods -exec 10
+	end
+        $POLLLIMIT=32
+end
+
+macro extendexec
+    task magic.destreak.load
+        periods -exec 5
+    end
+end
+
+
Index: branches/eam_branches/20090820/operations/magic/dsoff
===================================================================
--- branches/eam_branches/20090820/operations/magic/dsoff	(revision 25766)
+++ branches/eam_branches/20090820/operations/magic/dsoff	(revision 25766)
@@ -0,0 +1,24 @@
+macro magic.ds.off
+    task magic.destreak.load
+        active false
+    end
+    task magic.destreak.run
+        active false
+    end
+end
+macro magic.ds.on
+    task magic.destreak.load
+        active true
+    end
+    task magic.destreak.run
+        active true
+    end
+end
+
+macro magic.ds.status
+    echo magicToDS
+    book listbook magicToDS
+    echo ""
+    echo magicDSToRevert
+    book listbook magicDSToRevert
+end
Index: branches/eam_branches/20090820/operations/magic/input
===================================================================
--- branches/eam_branches/20090820/operations/magic/input	(revision 25766)
+++ branches/eam_branches/20090820/operations/magic/input	(revision 25766)
@@ -0,0 +1,68 @@
+module pantasks.pro
+
+module site.mhpcc.pro
+init.copy.mhpcc on
+queueload tmp -x "cat $MODULES:0/ipphosts.mhpcc.config"
+ipptool2book tmp ipphosts -key camera
+
+macro add.hosts
+    controller host add ipp021 
+    controller host add ipp024 
+    controller host add ipp026 
+    controller host add ipp028 
+    controller host add ipp029 
+    controller host add ipp030 
+    controller host add ipp031 
+    controller host add ipp032 
+    controller host add ipp033 
+    controller host add ipp034 
+    controller host add ipp035 
+    controller host add ipp036 
+    controller host add ipp038
+    controller host add ipp039
+    controller host add ipp040
+    controller host add ipp041
+    controller host add ipp042
+    controller host add ipp043
+    controller host add ipp044
+    controller host add ipp045
+    controller host add ipp046
+    controller host add ipp047
+    controller host add ipp048
+    controller host add ipp049
+    controller host add ipp050
+    controller host add ipp051
+    controller host add ipp052
+    controller host add ipp053
+end
+
+macro skycell.hosts
+    controller host add ipp024
+    controller host add ipp013
+    controller host add ipp026
+    controller host add ipp028
+    controller host add ipp029
+    controller host add ipp030
+    controller host add ipp031
+    controller host add ipp032
+    controller host add ipp033
+    controller host add ipp034
+    controller host add ipp035
+    controller host add ipp036
+end
+
+#skycell.hosts
+
+add.hosts
+
+module magic.pro
+magic.off
+#magic.ds.on
+magic.ds.revert.on
+
+add.database gpc1
+add.label ThreePi_SouthernRegion.090724
+#add.label ThreePi_NorthernRegion.090724
+#add.label STS.090724
+echo labels:
+show.labels
Index: branches/eam_branches/20090820/operations/magic/ptolemy.rc
===================================================================
--- branches/eam_branches/20090820/operations/magic/ptolemy.rc	(revision 25766)
+++ branches/eam_branches/20090820/operations/magic/ptolemy.rc	(revision 25766)
@@ -0,0 +1,5 @@
+
+PANTASKS_SERVER_STDOUT  pantasks.stdout.log
+PANTASKS_SERVER_STDERR  pantasks.stderr.log
+PANTASKS_SERVER         ippc01
+PASSWORD                foobar
Index: branches/eam_branches/20090820/operations/publishing/.pantasks
===================================================================
--- branches/eam_branches/20090820/operations/publishing/.pantasks	(revision 25766)
+++ branches/eam_branches/20090820/operations/publishing/.pantasks	(revision 25766)
@@ -0,0 +1,104 @@
+input input
+setup
+status
+halt
+run
+status
+halt
+add.label mops.20090629
+run
+status
+show.labels
+!pwd
+!pwd
+show.labels
+status
+status
+status
+halt
+status
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+halt
+halt
+run
+status
+status
+status
+status
+status
+status
+status
+status
+halt
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+halt
+!who am i
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+add.label mops.20090701
+status
+status
+status
+server input input
+setup
+status
+run
+status
+status
+status
+stop
+status
+run
+status
+status
+status
+status
+stop
+waveC_nothreads
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+shutdown now
Index: branches/eam_branches/20090820/operations/publishing/input
===================================================================
--- branches/eam_branches/20090820/operations/publishing/input	(revision 25766)
+++ branches/eam_branches/20090820/operations/publishing/input	(revision 25766)
@@ -0,0 +1,90 @@
+macro setup
+    $MODULES:0 = /home/panstarrs/ipp/ipp-svn/ippTasks
+
+    module pantasks.pro
+    module publish.pro
+
+    $POLLLIMIT = 16
+
+    $LOADPOLL = 1
+    $LOADEXEC = 30
+
+    $RUNPOLL = 0.5
+    $RUNEXEC = 1.0
+
+    add.database gpc1
+    add.label dummy
+
+    waveC_nothreads
+end
+
+macro change_verbosity
+    $VERBOSE = $1
+end
+
+macro change_polllimit
+    $POLLLIMIT = $1
+end
+
+macro change_runexec
+    $RUNEXEC = $1
+end
+
+macro change_runpoll
+    $RUNPOLL = $1
+end
+
+macro print_verbosity
+    echo $VERBOSE
+end
+
+macro print_polllimit
+    echo $POLLLIMIT
+end
+
+macro print_runexec
+    echo $RUNEXEC
+end
+
+macro print_runpoll
+    echo $RUNPOLL
+end
+
+macro change_loadexec
+    $LOADEXEC = $1
+end
+
+macro change_loadpoll
+    $LOADPOLL = $1
+end
+
+macro print_loadexec
+    echo $LOADEXEC
+end
+
+macro print_loadpoll
+    echo $LOADPOLL
+end
+
+macro waveC_nothreads
+  controller host add ippc00
+  controller host add ippc01
+  controller host add ippc02
+  controller host add ippc03
+  controller host add ippc04
+  controller host add ippc05
+  controller host add ippc06
+  controller host add ippc07
+end
+
+macro waveC
+  controller host add ippc00 -threads $1
+  controller host add ippc01 -threads $1
+  controller host add ippc02 -threads $1
+  controller host add ippc03 -threads $1
+  controller host add ippc04 -threads $1
+  controller host add ippc05 -threads $1
+  controller host add ippc06 -threads $1
+  controller host add ippc07 -threads $1
+end
+
Index: branches/eam_branches/20090820/operations/publishing/ptolemy.rc
===================================================================
--- branches/eam_branches/20090820/operations/publishing/ptolemy.rc	(revision 25766)
+++ branches/eam_branches/20090820/operations/publishing/ptolemy.rc	(revision 25766)
@@ -0,0 +1,6 @@
+
+PANTASKS_SERVER_STDOUT  pantasks.stdout.log
+PANTASKS_SERVER_STDERR  pantasks.stderr.log
+PANTASKS_SERVER         ippc08
+PASSWORD                publishing
+
Index: branches/eam_branches/20090820/operations/registration/ptolemy.rc
===================================================================
--- branches/eam_branches/20090820/operations/registration/ptolemy.rc	(revision 25206)
+++ branches/eam_branches/20090820/operations/registration/ptolemy.rc	(revision 25766)
@@ -2,5 +2,5 @@
 PANTASKS_SERVER_STDOUT  pantasks.stdout.log
 PANTASKS_SERVER_STDERR  pantasks.stderr.log
-PANTASKS_SERVER         ipp009
+PANTASKS_SERVER         ippc02
 PASSWORD                foobar
 
Index: branches/eam_branches/20090820/operations/replication/.pantasks
===================================================================
--- branches/eam_branches/20090820/operations/replication/.pantasks	(revision 25766)
+++ branches/eam_branches/20090820/operations/replication/.pantasks	(revision 25766)
@@ -0,0 +1,103 @@
+server input input
+setup
+run
+status
+status -tasks
+status
+shutdown now
+module pantasks.pro
+server module pantasks.pro
+server module replicate.pro
+server input input
+server input input
+setup
+status
+run
+status
+stop
+shutdown now
+status -tasks
+status
+status
+status -tasks
+status
+status
+status
+controller status
+status
+status -tasks
+status -tasks
+controller status
+status -tasks
+status -tasks
+status -tasks
+status
+controller status
+server input input
+server input input
+$pwd
+!pwd
+!ls
+server input input
+status
+shutdown onw
+shutdown now
+server input input
+status
+setup
+status
+shutdown now
+server input input
+setup
+status
+run
+status
+server input input
+setup
+run
+status
+status
+status
+status
+status
+status
+controller status
+status
+halt
+shutdown now
+server input input
+add.hosts
+load.hosts
+!cat input
+load.hosts
+loadhosts
+addhosts
+init.site
+stei.init
+setup
+status
+run
+status
+status
+status
+status
+status
+status
+status
+status
+shudown now
+shutdown now
+status
+status -tasks
+status
+shutdown now
+status
+status
+shutdown now
+status
+shutdown now
+server input input
+run
+status
+halt
+run
Index: branches/eam_branches/20090820/operations/replication/input
===================================================================
--- branches/eam_branches/20090820/operations/replication/input	(revision 25766)
+++ branches/eam_branches/20090820/operations/replication/input	(revision 25766)
@@ -0,0 +1,23 @@
+
+macro setup
+  module pantasks.pro
+  module replicate.pro
+  module site.mhpcc.pro
+  init.site
+  add.database gpc1
+end
+
+macro resetup
+#  module pantasks.pro
+#  module summit.copy.pro
+#  module site.mhpcc.pro
+#  init.site
+  add.database gpc1
+end
+
+macro replication.status
+  echo "replicatePending"
+  book npages replicatePending
+  book listbook replicatePending
+end
+
Index: branches/eam_branches/20090820/operations/replication/params
===================================================================
--- branches/eam_branches/20090820/operations/replication/params	(revision 25766)
+++ branches/eam_branches/20090820/operations/replication/params	(revision 25766)
@@ -0,0 +1,4 @@
+echo NEB_USER $NEB_USER
+echo NEB_PASS $NEB_PASS
+echo NEB_HOST $NEB_HOST
+echo NEB_DB   $NEB_DB
Index: branches/eam_branches/20090820/operations/replication/ptolemy.rc
===================================================================
--- branches/eam_branches/20090820/operations/replication/ptolemy.rc	(revision 25766)
+++ branches/eam_branches/20090820/operations/replication/ptolemy.rc	(revision 25766)
@@ -0,0 +1,6 @@
+
+PANTASKS_SERVER_STDOUT  pantasks.stdout.log
+PANTASKS_SERVER_STDERR  pantasks.stderr.log
+PANTASKS_SERVER         ipp004
+PASSWORD                foobar
+
Index: branches/eam_branches/20090820/operations/stdscience/.mana
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/.mana	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/.mana	(revision 25766)
@@ -0,0 +1,13 @@
+echo {4*4/12/12}
+echo {30000/(4*4/12/12)}
+echo {5500*90}
+echo {270000/5000}
+echo {400000*(60*4 + 120)}
+echo {(60*4 + 120)}
+echo {300000*360*5}
+echo {300000*360*5/1e6}
+echo {300000*360*5/3e7}
+echo {(60*8 + 120)}
+echo {300000*600*5/3e7}
+echo {(60*12 + 120)}
+echo {300000*840*5/3e7}
Index: branches/eam_branches/20090820/operations/stdscience/.pantasks
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/.pantasks	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/.pantasks	(revision 25766)
@@ -0,0 +1,1848 @@
+status
+server input input
+setup
+shutdown now
+pwd
+status
+server input input
+setup
+status
+show.database
+show.label
+load.hosts
+status
+status
+status
+show.labels
+run
+run
+show.labels
+status
+status
+add.label scitest.20090419.v0
+status
+status
+status
+status
+status
+status
+status
+add.label scitest.20090419.v1
+status
+status
+status
+status
+status
+status
+pwd
+camera.off
+status
+!ls
+!ls -lrt
+show.label
+status
+show.label
+del.label dummy
+del.label scitest.20090419.v0
+del.label scitest.20090419.v1
+add.label scitest.20090419.v1
+status
+shutdown now
+status
+server input input
+setup
+status
+camera.off
+status
+run
+status
+status
+show.label
+status
+add.label ThreePi.Run2.g.v0
+status
+status
+status
+add.label ThreePi.Run2.r.v0
+add.label ThreePi.Run2.i.v0
+add.label ThreePi.Run2.z.v0
+add.label ThreePi.Run2.y.v0
+status
+status -tasks
+load.hosts
+status
+control status
+control status
+control status
+status
+status -tasks
+control status
+load.hosts
+status
+status
+control status
+server input input
+get.poll
+set.poll
+set.poll 100
+status
+load.hosts.wave2
+status
+control status
+quti
+server input input
+setup
+load.hosts
+show.label
+add.label ThreePi.Run2.g.v0
+add.label ThreePi.Run2.r.v0
+add.label ThreePi.Run2.i.v0
+add.label ThreePi.Run2.z.v0
+add.label ThreePi.Run2.y.v0
+stauts
+status
+run
+status
+status
+status -tasks
+camera.off
+status -tasks
+status -tasks
+server input input
+status
+setup
+status
+add.label ThreePi.Run2.g.v0
+add.label ThreePi.Run2.r.v0
+add.label ThreePi.Run2.i.v0
+add.label ThreePi.Run2.z.v0
+add.label ThreePi.Run2.y.v0
+status
+run
+load.hosts
+status
+statu
+status
+server input input
+setup
+status
+camera.off
+status
+add.label ThreePi.Run2.g.v0
+add.label ThreePi.Run2.r.v0
+add.label ThreePi.Run2.i.v0
+add.label ThreePi.Run2.z.v0
+add.label ThreePi.Run2.y.v0
+status
+loadhosts
+load.hosts
+status
+run
+status
+status -tasks
+stop
+status
+!cat input
+get.poll
+status
+status
+status
+status
+!cat input
+control status
+control status
+control host off ipp018
+control status
+control status
+control host on ipp018
+control status
+control status
+control status
+control status
+control off ipp018
+control host off ipp018
+control host
+control host on ipp018
+control status
+control host retry ipp018
+control status
+control status
+control status
+!cat input
+status
+run
+status
+status -asks
+status -tasks
+status -taskstats
+status -taskstats
+show.label
+status -taskstats
+load.hosts.wave2
+load.hosts.wave2
+server input input
+show.book chipProcessedImfile
+show.book chipProcessedImfiles
+show.book chipProcessedImfile
+status
+show.book chipPendingImfile
+server input input
+show.book chipPendingImfile
+show.label
+status
+status -tasks
+set.poll 100
+status
+status
+status
+status -tasks
+status -taskstats
+control status
+control status
+status -tasks
+status -taskstats
+status -taskstatreset
+status -taskstatsreset
+status -tasks
+status -taskstats
+~
+status -taskstats
+status -tasks
+status
+status -tasks
+status -taskstats
+status -taskstats
+status -tasks
+status
+control status
+status -tasks
+status
+status
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.r.v0
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.i.v0
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.z.v0
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.y.v0
+status
+status
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.r.v0
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.i.v0
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.z.v0
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.y.v0
+status
+status
+status
+exec chiptool -dbname gpc1 -revertprocessedimfile -label ThreePi.Run2.y.v0
+status
+status
+status
+status
+input input
+setup
+add.label ThreePi.Run2.r.v0
+add.label ThreePi.Run2.i.v0
+add.label ThreePi.Run2.z.v0
+add.label ThreePi.Run2.y.v0
+status
+run
+status
+stop
+load.hosts
+load.hosts.wave2
+run
+status
+stop
+status
+server input input
+setup
+add.label ThreePi.Run2.r.v0
+add.label ThreePi.Run2.i.v0
+add.label ThreePi.Run2.z.v0
+add.label ThreePi.Run2.y.v0
+load.hosts
+load.hosts.wave2
+run
+status
+add.label ThreePi.Run2.g.v0
+status
+status
+status
+status
+controller status
+status
+status
+controller status
+status
+status
+status
+stop
+run
+status
+stop
+status
+status
+status
+status
+status
+shutdown now
+status
+status
+shutdown now
+!cat inptu
+!cat input
+server input input
+setup
+load.hosts
+server module stack.pro
+status
+control status
+run
+status
+server input input
+setup
+status
+load.hosts.wave1
+load.hosts.wave2
+load.hosts.wave3
+status
+control status
+status
+control status
+status
+show.label
+add.label MD08.200906.v0
+status
+status
+run
+status
+status
+status
+status
+status
+status
+status
+status -tasks
+stop
+qut
+status
+status -
+status -taskstats
+status -taskstats
+status
+shutdown now
+server input input
+setup
+status
+load.wave1
+load.hosts.wave1
+load.hosts.wave2
+load.hosts.wave3
+status
+control status
+run
+show.label
+status
+add.label MD08.200906.v0
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+stop
+fake.off
+run
+status
+status -tasks
+echo {13*8 + 2}
+echo {60*(13*8 + 2)}
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+stop
+fake.on
+run
+status
+status -tasks
+status -tasks
+status -tasks
+stop
+warp.off
+warp.on
+run
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+stop
+status -tasksl
+stop
+run
+status -tasks
+status -tasksa
+status -tasksa
+status -tasks
+status -tasks
+status -tasksa
+status -tasks
+status -tasks
+status -tasksa
+status -tasks
+shutdown now
+server input input
+setup
+status
+load.hosts.wave1
+load.hosts.wave2
+load.hosts.wave3
+status
+show.label
+add.label MD08.200906.v0
+status
+control status
+run
+status
+show.label
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+stats
+status
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+status -taskstats
+status -tasks
+status -task
+status -tasks
+echo {100*60*1.5}
+status -tasks
+status
+status -tasks
+show.label
+add.label MD06.200906.v0
+add.label MD07.200906.v0
+add.label MD09.200906.v0
+show.label
+status -tasks
+status
+status -tasks
+stop
+del.label dummy
+show.label
+run
+statu
+status -tasks
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskss
+status -tasks
+status -tasks
+status -tasks
+status -task
+control status
+control status
+status -task
+status -taskstats
+status -task
+status -tasks
+status -tasks
+load.hosts.wave3
+status -tasks
+status -tasks
+stop
+show.labels
+del.label MD06.200906.v0
+del.label MD07.200906.v0
+del.label MD09.200906.v0
+show.label
+run
+status -tasks
+status -task
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+status -tasks
+status -taskstats
+control status
+show.label
+add.label noise.20090626
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+stop
+status -taskss
+status -taskss
+status -taskss
+control status
+status -tasks
+status -taskss
+status -taskss
+status -taskss
+status -taskss
+status -taskss
+server input input
+load.hosts.compute
+status
+control status
+control status
+control status
+control status
+control status
+status -taskss
+status -taskss
+status -taskss
+control status
+control status
+run
+status
+status
+show.label
+status
+status
+status -tasks
+status -tasks
+control status
+status -tasks
+status -tasks
+status -taskss
+stop
+control status
+shutdown now
+server input input
+setup
+add.label noise.20090626
+status
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+status
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+stop
+shutdown now
+server input input
+setup
+status
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+status
+control status
+control status
+control status
+control status
+status
+show.label
+add.label noise.20090626
+run
+status
+run
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+show.label
+stop
+add.label MD08.200906.v0
+run
+status
+status -tasks
+status -task
+status -tasks
+show.label
+stop
+add.label MD06.200905.v0
+add.label MD07.200905.v0
+add.label MD08.200905.v0
+add.label MD07.200906.v0
+add.label MD09.200906.v0
+show.label
+status -tasks
+status -task
+run
+status -tasks
+status -tas
+status -task
+status -tasks
+status -tasks
+status -task
+status -tasks
+stop
+status -tasks
+chip.off
+warp.off
+fake.off
+camera.off
+status -tasks
+status -tasks
+status -tasks
+show.label
+del.label dummy
+del.label MD06.200905.v0
+del.label MD07.200905.v0
+del.label MD08.200905.v0
+del.label MD09.200905.v0
+show.label
+del.label MD09.200906.v0
+del.label MD07.200906.v0
+show.label
+run
+status -tasks
+status -taskss
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+show.label
+stop
+server module magic.pro
+shutdown now
+server module magic.pro
+server input input
+status -tasks
+setup
+server input input
+setup
+server input input
+setup
+status
+add.label noise.20090626
+status
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+run
+status
+status
+status
+status
+status
+status
+stop
+status -tasks
+magic.off
+status
+shutdown now
+status
+status shutdown now
+shutdown now
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+status
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave23
+load.hosts.wave3
+load.hosts.compute
+status
+add.label mops.20090701
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+shutdown now
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+add.label MD08.200904.v1
+add.label MD08.200905.v1
+add.label MD08.200906.v1
+chip.revert.off
+status
+control status
+control status
+control status
+control status
+control status
+control status
+status
+run
+show.label
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -task
+status -tasks
+status -tasks
+status
+stop
+echo {0.26*5.2}
+echo {0.26*5.}
+status
+run
+status
+status
+show.label
+status
+stop
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+stop
+server input input
+warp.revert.off
+server input input
+warp.revert.off
+status
+run
+status
+status
+status
+status -tasks
+status -taskstats
+status -taskstats
+status
+status -taskstats
+status -tasks
+status -tasks
+stop
+magic.off
+status -tasks
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+show.label
+add.label MD08.200906.v1.test
+status
+stop
+magic.on
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+echo {50*8*4800*40}
+echo {50*8*4800*40/(4800^2*60)}
+status
+status
+stop
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status
+status
+control status
+quti
+stop
+status
+show.label
+del.label MD08.200906.v1.test
+show.label
+del.label MD08.200904.v1
+del.label MD08.200905.v1
+show.label
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -task
+show.label
+add.label MD06.200904.v1
+add.label MD06.200905.v1
+add.label MD06.200906.v1
+add.label MD07.200904.v1
+add.label MD07.200905.v1
+add.label MD07.200906.v1
+show.label
+status -task
+status -task
+status -task
+status -task
+status -tasks
+status -tasks
+load.hosts.wave3
+load.hosts.compute
+status -tasks
+status -tasks
+status -task
+control status
+status -tasks
+status -tasks
+status -task
+status -tasks
+status -tasks
+status
+shutdown now
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+run
+status
+show.label
+stop
+add.label MD08.200906.t1
+run
+status
+status
+stop
+status
+show.label
+run
+status
+status
+status
+status -taskstats
+status
+status
+status
+status
+status
+status
+stop
+show.label
+add.label MD08.200906.v1
+del.label MD08.200906.t1
+status
+run
+status
+status
+status -tsks
+status -tasks
+status -tasks
+stop
+warp.revert.off
+run
+status -tasks
+status -task
+status -task
+status -tasks
+echo {600*600}
+control status
+echo {600*600/50}
+status -tasks
+show.label
+stop
+add.label MD06.200906.v1
+add.label MD07.200906.v1
+show.label
+run
+status
+status -tasks
+status -tasks
+status
+status -tasks
+status -tasks
+status
+status
+status -tasks
+status -task
+show.label
+control status
+status -task
+status -tasks
+status -task
+status -tasks
+status -task
+status -tasks
+status -tasks
+status -taskstats
+echo {300*80*50/50}
+echo {300*80*50/50/3600}
+show.label
+status
+stop
+add.label MD07.200904.v1
+add.label MD06.200904.v1
+add.label MD06.200905.v1
+add.label MD07.2009045.v1
+del.label MD07.2009045.v1
+add.label MD07.200905.v1
+show.label
+status
+run
+status
+status -tasks
+echo {497*80*50/50}
+echo {497*80*50/50/3600}
+status -tasks
+status -tasks
+status -tasks
+show.label
+stop
+del.label MD07.200904.v1
+del.label MD07.200905.v1
+del.label MD06.200904.v1
+del.label MD06.200905.v1
+show.label
+status
+run
+status
+load.hosts.compute
+load.hosts.wave3
+status
+control status
+show.label
+add.label MD06.200904.v1
+add.label MD07.200904.v1
+add.label MD08.200904.v1
+add.label MD06.200905.v1
+add.label MD07.200905.v1
+add.label MD08.200905.v1
+show.label
+status -tasks
+status
+control status
+status -tasks
+status -task
+control status
+control status
+pwd
+cat input
+!cat input
+load.hosts.wave2
+control status
+status -tasks
+status -taskstats
+status -task
+control status
+show.labels
+echo {58*80*50/100}
+show.labels
+del.label dummy
+del.label MD06.200906.v1
+del.label MD07.200906.v1
+show.labels
+del.label MD07.200905.v1
+del.label MD08.200905.v1
+del.label MD06.200905.v1
+show.label
+del.label MD07.200904.v1
+del.label MD08.200904.v1
+status
+control status
+show.label
+status
+control status
+status -tasks
+status
+control status
+show.label
+status
+status
+status -tasks
+status -tasks
+status
+status
+status
+status
+show.label
+del.label MD06.200904.v1
+status
+status
+show.label
+stop
+show.label
+add.label MD07.200906.v1
+add.label MD06.200906.v1
+show.label
+status
+run
+status
+status
+control status
+control status
+control status
+status
+status -taskstats
+status -taskstats
+control status
+control status
+status
+stop
+server input input
+adjust.magic
+status
+status -taskstats
+run
+status
+status
+status -taskstats
+status -taskstats
+show.label
+stop
+add.label MD07.200904.v1
+add.label MD08.200904.v1
+run
+status
+status -taskstats
+status
+status -taskstats
+status
+control status
+status -tasks
+status -tasks
+echo {400*80}
+status -tasks
+status -taskstats
+status -taskstatsinfo
+stop
+server input input
+adjust.magic
+status
+run
+status
+status
+status
+status -tasks
+status -tasks
+get.poll
+status -task
+status -task
+status -task
+control status
+control status
+status -tasks
+control status
+stop
+server input input
+adjust.magic
+run
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+control status
+status -task
+status -tasks
+status -tasks
+echo {6/25}
+echo {100*0.24}
+echo {400*24}
+echo {400*24/3600}
+status -tasks
+status -tasks
+status -task
+status -tasks
+status -tasks
+status -tasks
+status -task
+status -task
+status -taskstats
+status -tasks
+echo {58287*0.25}
+echo {58287*0.25 / 3600}
+status -tasks
+status -taskss
+status -taskss
+control status
+status -taskss
+status -tasks
+show.book magicToProcess
+status -tasks
+stop
+server module magic.pro
+status
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status -taskinfo
+status
+status
+control status
+show.book magicToProcess
+status
+status -taskinfo
+status -taskinfo
+stop
+chip.off
+cam.off
+camera.off
+warp.off
+stack.off
+status
+fake.off
+status
+run
+status
+status
+status
+status
+show.label
+status
+stop
+server module magic.pro
+run
+status
+status
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+control status
+control status
+status -tasks
+status -tasks
+status -tasks
+status -taskstats
+status -tasks
+status -tasks
+date; status -tasks
+date; status -tasks
+echo {(12765 - 10147)/(7.5*60)}
+echo {(7.5*60)/(12765 - 10147)}
+show.labels
+stop
+del.label MD08.200906.v1
+del.label MD07.200906.v1
+del.label MD07.200904.v1
+del.label MD08.200904.v1
+show.label
+run
+status
+echo {17500-13200}
+echo {(17500-13200)*0.17}
+status
+date; status -tasks
+status
+show.label
+add.label MD07.200906.v1
+add.label MD08.200906.v1
+status -tasks
+status -tasks
+control status
+show.label
+add.label MD06.200905.v1
+add.label MD07.200905.v1
+add.label MD08.200905.v1
+status
+status -tasks
+stop
+run
+status
+status
+status -tasks
+status -tasks
+status
+control status
+control status
+show.labels
+stop
+del.label MD06.200905.v1
+del.label MD07.200905.v1
+del.label MD08.200905.v1
+add.label MD08.200904.v1
+add.label MD07.200904.v1
+show.label
+add.label MD06.200905.v1
+add.label MD07.200905.v1
+add.label MD08.200905.v1
+show.label
+run
+status
+status
+status
+status
+status
+status
+status
+status
+control status
+control status
+status
+status -tasks
+status -tasks
+show.labels
+status -tasks
+control -status
+control status
+show.label
+stop
+del.label MD06.200905.v1
+del.label MD07.200905.v1
+del.label MD08.200905.v1
+run
+status
+show.label
+show.label
+status -tasks
+status
+status -
+status -
+status -
+status
+stop
+show.label
+add.label MD06.200904.v1
+add.label MD06.200905.v1
+add.label MD07.200905.v1
+add.label MD08.200905.v1
+show.label
+run
+status
+status -tasks
+status
+status -tasks
+control status
+status
+status
+control status
+status
+status
+status
+show.label
+del.label MD06.200906.v1
+del.label MD07.200906.v1
+del.label MD08.200906.v1
+del.label MD06.200904.v1
+del.label MD07.200904.v1
+del.label MD08.200904.v1
+show.label
+statu
+statu -tasks
+statu -tasks
+statu -tasks
+status
+!magictool -dbname gpc1 -reverttree -h
+!magictool -dbname gpc1 -reverttree -magic_id 1303
+!magictool -dbname gpc1 -reverttree -magic_id 1352
+!magictool -dbname gpc1 -reverttree -magic_id 1480
+!magictool -dbname gpc1 -revertnode -label MD06.200905.v1
+!magictool -dbname gpc1 -revertnode -label MD07.200905.v1
+!magictool -dbname gpc1 -revertnode -label MD08.200905.v1
+!magictool -dbname gpc1 -revertnode -label MD06.200904.v1
+!magictool -dbname gpc1 -revertnode -label MD07.200904.v1
+!magictool -dbname gpc1 -revertnode -label MD08.200904.v1
+!magictool -dbname gpc1 -revertnode -label MD06.200906.v1
+!magictool -dbname gpc1 -revertnode -label MD07.200906.v1
+!magictool -dbname gpc1 -revertnode -label MD08.200906.v1
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+status
+status
+control status
+status
+status
+show.label
+add.label ThreePi.S00.200906.v1
+status
+status
+status
+status
+status -tasks
+status -tasks
+status
+status -tasks
+stop
+status
+status -tasks
+run
+yur
+status
+status -tasks
+stop
+status -tasks
+status
+status
+run
+status
+status
+status -tasks
+show.labels
+status -tasks
+status -tasks
+stop
+status
+status
+shutdown now
+status
+server input input
+setup
+load.host.wave2
+load.hosts.wave2
+load.hosts.compute
+status
+camera.off
+add.label ThreePi.S00.200906.v1
+run
+status
+status
+status -tasks
+status
+status -tasks
+status -tasks
+status -
+status -tasks
+status -taskstast
+status -taskstats
+status -tasks
+status -task
+stop
+echo {1379/7}
+echo {2044/7/2}
+echo {882/7/2}
+echo {882/2}
+echo {994/6}
+echo {149+18}
+status
+status
+show.labels
+stop
+add.label MD09.200906.v1
+add.label MD09.200907.v1
+run
+status
+status -tasks
+status -tasks
+status -task
+status
+status
+status
+status -tasks
+status
+!difftool -revertdiffskyfile -dbname gpc1 -label MD09.200906.v1
+!difftool -revertdiffskyfile -dbname gpc1 -label MD09.200907.v1
+status
+status
+status
+status
+status
+status
+stop
+module magic.pro
+server module magic.pro
+status
+run
+status
+show.label
+status
+status
+status
+status -taskinfo
+status
+status -taskinfo
+status
+status -tasks
+status -tasks
+status
+shutdown now
+status
+shutdown now
+status
+server input input
+setup
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+run
+status
+show.label
+add.label stdscience.darktest.20090717
+status
+status
+stop
+del.label stdscience.darktest.20090717
+run
+status
+status
+stop
+add.label stdscience.darktest.20090717
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+control status
+status -tasks
+stop
+control host off ipp026
+control status
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+stop
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -task
+run
+status -tasks
+status -tasks
+status -task
+status -tasks
+status -tasks
+status -tasks
+show.label
+add.label stdscience.darktest.20090717.v2
+status -tasks
+status -tasks
+status -task
+status -task
+status -task
+status -task
+status -task
+status -tasks
+status
+show.label
+add.label ThreePi.S00.200906.v1
+status
+show.labels
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+status
+status -taskstatsreset
+status -tasks
+status
+status -tasks
+stop
+warp.off
+camera.off
+show.label
+status -task
+add.label stdscience.darktest.20090717.v0
+status
+module magic.pro
+server module magic.pro
+status
+run
+status
+run
+status
+status
+status -tasks
+status -tasks
+status -tasks
+status -tasks
+!magictool -h
+!magictool -dbname gpc1 -reverttree -h
+!magictool -dbname gpc1 -reverttree -magic_id 1653
+!magictool -dbname gpc1 -reverttree -magic_id 1655
+status -tasks
+!magictool -dbname gpc1 -revertnode -h
+!magictool -dbname gpc1 -revertnode -label stdscience.darktest.20090717.v2
+st
+status -tasks
+show.label
+status -task
+status -task
+control status
+status -taskinfo
+status -task
+status -tasks
+status -tasks
+!magictool -dbname gpc1 -revertnode -label stdscience.darktest.20090717.v0
+status
+sto
+status
+show.labels
+del.label stdscience.darktest.20090717
+del.label stdscience.darktest.20090717.v0
+del.label stdscience.darktest.20090717.v2
+del.label ThreePi.S00.200906.v1
+show.labels
+add.label stdscience.darktest.20090717.v3
+status
+status -taskstatsreset
+status
+run
+status
+status
+status
+status
+status
+stop
+camera.on
+run
+status
+status
+status
+status
+status
+echo {100000*0.001}
+echo {100000*0.05}
+echo {100000*0.05/12}
+status
+status
+status
+stop
+status
+!chiptool -revertprocessedimfile -dbname gpc1 -label stdscience.darktest.20090717.v3
+run
+status
+status
+status
+status
+status
+status
+status
+status
+stop
+status
+status
+controller status
+status
+shutdown now
+server input input
+setup
+status
+load.hosts.wave1
+load.hosts.wave2
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.wave3
+load.hosts.compute
+load.hosts.compute
+run
+status
+status
+status
+status
+status
+controller status
+add.label stdscience.diffclip.20090721
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+server module magic.pro
+add label stdscience.diffclip.20090721.magic
+add.label stdscience.diffclip.20090721.magic
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+show.label
+add.label stdscience.diffclip.20090721.magic
+add.label stdscience.diffclip.20090721.magic
+status
+!cat input
+show.book magicTree
+status
+show.book magicToTree
+status
+stop
+magic.off
+status
+stop
+magic.on
+status
+run
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+stop
+shutdown now
+server input input
+setup
+status
+shutdown now
+server input input
+setup
+status
+add.label stdscience.diffclip.20090721.magic
+run
+status
+status
+status
+status
+status
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+add.label pattern.20090722.magic
+status
+status
+status
+add.label STS.090724
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+status
+controller status
+status
+controller status
+controller status
+controller status
+show.label
+show.label
+status
+controller status
+controller status
+load.hosts.wave1
+load.hosts.wave2
+load.hosts.wave3
+load.hosts.compute
+controller status
+controller status
+controller status
+controller status
+controller status
+controller status
+controller status
+controller status
+controller status
+controller status
+status
+status
+status
+status
+show.label
+status
+status -tasks
+stop
+chip.off
+run
+stop
+camera.off
+run
+stop
+chip..on
+chip.on
+camera.on
+run
+status
+status -tasks
+server input input
+setup
+load.host.compute
+run
+load.host.comput
+load.host.compute
+load.hosts.compute
+load.hosts.wave1
+load.hosts.wave2
+load.hosts.wave3
+controller status
+status
+show labels
+show label
+show.labels
+add.label STS.090724
+add.label ThreePi_SouthernRegion.090724
+status
+show.labels
+show.labels
+status
+controller status
+controller status
+status
+show.labels
+stop
+status
+status
+controller status
+controller status
+controller status
+controller status
+controller status
+controller status
+status
+status
+status
+controller status
+load.hosts.wave3
+load.hosts.wave2
+load.hosts.wave1
+controller status
+load.hosts.compute
+controller status
+status
+controller status
+controller status
+status
+status
+status
+load.hosts.compute
+status
+status
+server input input
Index: branches/eam_branches/20090820/operations/stdscience/3pi.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/3pi.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/3pi.chip	(revision 25766)
@@ -0,0 +1,17 @@
+#!/bin/csh -f
+
+# run the ThreePi data for June 2009 for the sky region 18h:20h,-30:-15 (S00)
+
+set options = "-simple -dbname gpc1 -definebyquery -ra_min 270.0 -ra_max 300.0 -decl_min -35.0 -decl_max -15.0 -set_end_stage warp -set_tess_id RINGS.V0 -set_reduction STDSCIENCE_V0 -comment ThreePi%"
+
+# June 2009 (only g & r in this region & time range)
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-25T00:00:00 -dateobs_end 2009-06-25T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090625.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-27T00:00:00 -dateobs_end 2009-06-27T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090627.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-28T00:00:00 -dateobs_end 2009-06-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090628.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-29T00:00:00 -dateobs_end 2009-06-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090629.stdsci.v1 
+chiptool $options -set_label ThreePi.S00.200906.v1 -dateobs_begin 2009-06-30T00:00:00 -dateobs_end 2009-06-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090630.stdsci.v1 
Index: branches/eam_branches/20090820/operations/stdscience/3pi.labels
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/3pi.labels	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/3pi.labels	(revision 25766)
@@ -0,0 +1,5 @@
+add.label ThreePi.Run2.g.v0
+add.label ThreePi.Run2.r.v0
+add.label ThreePi.Run2.i.v0
+add.label ThreePi.Run2.y.v0
+add.label ThreePi.Run2.z.v0
Index: branches/eam_branches/20090820/operations/stdscience/3pi.t2.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/3pi.t2.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/3pi.t2.chip	(revision 25766)
@@ -0,0 +1,12 @@
+#!/bin/csh -f
+
+# run the ThreePi data for June 2009 for the sky region 295.0 - 300.0, -10.0 - -5.0
+
+set options = "-simple -dbname gpc1 -definebyquery"
+set options = "$options -ra_min 295.0 -ra_max 300.0 -decl_min -20.0 -decl_max -15.0"
+set options = "$options -set_end_stage warp -set_tess_id RINGS.V0 -set_reduction STDSCIENCE_V0 -comment ThreePi%"
+set options = "$options -dateobs_begin 2009-06-20T12:30:00 -dateobs_end 2009-06-20T14:00:00"
+# set options = "$options -pretend"
+
+# June 2009 (only g & r in this region & time range)
+chiptool $options -set_label stdscience.darktest.20090717.v3  -set_workdir neb://@HOST@.0/gpc1/stdscience.darktest.20090717 
Index: branches/eam_branches/20090820/operations/stdscience/3pi.test.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/3pi.test.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/3pi.test.chip	(revision 25766)
@@ -0,0 +1,12 @@
+#!/bin/csh -f
+
+# run the ThreePi data for June 2009 for the sky region 295.0 - 300.0, -10.0 - -5.0
+
+set options = "-simple -dbname gpc1 -definebyquery"
+set options = "$options -ra_min 295.0 -ra_max 300.0 -decl_min -20.0 -decl_max -15.0"
+set options = "$options -set_end_stage warp -set_tess_id RINGS.V0 -set_reduction STDSCIENCE_DARKTEST -comment ThreePi%"
+set options = "$options -dateobs_begin 2009-04-01T00:00:00 -dateobs_end 2009-07-01T00:00:00"
+# set options = "$options -pretend"
+
+# June 2009 (only g & r in this region & time range)
+chiptool $options -set_label stdscience.darktest.20090717.v2  -set_workdir neb://@HOST@.0/gpc1/stdscience.darktest.20090717 
Index: branches/eam_branches/20090820/operations/stdscience/3pi.test.dm
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/3pi.test.dm	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/3pi.test.dm	(revision 25766)
@@ -0,0 +1,54 @@
+#!/bin/csh -f
+
+if ($#argv != 1) then
+  echo "USAGE: 3pi.test.dm (version)"
+  exit 2
+endif
+set got_version = 0
+
+# run the ThreePi data for June 2009 for the sky region 295.0 - 300.0, -10.0 - -5.0
+
+if (0) then
+set options = "-simple -dbname gpc1 -definewarpwarp"
+set options = "$options -ra_min 295.0 -ra_max 300.0 -decl_min -20.0 -decl_max -15.0"
+set options = "$options -distance 0.1"
+set options = "$options -timediff 1800"
+set options = "$options -reduction WARPWARP"
+set options = "$options -good_frac 0.2"
+set options = "$options -rerun -available"
+# set options = "$options -pretend"
+endif
+
+if ("$1" == "test.v2 done") then
+  set options = "$options -input_label stdscience.darktest.20090717.v2"
+  set options = "$options -template_label stdscience.darktest.20090717.v2"
+  set options = "$options -label stdscience.darktest.20090717.v2"
+  set got_version = 1
+endif
+
+if ("$1" == "test.v0 done") then
+  set options = "$options -input_label ThreePi.S00.200906.v1"
+  set options = "$options -template_label ThreePi.S00.200906.v1"
+  set options = "$options -label stdscience.darktest.20090717.v0"
+  set got_version = 1
+endif
+
+if ("$1" == "magic.v0 done") then
+  set label = stdscience.darktest.20090717.v0
+  magictool -dbname gpc1 -definebyquery -workdir /data/ipp023.0/gpc1_destreak/$label -rerun -label $label -diff_label $label
+  exit 0
+endif
+
+if ("$1" == "magic.v2 done") then
+  set label = stdscience.darktest.20090717.v2
+  magictool -dbname gpc1 -definebyquery -workdir /data/ipp023.0/gpc1_destreak/$label -rerun -label $label -diff_label $label
+  exit 0
+endif
+
+if ($got_version == 0) then
+  echo "unknown version $1 (allowed: test.v0, test.v2)"
+  exit 2
+endif
+
+# June 2009 (only g & r in this region & time range)
+difftool $options -workdir neb://@HOST@.0/gpc1/stdscience.darktest.20090717 
Index: branches/eam_branches/20090820/operations/stdscience/heather/md08.v2.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/heather/md08.v2.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/heather/md08.v2.chip	(revision 25766)
@@ -0,0 +1,54 @@
+#!/bin/csh -f
+
+# run the MD08 data for April, May, June and July 2009:
+
+set options = "-simple -dbname gpc1 -definebyquery -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0 -comment MD08% -filter i.00000"
+
+# July 2209:
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-01T00:00:00 -dateobs_end 2009-07-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090701.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-02T00:00:00 -dateobs_end 2009-07-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090702.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-03T00:00:00 -dateobs_end 2009-07-03T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090703.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-04T00:00:00 -dateobs_end 2009-07-04T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090704.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-05T00:00:00 -dateobs_end 2009-07-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090705.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-06T00:00:00 -dateobs_end 2009-07-06T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090706.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-07T00:00:00 -dateobs_end 2009-07-07T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090707.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-08T00:00:00 -dateobs_end 2009-07-08T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090708.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-09T00:00:00 -dateobs_end 2009-07-09T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090709.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-17T00:00:00 -dateobs_end 2009-07-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090717.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-22T00:00:00 -dateobs_end 2009-07-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090722.stdsci.v2
+
+# June 2009:
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-02T00:00:00 -dateobs_end 2009-06-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090602.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-05T00:00:00 -dateobs_end 2009-06-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090605.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-11T00:00:00 -dateobs_end 2009-06-11T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090611.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-14T00:00:00 -dateobs_end 2009-06-14T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090614.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-15T00:00:00 -dateobs_end 2009-06-15T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090615.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-18T00:00:00 -dateobs_end 2009-06-18T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090618.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-25T00:00:00 -dateobs_end 2009-06-25T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090625.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-27T00:00:00 -dateobs_end 2009-06-27T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090627.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-28T00:00:00 -dateobs_end 2009-06-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090628.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-29T00:00:00 -dateobs_end 2009-06-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090629.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-30T00:00:00 -dateobs_end 2009-06-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090630.stdsci.v2 
+
+# May 2009:
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-01T00:00:00 -dateobs_end 2009-05-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090501.stdsci.v2
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-02T00:00:00 -dateobs_end 2009-05-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090502.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-05T00:00:00 -dateobs_end 2009-05-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090505.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-06T00:00:00 -dateobs_end 2009-05-06T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090506.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-10T00:00:00 -dateobs_end 2009-05-10T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090510.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-22T00:00:00 -dateobs_end 2009-05-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090522.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-28T00:00:00 -dateobs_end 2009-05-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090528.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-31T00:00:00 -dateobs_end 2009-05-31T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090531.stdsci.v2 
+
+# April 2009:
+chiptool $options -set_label MD08.200904.v2 -dateobs_begin 2009-04-19T00:00:00 -dateobs_end 2009-04-19T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090419.stdsci.v2 
+chiptool $options -set_label MD08.200904.v2 -dateobs_begin 2009-04-20T00:00:00 -dateobs_end 2009-04-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090420.stdsci.v2 
+chiptool $options -set_label MD08.200904.v2 -dateobs_begin 2009-04-29T00:00:00 -dateobs_end 2009-04-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090429.stdsci.v2 
+chiptool $options -set_label MD08.200904.v2 -dateobs_begin 2009-04-30T00:00:00 -dateobs_end 2009-04-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090430.stdsci.v2 
Index: branches/eam_branches/20090820/operations/stdscience/heather/md08.v2.stk
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/heather/md08.v2.stk	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/heather/md08.v2.stk	(revision 25766)
@@ -0,0 +1,139 @@
+#!/bin/csh -f
+
+set mode = stack
+
+if ("$mode" == "stack") then 
+  # we are making a stack using the best seeing data availble from April-July 2009.
+  # label these MD08.200906.v2 for convenience...
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label 20090807.MD09.v2 \
+   -workdir neb://@HOST@.0/gpc1/20090807.MD09.v2 \
+   -select_label 20090807.MD09 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 6.0 \
+   -select_filter g.00000 \
+   -min_num 4
+   -pretend 
+    
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter r.00000 \
+   -min_num 4
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter i.00000 \
+   -min_num 4
+
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter z.00000 \
+   -min_num 4
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter y.00000 \
+   -min_num 4
+  
+  exit 0; 
+endif # end of stacks
+
+if ("$mode" == "diff") then 
+  # generate diffs using above stacks
+  
+  # diffs for July (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200907.v2 \
+     -workdir neb://@HOST@.0/gpc1/200907.stdsci.v2 \
+     -warp_label MD08.200907.v2 \
+     -stack_label MD08.200907.v2 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for June (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200906.v2 \
+     -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+     -warp_label MD08.200906.v2 \
+     -stack_label MD08.200906.v2 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for May (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200905.v2 \
+     -workdir neb://@HOST@.0/gpc1/200905.stdsci.v2 \
+     -warp_label MD08.200905.v2 \
+     -stack_label MD08.200906.v2 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for April (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200904.v2 \
+     -workdir neb://@HOST@.0/gpc1/200904.stdsci.v2 \
+     -warp_label MD08.200904.v2 \
+     -stack_label MD08.200906.v2 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  exit 0;
+endif # end of diffs
+
+if ("$mode" == "magic") then
+
+  # magic for April data
+   magictool -dbname gpc1 -definebyquery \
+   -workdir /data/ipp050.0/gpc1_destreak/MD08.200904.stdsci.v2 \
+   -rerun -label MD08.200904.v2 \
+   -diff_label MD08.200904.v2
+
+  # magic for May data
+  magictool -dbname gpc1 -definebyquery \
+  -workdir /data/ipp050.0/gpc1_destreak/MD08.200905.stdsci.v2 \
+  -rerun -label MD08.200905.v2 \
+  -diff_label MD08.200905.v2
+
+  # magic for June data
+   magictool -dbname gpc1 -definebyquery \
+   -workdir /data/ipp050.0/gpc1_destreak/MD08.200906.stdsci.v2 \
+   -rerun -label MD08.200906.v2 \
+   -diff_label MD08.200906.v2
+
+  # magic for July data
+   magictool -dbname gpc1 -definebyquery \
+   -workdir /data/ipp050.0/gpc1_destreak/MD08.200907.stdsci.v2 \
+   -rerun -label MD08.200907.v2 \
+   -diff_label MD08.200907.v2
+
+
+
+
+  exit 0
+endif # end of magic section
Index: branches/eam_branches/20090820/operations/stdscience/input
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/input	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/input	(revision 25766)
@@ -0,0 +1,195 @@
+
+macro setup
+  module pantasks.pro
+
+  module chip.pro
+  module camera.pro
+  module fake.pro
+  module warp.pro
+  module stack.pro
+  module diff.pro
+  module magic.pro
+  
+  # turn destreaking off. we are running this in a separate pantasks for now
+  magic.ds.off
+
+  # module survey.pro
+
+  module site.mhpcc.pro
+
+  init.copy.mhpcc on
+  queueload tmp -x "cat $MODULES:0/ipphosts.mhpcc.config"
+  ipptool2book tmp ipphosts -key camera
+
+  # XXX merge the above into init.site more cleanly (careful with summit copy stuff)
+  # init.site (we do not use init.site because it loads the hosts)
+
+  add.database gpc1
+  add.label dummy
+  set.poll 100
+end
+
+macro set.poll
+  if ($0 != 2)
+    echo "USAGE:set.poll (value)"
+    break
+  end
+ 
+  $POLLLIMIT = $1
+end
+
+macro get.poll
+  echo "poll limit: $POLLLIMIT"
+end
+
+macro load.hosts.wave1
+  controller host add ipp005 -threads 4
+  controller host add ipp006 -threads 4
+# controller host add ipp007 -threads 4 (respawning?)
+# controller host add ipp008 -threads 4 (flaky)
+  controller host add ipp009 -threads 4
+  controller host add ipp010 -threads 4
+  controller host add ipp011 -threads 4
+  controller host add ipp012 -threads 4
+  controller host add ipp013 -threads 4
+# controller host add ipp014 -threads 4
+# controller host add ipp016 -threads 4 (flaky)
+  controller host add ipp017 -threads 4
+# controller host add ipp018 -threads 4 (flaky)
+# controller host add ipp019 -threads 4 (nebulous)
+  controller host add ipp020 -threads 4
+  controller host add ipp021 -threads 4
+end
+
+macro load.hosts.wave2
+  controller host add ipp015 -threads 4
+  controller host add ipp017 -threads 4
+  controller host add ipp023 -threads 4
+  controller host add ipp024 -threads 4
+  controller host add ipp026 -threads 4
+  controller host add ipp027 -threads 4
+  controller host add ipp028 -threads 4
+  controller host add ipp029 -threads 4
+  controller host add ipp030 -threads 4
+  controller host add ipp031 -threads 4
+  controller host add ipp032 -threads 4
+  controller host add ipp033 -threads 4
+  controller host add ipp034 -threads 4
+  controller host add ipp035 -threads 4
+  controller host add ipp036 -threads 4
+end
+
+macro load.hosts.wave3
+  controller host add ipp038 -threads 4
+  controller host add ipp039 -threads 4
+  controller host add ipp040 -threads 4
+  controller host add ipp041 -threads 4
+  controller host add ipp042 -threads 4
+  controller host add ipp043 -threads 4
+  controller host add ipp044 -threads 4
+  controller host add ipp045 -threads 4
+  controller host add ipp046 -threads 4
+  controller host add ipp047 -threads 4
+  controller host add ipp048 -threads 4
+  controller host add ipp049 -threads 4
+  controller host add ipp050 -threads 4
+  controller host add ipp051 -threads 4
+  controller host add ipp052 -threads 4
+  controller host add ipp053 -threads 4
+end
+
+macro load.hosts.compute
+  controller host add ippc00 -threads 4
+  controller host add ippc01 -threads 4
+  controller host add ippc02 -threads 4
+  controller host add ippc03 -threads 4
+  controller host add ippc04 -threads 4
+  controller host add ippc05 -threads 4
+  controller host add ippc06 -threads 4
+# controller host add ippc07 -threads 4 (pantasks - register)
+  controller host add ippc08 -threads 4
+  controller host add ippc09 -threads 4
+# controller host add ippc10 -threads 4 (pantasks - stdscience)
+  controller host add ippc11 -threads 4
+  controller host add ippc12 -threads 4
+  controller host add ippc13 -threads 4
+  controller host add ippc14 -threads 4
+  controller host add ippc15 -threads 4
+  controller host add ippc16 -threads 4
+  controller host add ippc17 -threads 4
+  controller host add ippc18 -threads 4
+  controller host add ippc19 -threads 4
+end
+
+macro show.book
+  if ($0 != 2)
+   echo "USAGE: show.book (book)"
+   break
+  end
+
+  book npages $1 -var npages
+  for i 0 $npages
+    book getpage $1 $i -var pagename
+    book listpage $1 $pagename
+  end
+
+  echo "npages: $npages"
+end
+
+macro del.page.from.book
+  if ($0 != 3)
+   echo "USAGE: show.book (book) (page)"
+   break
+  end
+
+  book delpage $1 $2
+end
+
+macro chip.revert.on
+  task chip.revert
+    active true
+  end
+end
+
+macro chip.revert.off
+  task chip.revert
+    active false
+  end
+end
+
+macro warp.revert.on
+  task warp.revert.warped
+    active true
+  end
+  task warp.revert.overlap
+    active true
+  end
+end
+
+macro warp.revert.off
+  task warp.revert.warped
+    active false
+  end
+  task warp.revert.overlap
+    active false
+  end
+end
+
+macro adjust.magic
+  task magic.tree.run
+    periods -poll 0.5
+    periods -exec 1.0
+  end
+  task magic.process.run
+    periods -poll 0.5
+    periods -exec 1.0
+  end
+  task magic.tree.load
+    periods -poll 1.0
+    periods -exec 5.0
+  end
+  task magic.process.load
+    periods -poll 1.0
+    periods -exec 5.0
+  end
+end
Index: branches/eam_branches/20090820/operations/stdscience/input2
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/input2	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/input2	(revision 25766)
@@ -0,0 +1,114 @@
+
+macro setup
+  module pantasks.pro
+
+#  module chip.pro
+#  module camera.pro
+#  module fake.pro
+  module warp.pro
+#  module diff.pro
+
+  # module survey.pro
+
+  module site.mhpcc.pro
+
+  init.copy.mhpcc on
+  queueload tmp -x "cat $MODULES:0/ipphosts.mhpcc.config"
+  ipptool2book tmp ipphosts -key camera
+
+  # XXX merge the above into init.site more cleanly (careful with summit copy stuff)
+  # init.site (we do not use init.site because it loads the hosts)
+
+  add.database gpc1
+  add.label dummy
+  set.poll 100
+end
+
+macro set.poll
+  if ($0 != 2)
+    echo "USAGE:set.poll (value)"
+    break
+  end
+ 
+  $POLLLIMIT = $1
+end
+
+macro get.poll
+  echo "poll limit: $POLLLIMIT"
+end
+
+macro load.hosts
+  controller host add ipp005 -threads 4
+  controller host add ipp006 -threads 4
+  controller host add ipp007 -threads 4
+# controller host add ipp008 (flaky)
+  controller host add ipp009 -threads 4
+  controller host add ipp010 -threads 4
+  controller host add ipp011 -threads 4
+  controller host add ipp012 -threads 4
+  controller host add ipp013 -threads 4
+# controller host add ipp014 (flaky)
+  controller host add ipp015 -threads 4
+# controller host add ipp016 (flaky)
+  controller host add ipp017 -threads 4
+  controller host add ipp018 -threads 4
+# controller host add ipp019 (nebulous)
+  controller host add ipp020 -threads 4
+  controller host add ipp021 -threads 4
+  controller host add ipp023 -threads 4
+  controller host add ipp024 -threads 4
+  controller host add ipp025 -threads 4
+  controller host add ipp026 -threads 4
+  controller host add ipp027 -threads 4
+  controller host add ipp028 -threads 4
+  controller host add ipp029 -threads 4
+  controller host add ipp030 -threads 4
+  controller host add ipp031 -threads 4
+  controller host add ipp032 -threads 4
+  controller host add ipp033 -threads 4
+  controller host add ipp034 -threads 4
+  controller host add ipp035 -threads 4
+  controller host add ipp036 -threads 4
+end
+
+macro load.hosts.wave2
+  controller host add ipp015 -threads 4
+  controller host add ipp017 -threads 4
+  controller host add ipp023 -threads 4
+  controller host add ipp024 -threads 4
+  controller host add ipp026 -threads 4
+  controller host add ipp027 -threads 4
+  controller host add ipp028 -threads 4
+  controller host add ipp029 -threads 4
+  controller host add ipp030 -threads 4
+  controller host add ipp031 -threads 4
+  controller host add ipp032 -threads 4
+  controller host add ipp033 -threads 4
+  controller host add ipp034 -threads 4
+  controller host add ipp035 -threads 4
+  controller host add ipp036 -threads 4
+end
+
+macro show.book
+  if ($0 != 2)
+   echo "USAGE: show.book (book)"
+   break
+  end
+
+  book npages $1 -var npages
+  for i 0 $npages
+    book getpage $1 $i -var pagename
+    book listpage $1 $pagename
+  end
+
+  echo "npages: $npages"
+end
+
+macro del.page.from.book
+  if ($0 != 3)
+   echo "USAGE: show.book (book) (page)"
+   break
+  end
+
+  book delpage $1 $2
+end
Index: branches/eam_branches/20090820/operations/stdscience/notes.txt
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/notes.txt	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/notes.txt	(revision 25766)
@@ -0,0 +1,7 @@
+Re-process diffs from ThreePi_SouthernRegion and ThreePi_NorthernRegion with improved convolution choice algorithm (trunk@r25120) by PAP:
+
+difftool -definewarpwarp -distance 0.1 -good_frac 0.1 -timediff 3600 -input_label ThreePi_SouthernRegion.090724 -template_label ThreePi_SouthernRegion.090724 -label ThreePi_SouthernRegion.090818 -workdir neb://@HOST@.0/gpc1/ThreePi_SouthernRegion.090818 -dbname gpc1
+difftool -definewarpwarp -distance 0.1 -good_frac 0.1 -timediff 3600 -input_label ThreePi_NorthernRegion.090729 -template_label ThreePi_NorthernRegion.090729 -label ThreePi_NorthernRegion.090818 -workdir neb://@HOST@.0/gpc1/ThreePi_NorthernRegion.090818 -dbname gpc1
+
+
+
Index: branches/eam_branches/20090820/operations/stdscience/ptolemy.rc
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/ptolemy.rc	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/ptolemy.rc	(revision 25766)
@@ -0,0 +1,5 @@
+
+PANTASKS_SERVER_STDOUT  pantasks.stdout.log
+PANTASKS_SERVER_STDERR  pantasks.stderr.log
+PANTASKS_SERVER         ippc10
+PASSWORD                foobar
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md06.v0.cmds
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md06.v0.cmds	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md06.v0.cmds	(revision 25766)
@@ -0,0 +1,26 @@
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD06.200904.v0 -dateobs_begin 2009-04-19T00:00:00 -dateobs_end 2009-04-19T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090419.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD06.200904.v0 -dateobs_begin 2009-04-20T00:00:00 -dateobs_end 2009-04-20T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090420.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD06.200904.v0 -dateobs_begin 2009-04-21T00:00:00 -dateobs_end 2009-04-21T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090421.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD06.200904.v0 -dateobs_begin 2009-04-26T00:00:00 -dateobs_end 2009-04-26T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090426.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD06.200904.v0 -dateobs_begin 2009-04-27T00:00:00 -dateobs_end 2009-04-27T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090427.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD06.200904.v0 -dateobs_begin 2009-04-30T00:00:00 -dateobs_end 2009-04-30T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090430.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200905.v0 -dateobs_begin 2009-05-01T00:00:00 -dateobs_end 2009-05-01T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090501.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200905.v0 -dateobs_begin 2009-05-02T00:00:00 -dateobs_end 2009-05-02T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090502.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200905.v0 -dateobs_begin 2009-05-05T00:00:00 -dateobs_end 2009-05-05T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090505.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200905.v0 -dateobs_begin 2009-05-29T00:00:00 -dateobs_end 2009-05-29T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090529.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-02T00:00:00 -dateobs_end 2009-06-02T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090602.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-05T00:00:00 -dateobs_end 2009-06-05T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090605.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-07T00:00:00 -dateobs_end 2009-06-07T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090607.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-08T00:00:00 -dateobs_end 2009-06-08T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090608.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-09T00:00:00 -dateobs_end 2009-06-09T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090609.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-11T00:00:00 -dateobs_end 2009-06-11T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090611.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-12T00:00:00 -dateobs_end 2009-06-12T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090612.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-14T00:00:00 -dateobs_end 2009-06-14T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090614.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-18T00:00:00 -dateobs_end 2009-06-18T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090618.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-19T00:00:00 -dateobs_end 2009-06-19T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090619.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD06.200906.v0 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -comment 'MD06%' -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v0 -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md07.v0.cmds
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md07.v0.cmds	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md07.v0.cmds	(revision 25766)
@@ -0,0 +1,29 @@
+# chiptool -dbname gpc1 -definebyquery -set_label MD07.200904.v0 -dateobs_begin 2009-04-19T00:00:00 -dateobs_end 2009-04-19T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090419.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD07.200904.v0 -dateobs_begin 2009-04-26T00:00:00 -dateobs_end 2009-04-26T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090426.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD07.200904.v0 -dateobs_begin 2009-04-29T00:00:00 -dateobs_end 2009-04-29T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090429.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200905.v0 -dateobs_begin 2009-05-01T00:00:00 -dateobs_end 2009-05-01T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090501.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200905.v0 -dateobs_begin 2009-05-02T00:00:00 -dateobs_end 2009-05-02T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090502.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200905.v0 -dateobs_begin 2009-05-05T00:00:00 -dateobs_end 2009-05-05T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090505.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200905.v0 -dateobs_begin 2009-05-06T00:00:00 -dateobs_end 2009-05-06T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090506.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200905.v0 -dateobs_begin 2009-05-10T00:00:00 -dateobs_end 2009-05-10T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090510.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200905.v0 -dateobs_begin 2009-05-22T00:00:00 -dateobs_end 2009-05-22T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090522.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200905.v0 -dateobs_begin 2009-05-28T00:00:00 -dateobs_end 2009-05-28T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090528.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200905.v0 -dateobs_begin 2009-05-31T00:00:00 -dateobs_end 2009-05-31T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090531.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-01T00:00:00 -dateobs_end 2009-06-01T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090601.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-02T00:00:00 -dateobs_end 2009-06-02T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090602.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-05T00:00:00 -dateobs_end 2009-06-05T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090605.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-07T00:00:00 -dateobs_end 2009-06-07T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090607.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-08T00:00:00 -dateobs_end 2009-06-08T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090608.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-09T00:00:00 -dateobs_end 2009-06-09T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090609.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-11T00:00:00 -dateobs_end 2009-06-11T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090611.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-12T00:00:00 -dateobs_end 2009-06-12T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090612.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-14T00:00:00 -dateobs_end 2009-06-14T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090614.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-18T00:00:00 -dateobs_end 2009-06-18T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090618.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
+chiptool -simple -dbname gpc1 -definebyquery -set_label MD07.200906.v0 -dateobs_begin 2009-06-25T00:00:00 -dateobs_end 2009-06-25T23:59:59 -comment 'MD07%' -set_workdir neb://@HOST@.0/gpc1/20090625.stdsci.v0 -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md08.v0.cmds
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md08.v0.cmds	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md08.v0.cmds	(revision 25766)
@@ -0,0 +1,26 @@
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD08.200904.v0 -dateobs_begin 2009-04-19T00:00:00 -dateobs_end 2009-04-19T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090419.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD08.200904.v0 -dateobs_begin 2009-04-20T00:00:00 -dateobs_end 2009-04-20T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090420.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD08.200904.v0 -dateobs_begin 2009-04-29T00:00:00 -dateobs_end 2009-04-29T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090429.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -pretend -dbname gpc1 -definebyquery -set_label MD08.200904.v0 -dateobs_begin 2009-04-30T00:00:00 -dateobs_end 2009-04-30T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090430.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD08.200905.v0 -dateobs_begin 2009-05-01T00:00:00 -dateobs_end 2009-05-01T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090501.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD08.200905.v0 -dateobs_begin 2009-05-02T00:00:00 -dateobs_end 2009-05-02T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090502.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD08.200905.v0 -dateobs_begin 2009-05-05T00:00:00 -dateobs_end 2009-05-05T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090505.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD08.200905.v0 -dateobs_begin 2009-05-06T00:00:00 -dateobs_end 2009-05-06T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090506.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD08.200905.v0 -dateobs_begin 2009-05-10T00:00:00 -dateobs_end 2009-05-10T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090510.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD08.200905.v0 -dateobs_begin 2009-05-22T00:00:00 -dateobs_end 2009-05-22T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090522.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD08.200905.v0 -dateobs_begin 2009-05-28T00:00:00 -dateobs_end 2009-05-28T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090528.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD08.200905.v0 -dateobs_begin 2009-05-31T00:00:00 -dateobs_end 2009-05-31T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090531.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-02T00:00:00 -dateobs_end 2009-06-02T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090602.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-05T00:00:00 -dateobs_end 2009-06-05T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090605.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-11T00:00:00 -dateobs_end 2009-06-11T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090611.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-14T00:00:00 -dateobs_end 2009-06-14T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090614.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-15T00:00:00 -dateobs_end 2009-06-15T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090615.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-18T00:00:00 -dateobs_end 2009-06-18T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090618.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
+# chiptool -dbname gpc1 -definebyquery -set_label MD08.200906.v0 -dateobs_begin 2009-06-25T00:00:00 -dateobs_end 2009-06-25T23:59:59 -comment 'MD08%' -set_workdir neb://@HOST@.0/gpc1/20090625.stdsci.v0 -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md08.v0.stk
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md08.v0.stk	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md08.v0.stk	(revision 25766)
@@ -0,0 +1,56 @@
+
+# stacktool -definebyquery -workdir neb://@HOST@.0/gpc1/noise.20090618 -label noise.20090618 -select_label noise.20090618 -select_good_frac_min 0.5 -select_filter g.00000 -min_num 4 -dbname gpc1
+
+magictool -definebyquery -workdir /data/ipp023.0/gpc1_destreak/MD08.200906.stdsci.v0 -rerun -label MD08.200906.v0 -diff_label MD08.200906.v0
+
+stacktool -dbname gpc1 -definebyquery \
+ -label MD08.200906.v0 \
+ -workdir neb://@HOST@.0/gpc1/200906.stdsci.v0 \
+ -select_label MD08.200906.v0 \
+ -select_dateobs_begin 2009-06-01T00:00:00 \
+ -select_dateobs_end 2009-06-26T00:00:00 \
+ -select_good_frac_min 0.5 \
+ -select_filter g.00000 \
+ -min_num 4
+
+stacktool -dbname gpc1 -definebyquery \
+ -label MD08.200906.v0 \
+ -workdir neb://@HOST@.0/gpc1/200906.stdsci.v0 \
+ -select_label MD08.200906.v0 \
+ -select_dateobs_begin 2009-06-01T00:00:00 \
+ -select_dateobs_end 2009-06-26T00:00:00 \
+ -select_good_frac_min 0.5 \
+ -select_filter r.00000 \
+ -min_num 4
+
+stacktool -dbname gpc1 -definebyquery \
+ -label MD08.200906.v0 \
+ -workdir neb://@HOST@.0/gpc1/200906.stdsci.v0 \
+ -select_label MD08.200906.v0 \
+ -select_dateobs_begin 2009-06-01T00:00:00 \
+ -select_dateobs_end 2009-06-26T00:00:00 \
+ -select_good_frac_min 0.5 \
+ -select_filter i.00000 \
+ -min_num 4
+
+stacktool -dbname gpc1 -definebyquery \
+ -label MD08.200906.v0 \
+ -workdir neb://@HOST@.0/gpc1/200906.stdsci.v0 \
+ -select_label MD08.200906.v0 \
+ -select_dateobs_begin 2009-06-01T00:00:00 \
+ -select_dateobs_end 2009-06-26T00:00:00 \
+ -select_good_frac_min 0.5 \
+ -select_filter z.00000 \
+ -min_num 4
+
+stacktool -dbname gpc1 -definebyquery \
+ -label MD08.200906.v0 \
+ -workdir neb://@HOST@.0/gpc1/200906.stdsci.v0 \
+ -select_label MD08.200906.v0 \
+ -select_dateobs_begin 2009-06-01T00:00:00 \
+ -select_dateobs_end 2009-06-26T00:00:00 \
+ -select_good_frac_min 0.5 \
+ -select_filter y.00000 \
+ -min_num 4
+
+difftool -definewarpstack -workdir neb://@HOST@.0/gpc1/200806.stdsci.v0 -label MD08.200906.v0 -warp_label MD08.200906.v0 -good_frac 0.2 -stack_label MD08.200906.v0 -dbname gpc1 -rerun -available
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md09.v0.cmds
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md09.v0.cmds	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/md09.v0.cmds	(revision 25766)
@@ -0,0 +1,4 @@
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD09.200906.v0 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -comment 'MD09%' -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v0 -set_end_stage warp -set_tess_id MD09 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD09.200906.v0 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -comment 'MD09%' -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v0 -set_end_stage warp -set_tess_id MD09 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD09.200906.v0 -dateobs_begin 2009-06-09T00:00:00 -dateobs_end 2009-06-09T23:59:59 -comment 'MD09%' -set_workdir neb://@HOST@.0/gpc1/20090609.stdsci.v0 -set_end_stage warp -set_tess_id MD09 -set_reduction STDSCIENCE_V0
+# chiptool -simple -dbname gpc1 -definebyquery -set_label MD09.200906.v0 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -comment 'MD09%' -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v0 -set_end_stage warp -set_tess_id MD09 -set_reduction STDSCIENCE_V0
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd06
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd06	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd06	(revision 25766)
@@ -0,0 +1,49 @@
+#!/usr/bin/env perl
+#
+# file to queue chipRuns for the MD06 exposures from April 1 - June 25 2009
+# md08 fields
+my @dates = qw(
+2009-04-19     
+2009-04-20     
+2009-04-21     
+2009-04-26     
+2009-04-27     
+2009-04-30     
+2009-05-01     
+2009-05-02     
+2009-05-05     
+2009-05-29     
+2009-06-02     
+2009-06-03     
+2009-06-04     
+2009-06-05     
+2009-06-07     
+2009-06-08     
+2009-06-09     
+2009-06-11     
+2009-06-12     
+2009-06-13     
+2009-06-14     
+2009-06-17     
+2009-06-18     
+2009-06-19     
+2009-06-20     
+2009-06-22     
+);
+
+my $field = 'MD06';
+
+foreach my $date (@dates) {
+
+    my $tag = $date;
+    $tag =~ s/\-//g;
+
+    my $block = substr($date, 0, 7);
+    $block =~ s/\-//g;
+    $label = "$field.$block.v0";
+
+    my $command = "chiptool -pretend -dbname gpc1 -definebyquery -set_label $label -dateobs_begin ${date}T00:00:00 -dateobs_end ${date}T23:59:59 -comment \'$field%\' -set_workdir neb://\@HOST\@.0/gpc1/$tag.stdsci.v0 -set_end_stage warp -set_tess_id $field -set_reduction STDSCIENCE_V0";
+
+    print "$command\n";
+}
+
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd07
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd07	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd07	(revision 25766)
@@ -0,0 +1,52 @@
+#!/usr/bin/env perl
+#
+# file to queue chipRuns for the MD07 exposures from April 1 - June 25 2009
+# md07 fields
+my @dates = qw(
+ 2009-04-19     
+ 2009-04-26     
+ 2009-04-29     
+ 2009-05-01     
+ 2009-05-02     
+ 2009-05-05     
+ 2009-05-06     
+ 2009-05-10     
+ 2009-05-22     
+ 2009-05-28     
+ 2009-05-31     
+ 2009-06-01     
+ 2009-06-02     
+ 2009-06-03     
+ 2009-06-04     
+ 2009-06-05     
+ 2009-06-07     
+ 2009-06-08     
+ 2009-06-09     
+ 2009-06-11     
+ 2009-06-12     
+ 2009-06-13     
+ 2009-06-14     
+ 2009-06-16     
+ 2009-06-17     
+ 2009-06-18     
+ 2009-06-20     
+ 2009-06-22     
+ 2009-06-25     
+);
+
+my $field = 'MD07';
+
+foreach my $date (@dates) {
+
+    my $tag = $date;
+    $tag =~ s/\-//g;
+
+    my $block = substr($date, 0, 7);
+    $block =~ s/\-//g;
+    $label = "$field.$block.v0";
+
+    my $command = "chiptool -pretend -dbname gpc1 -definebyquery -set_label $label -dateobs_begin ${date}T00:00:00 -dateobs_end ${date}T23:59:59 -comment \'$field%\' -set_workdir neb://\@HOST\@.0/gpc1/$tag.stdsci.v0 -set_end_stage warp -set_tess_id $field -set_reduction STDSCIENCE_V0";
+
+    print "$command\n";
+}
+
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd08
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd08	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd08	(revision 25766)
@@ -0,0 +1,48 @@
+#!/usr/bin/env perl
+#
+# file to queue chipRuns for the MD08 exposures from April 1 - June 25 2009
+# md08 fields
+my @dates = qw(
+2009-04-19
+2009-04-20
+2009-04-29
+2009-04-30
+2009-05-01
+2009-05-02
+2009-05-05
+2009-05-06
+2009-05-10
+2009-05-22
+2009-05-28
+2009-05-31
+2009-06-02
+2009-06-03
+2009-06-04
+2009-06-05
+2009-06-11
+2009-06-13
+2009-06-14
+2009-06-15
+2009-06-16
+2009-06-17
+2009-06-18
+2009-06-20
+2009-06-22
+2009-06-25
+);
+
+my $field = 'MD08';
+
+foreach my $date (@dates) {
+
+    my $tag = $date;
+    $tag =~ s/\-//g;
+
+    my $block = substr($date, 0, 7);
+    $block =~ s/\-//g;
+    $label = "$field.$block.v0";
+
+    my $command = "chiptool -pretend -dbname gpc1 -definebyquery -set_label $label -dateobs_begin ${date}T00:00:00 -dateobs_end ${date}T23:59:59 -comment \'$field%\' -set_workdir neb://\@HOST\@.0/gpc1/$tag.stdsci.v0 -set_end_stage warp -set_tess_id $field -set_reduction STDSCIENCE_V0";
+
+    print "$command\n";
+}
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd09
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd09	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v0/queuemd09	(revision 25766)
@@ -0,0 +1,27 @@
+#!/usr/bin/env perl
+#
+# file to queue chipRuns for the MD09 exposures from April 1 - June 25 2009
+# md09 fields
+my @dates = qw(
+ 2009-06-03     
+ 2009-06-04     
+ 2009-06-09     
+ 2009-06-16     
+);
+
+my $field = 'MD09';
+
+foreach my $date (@dates) {
+
+    my $tag = $date;
+    $tag =~ s/\-//g;
+
+    my $block = substr($date, 0, 7);
+    $block =~ s/\-//g;
+    $label = "$field.$block.v0";
+
+    my $command = "chiptool -pretend -dbname gpc1 -definebyquery -set_label $label -dateobs_begin ${date}T00:00:00 -dateobs_end ${date}T23:59:59 -comment \'$field%\' -set_workdir neb://\@HOST\@.0/gpc1/$tag.stdsci.v0 -set_end_stage warp -set_tess_id $field -set_reduction STDSCIENCE_V0";
+
+    print "$command\n";
+}
+
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md06.v1.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md06.v1.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md06.v1.chip	(revision 25766)
@@ -0,0 +1,37 @@
+#!/bin/csh -f
+
+# run the MD06 data for April, May, and June 2009:
+
+set options = "-simple -dbname gpc1 -definebyquery -set_end_stage warp -set_tess_id MD06 -set_reduction STDSCIENCE_V0 -comment MD06%"
+
+# April 2009:
+chiptool $options -set_label MD06.200904.v1 -dateobs_begin 2009-04-19T00:00:00 -dateobs_end 2009-04-19T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090419.stdsci.v1
+chiptool $options -set_label MD06.200904.v1 -dateobs_begin 2009-04-20T00:00:00 -dateobs_end 2009-04-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090420.stdsci.v1
+chiptool $options -set_label MD06.200904.v1 -dateobs_begin 2009-04-21T00:00:00 -dateobs_end 2009-04-21T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090421.stdsci.v1
+chiptool $options -set_label MD06.200904.v1 -dateobs_begin 2009-04-26T00:00:00 -dateobs_end 2009-04-26T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090426.stdsci.v1
+chiptool $options -set_label MD06.200904.v1 -dateobs_begin 2009-04-27T00:00:00 -dateobs_end 2009-04-27T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090427.stdsci.v1
+chiptool $options -set_label MD06.200904.v1 -dateobs_begin 2009-04-30T00:00:00 -dateobs_end 2009-04-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090430.stdsci.v1
+
+# May 2009:
+chiptool $options -set_label MD06.200905.v1 -dateobs_begin 2009-05-01T00:00:00 -dateobs_end 2009-05-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090501.stdsci.v1
+chiptool $options -set_label MD06.200905.v1 -dateobs_begin 2009-05-02T00:00:00 -dateobs_end 2009-05-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090502.stdsci.v1
+chiptool $options -set_label MD06.200905.v1 -dateobs_begin 2009-05-05T00:00:00 -dateobs_end 2009-05-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090505.stdsci.v1
+chiptool $options -set_label MD06.200905.v1 -dateobs_begin 2009-05-29T00:00:00 -dateobs_end 2009-05-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090529.stdsci.v1
+
+# June 2009:
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-02T00:00:00 -dateobs_end 2009-06-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090602.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-05T00:00:00 -dateobs_end 2009-06-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090605.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-07T00:00:00 -dateobs_end 2009-06-07T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090607.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-08T00:00:00 -dateobs_end 2009-06-08T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090608.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-09T00:00:00 -dateobs_end 2009-06-09T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090609.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-11T00:00:00 -dateobs_end 2009-06-11T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090611.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-12T00:00:00 -dateobs_end 2009-06-12T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090612.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-14T00:00:00 -dateobs_end 2009-06-14T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090614.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-18T00:00:00 -dateobs_end 2009-06-18T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090618.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-19T00:00:00 -dateobs_end 2009-06-19T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090619.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v1
+chiptool $options -set_label MD06.200906.v1 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v1
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md06.v1.stk
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md06.v1.stk	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md06.v1.stk	(revision 25766)
@@ -0,0 +1,125 @@
+#!/bin/csh -f
+
+set mode = none
+
+if ("$mode" == "stack") then
+  # we are making a stack using the best seeing data availble from April-June 2009.
+  # label these MD06.200906.v1 for convenience...
+
+  # g.00000 : May - June : 25 total -> 15 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD06.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD06.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter g.00000 \
+   -min_num 4
+  
+  # r.00000 : May - June : 56 total -> 31 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD06.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD06.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter r.00000 \
+   -min_num 4
+  
+  # i.00000 : May - June : 101 total -> 44 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD06.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD06.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter i.00000 \
+   -min_num 4
+  
+  # z.00000 : May - June : 95 total -> 30 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD06.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD06.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter z.00000 \
+   -min_num 4
+  
+  # y.00000 : May - June :14 total -> 14 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD06.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD06.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter y.00000 \
+   -min_num 4
+  
+  exit 0; 
+endif # end of stack section
+
+if ("$mode" == "diff") then 
+  # generate diffs using above stacks
+  
+  # diffs for June (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD06.200906.v1 \
+     -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+     -warp_label MD06.200906.v1 \
+     -stack_label MD06.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+  
+  # diffs for May (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD06.200905.v1 \
+     -workdir neb://@HOST@.0/gpc1/200905.stdsci.v1 \
+     -warp_label MD06.200905.v1 \
+     -stack_label MD06.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+  
+  # diffs for April (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD06.200904.v1 \
+     -workdir neb://@HOST@.0/gpc1/200904.stdsci.v1 \
+     -warp_label MD06.200904.v1 \
+     -stack_label MD06.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+  
+  exit 0;
+endif # end of diffs
+
+if ("$mode" == "magic") then
+  # magic for April data
+  # magictool -dbname gpc1 -definebyquery \
+  # -workdir /data/ipp050.0/gpc1_destreak/MD06.200904.stdsci.v1 \
+  # -rerun -label MD06.200904.v1 \
+  # -diff_label MD06.200904.v1
+
+  # magic for May data
+  magictool -dbname gpc1 -definebyquery \
+  -workdir /data/ipp050.0/gpc1_destreak/MD06.200905.stdsci.v1 \
+  -rerun -label MD06.200905.v1 \
+  -diff_label MD06.200905.v1
+
+  # magic for June data
+  # magictool -dbname gpc1 -definebyquery \
+  # -workdir /data/ipp050.0/gpc1_destreak/MD06.200906.stdsci.v1 \
+  # -rerun -label MD06.200906.v1 \
+  # -diff_label MD06.200906.v1
+
+  exit 0;
+endif # end of magic section
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md07.v1.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md07.v1.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md07.v1.chip	(revision 25766)
@@ -0,0 +1,43 @@
+#!/bin/csh -f
+
+# run the MD07 data for April, May, and June 2009:
+
+set options = "-simple -dbname gpc1 -definebyquery -set_end_stage warp -set_tess_id MD07 -set_reduction STDSCIENCE_V0 -comment MD07%"
+
+# April 2009:
+chiptool $options -set_label MD07.200904.v1 -dateobs_begin 2009-04-17T00:00:00 -dateobs_end 2009-04-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090417.stdsci.v1
+chiptool $options -set_label MD07.200904.v1 -dateobs_begin 2009-04-19T00:00:00 -dateobs_end 2009-04-19T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090419.stdsci.v1
+chiptool $options -set_label MD07.200904.v1 -dateobs_begin 2009-04-26T00:00:00 -dateobs_end 2009-04-26T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090426.stdsci.v1
+chiptool $options -set_label MD07.200904.v1 -dateobs_begin 2009-04-29T00:00:00 -dateobs_end 2009-04-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090429.stdsci.v1
+
+# May 2009:
+chiptool $options -set_label MD07.200905.v1 -dateobs_begin 2009-05-01T00:00:00 -dateobs_end 2009-05-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090501.stdsci.v1
+chiptool $options -set_label MD07.200905.v1 -dateobs_begin 2009-05-02T00:00:00 -dateobs_end 2009-05-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090502.stdsci.v1
+chiptool $options -set_label MD07.200905.v1 -dateobs_begin 2009-05-05T00:00:00 -dateobs_end 2009-05-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090505.stdsci.v1
+chiptool $options -set_label MD07.200905.v1 -dateobs_begin 2009-05-06T00:00:00 -dateobs_end 2009-05-06T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090506.stdsci.v1
+chiptool $options -set_label MD07.200905.v1 -dateobs_begin 2009-05-10T00:00:00 -dateobs_end 2009-05-10T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090510.stdsci.v1
+chiptool $options -set_label MD07.200905.v1 -dateobs_begin 2009-05-22T00:00:00 -dateobs_end 2009-05-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090522.stdsci.v1
+chiptool $options -set_label MD07.200905.v1 -dateobs_begin 2009-05-28T00:00:00 -dateobs_end 2009-05-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090528.stdsci.v1
+chiptool $options -set_label MD07.200905.v1 -dateobs_begin 2009-05-31T00:00:00 -dateobs_end 2009-05-31T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090531.stdsci.v1
+
+# June 2009:
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-01T00:00:00 -dateobs_end 2009-06-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090601.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-02T00:00:00 -dateobs_end 2009-06-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090602.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-05T00:00:00 -dateobs_end 2009-06-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090605.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-07T00:00:00 -dateobs_end 2009-06-07T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090607.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-08T00:00:00 -dateobs_end 2009-06-08T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090608.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-09T00:00:00 -dateobs_end 2009-06-09T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090609.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-11T00:00:00 -dateobs_end 2009-06-11T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090611.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-12T00:00:00 -dateobs_end 2009-06-12T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090612.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-14T00:00:00 -dateobs_end 2009-06-14T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090614.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-18T00:00:00 -dateobs_end 2009-06-18T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090618.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-25T00:00:00 -dateobs_end 2009-06-25T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090625.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-28T00:00:00 -dateobs_end 2009-06-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090628.stdsci.v1
+chiptool $options -set_label MD07.200906.v1 -dateobs_begin 2009-06-30T00:00:00 -dateobs_end 2009-06-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090630.stdsci.v1
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md07.v1.stk
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md07.v1.stk	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md07.v1.stk	(revision 25766)
@@ -0,0 +1,127 @@
+#!/bin/csh -f
+
+set mode = none
+
+if ("$mode" == "stack") then 
+  # we are making a stack using the best seeing data availble from April-June 2009.
+  # label these MD07.200906.v1 for convenience...
+  
+  # g.00000 : May - June : 32 total -> 16 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD07.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD07.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter g.00000 \
+   -min_num 4
+  
+  # r.00000 : May - June : 46 total -> 21 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD07.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD07.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 6.5 \
+   -select_filter r.00000 \
+   -min_num 4
+  
+  # i.00000 : May - June : 97 total -> 36 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD07.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD07.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter i.00000 \
+   -min_num 4
+  
+  # z.00000 : May - June : 76 total -> 17 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD07.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD07.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.2 \
+   -select_filter z.00000 \
+   -min_num 4
+  
+  # y.00000 : May - June : 23 total -> 18 in stack
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD07.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD07.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter y.00000 \
+   -min_num 4
+  
+  exit 0; 
+
+endif # end of stack section
+
+if ("$mode" == "diff") then 
+  # generate diffs using above stacks
+  
+  # diffs for June (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD07.200906.v1 \
+     -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+     -warp_label MD07.200906.v1 \
+     -stack_label MD07.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+  
+  # diffs for May (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD07.200905.v1 \
+     -workdir neb://@HOST@.0/gpc1/200905.stdsci.v1 \
+     -warp_label MD07.200905.v1 \
+     -stack_label MD07.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+  
+  # diffs for April (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD07.200904.v1 \
+     -workdir neb://@HOST@.0/gpc1/200904.stdsci.v1 \
+     -warp_label MD07.200904.v1 \
+     -stack_label MD07.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  exit 0;
+endif # end of diff section
+
+if ("$mode" == "magic") then
+
+  # magic for April data
+  # magictool -dbname gpc1 -definebyquery \
+  # -workdir /data/ipp050.0/gpc1_destreak/MD07.200904.stdsci.v1 \
+  # -rerun -label MD07.200904.v1 \
+  # -diff_label MD07.200904.v1
+
+  # magic for May data
+  magictool -dbname gpc1 -definebyquery \
+  -workdir /data/ipp050.0/gpc1_destreak/MD07.200905.stdsci.v1 \
+  -rerun -label MD07.200905.v1 \
+  -diff_label MD07.200905.v1
+
+  # magic for June data
+  # magictool -dbname gpc1 -definebyquery \
+  # -workdir /data/ipp050.0/gpc1_destreak/MD07.200906.stdsci.v1 \
+  # -rerun -label MD07.200906.v1 \
+  # -diff_label MD07.200906.v1
+
+  exit 0;
+endif # end of magic section
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md08.v1.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md08.v1.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md08.v1.chip	(revision 25766)
@@ -0,0 +1,41 @@
+#!/bin/csh -f
+
+# run the MD08 data for April, May, and June 2009:
+
+set options = "-simple -dbname gpc1 -definebyquery -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0 -comment MD08%"
+
+# June 2009:
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-02T00:00:00 -dateobs_end 2009-06-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090602.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-05T00:00:00 -dateobs_end 2009-06-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090605.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-11T00:00:00 -dateobs_end 2009-06-11T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090611.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-14T00:00:00 -dateobs_end 2009-06-14T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090614.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-15T00:00:00 -dateobs_end 2009-06-15T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090615.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-18T00:00:00 -dateobs_end 2009-06-18T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090618.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-25T00:00:00 -dateobs_end 2009-06-25T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090625.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-27T00:00:00 -dateobs_end 2009-06-27T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090627.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-28T00:00:00 -dateobs_end 2009-06-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090628.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-29T00:00:00 -dateobs_end 2009-06-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090629.stdsci.v1 
+chiptool $options -set_label MD08.200906.v1 -dateobs_begin 2009-06-30T00:00:00 -dateobs_end 2009-06-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090630.stdsci.v1 
+
+# May 2009:
+chiptool $options -set_label MD08.200905.v1 -dateobs_begin 2009-05-01T00:00:00 -dateobs_end 2009-05-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090501.stdsci.v1
+chiptool $options -set_label MD08.200905.v1 -dateobs_begin 2009-05-02T00:00:00 -dateobs_end 2009-05-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090502.stdsci.v1 
+chiptool $options -set_label MD08.200905.v1 -dateobs_begin 2009-05-05T00:00:00 -dateobs_end 2009-05-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090505.stdsci.v1 
+chiptool $options -set_label MD08.200905.v1 -dateobs_begin 2009-05-06T00:00:00 -dateobs_end 2009-05-06T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090506.stdsci.v1 
+chiptool $options -set_label MD08.200905.v1 -dateobs_begin 2009-05-10T00:00:00 -dateobs_end 2009-05-10T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090510.stdsci.v1 
+chiptool $options -set_label MD08.200905.v1 -dateobs_begin 2009-05-22T00:00:00 -dateobs_end 2009-05-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090522.stdsci.v1 
+chiptool $options -set_label MD08.200905.v1 -dateobs_begin 2009-05-28T00:00:00 -dateobs_end 2009-05-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090528.stdsci.v1 
+chiptool $options -set_label MD08.200905.v1 -dateobs_begin 2009-05-31T00:00:00 -dateobs_end 2009-05-31T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090531.stdsci.v1 
+
+# April 2009:
+chiptool $options -set_label MD08.200904.v1 -dateobs_begin 2009-04-19T00:00:00 -dateobs_end 2009-04-19T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090419.stdsci.v1 
+chiptool $options -set_label MD08.200904.v1 -dateobs_begin 2009-04-20T00:00:00 -dateobs_end 2009-04-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090420.stdsci.v1 
+chiptool $options -set_label MD08.200904.v1 -dateobs_begin 2009-04-29T00:00:00 -dateobs_end 2009-04-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090429.stdsci.v1 
+chiptool $options -set_label MD08.200904.v1 -dateobs_begin 2009-04-30T00:00:00 -dateobs_end 2009-04-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090430.stdsci.v1 
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md08.v1.stk
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md08.v1.stk	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md08.v1.stk	(revision 25766)
@@ -0,0 +1,121 @@
+#!/bin/csh -f
+
+set mode = none
+
+if ("$mode" == "stack") then 
+  # we are making a stack using the best seeing data availble from April-June 2009.
+  # label these MD08.200906.v1 for convenience...
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD08.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 6.0 \
+   -select_filter g.00000 \
+   -min_num 4
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD08.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter r.00000 \
+   -min_num 4
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD08.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter i.00000 \
+   -min_num 4
+
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD08.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter z.00000 \
+   -min_num 4
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD08.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-01T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter y.00000 \
+   -min_num 4
+  
+  exit 0; 
+endif # end of stacks
+
+if ("$mode" == "diff") then 
+  # generate diffs using above stacks
+  
+  # diffs for June (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200906.v1 \
+     -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+     -warp_label MD08.200906.v1 \
+     -stack_label MD08.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for May (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200905.v1 \
+     -workdir neb://@HOST@.0/gpc1/200905.stdsci.v1 \
+     -warp_label MD08.200905.v1 \
+     -stack_label MD08.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for April (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200904.v1 \
+     -workdir neb://@HOST@.0/gpc1/200904.stdsci.v1 \
+     -warp_label MD08.200904.v1 \
+     -stack_label MD08.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  exit 0;
+endif # end of diffs
+
+if ("$mode" == "magic") then
+
+  # magic for April data
+  # magictool -dbname gpc1 -definebyquery \
+  # -workdir /data/ipp050.0/gpc1_destreak/MD08.200904.stdsci.v1 \
+  # -rerun -label MD08.200904.v1 \
+  # -diff_label MD08.200904.v1
+
+  # magic for May data
+  magictool -dbname gpc1 -definebyquery \
+  -workdir /data/ipp050.0/gpc1_destreak/MD08.200905.stdsci.v1 \
+  -rerun -label MD08.200905.v1 \
+  -diff_label MD08.200905.v1
+
+  # magic for June data
+  # magictool -dbname gpc1 -definebyquery \
+  # -workdir /data/ipp050.0/gpc1_destreak/MD08.200906.stdsci.v1 \
+  # -rerun -label MD08.200906.v1 \
+  # -diff_label MD08.200906.v1
+
+  exit 0
+endif # end of magic section
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md09.v1.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md09.v1.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md09.v1.chip	(revision 25766)
@@ -0,0 +1,15 @@
+#!/bin/csh -f
+
+# run the MD09 data for April, May, and June 2009:
+
+set options = "-simple -dbname gpc1 -definebyquery -set_end_stage warp -set_tess_id MD09 -set_reduction STDSCIENCE_V0 -comment MD09%"
+
+# June (+ early July) 2009:
+chiptool $options -set_label MD09.200906.v1 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v1 
+chiptool $options -set_label MD09.200906.v1 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v1 
+chiptool $options -set_label MD09.200906.v1 -dateobs_begin 2009-06-09T00:00:00 -dateobs_end 2009-06-09T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090609.stdsci.v1 
+chiptool $options -set_label MD09.200906.v1 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v1 
+chiptool $options -set_label MD09.200906.v1 -dateobs_begin 2009-06-29T00:00:00 -dateobs_end 2009-06-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090629.stdsci.v1 
+chiptool $options -set_label MD09.200906.v1 -dateobs_begin 2009-06-30T00:00:00 -dateobs_end 2009-06-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090630.stdsci.v1 
+chiptool $options -set_label MD09.200907.v1 -dateobs_begin 2009-07-01T00:00:00 -dateobs_end 2009-07-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090701.stdsci.v1 
+chiptool $options -set_label MD09.200907.v1 -dateobs_begin 2009-07-02T00:00:00 -dateobs_end 2009-07-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090702.stdsci.v1 
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md09.v1.stk
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md09.v1.stk	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v1/md09.v1.stk	(revision 25766)
@@ -0,0 +1,110 @@
+#!/bin/csh -f
+
+set mode = magic
+
+if ("$mode" == "stack") then 
+  # we are making a stack using the best seeing data availble from April-July 03 2009.
+  # label these MD09.200906.v1 for convenience...
+  
+  # 8 / 8 exp < 9.4 pix
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD09.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD09.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-03T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 9.5 \
+   -select_filter g.00000 \
+   -min_num 4
+  
+  # 4 / 4 exp < 8.2 pix
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD09.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD09.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-03T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 8.2 \
+   -select_filter r.00000 \
+   -min_num 4
+  
+  # 21 / 24 < 6.0 pix
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD09.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD09.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-03T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 6.0 \
+   -select_filter i.00000 \
+   -min_num 4
+
+  # 13 / 13 < 5.3 pix
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD09.200906.v1 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+   -select_label MD09.20090%.v1 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-03T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.3 \
+   -select_filter z.00000 \
+   -min_num 4
+  
+  # stacktool -dbname gpc1 -definebyquery \
+  #  -label MD09.200906.v1 \
+  #  -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+  #  -select_label MD09.20090%.v1 \
+  #  -select_dateobs_begin 2009-04-01T00:00:00 \
+  #  -select_dateobs_end 2009-07-01T00:00:00 \
+  #  -select_good_frac_min 0.5 \
+  #  -select_fwhm_major_max 5.0 \
+  #  -select_filter y.00000 \
+  #  -min_num 4
+  
+  exit 0; 
+endif # end of stacks
+
+if ("$mode" == "diff") then 
+  # generate diffs using above stacks
+  
+  # diffs for June (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD09.200906.v1 \
+     -workdir neb://@HOST@.0/gpc1/200906.stdsci.v1 \
+     -warp_label MD09.200906.v1 \
+     -stack_label MD09.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for July (vs June) (through July 03)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD09.200907.v1 \
+     -workdir neb://@HOST@.0/gpc1/200907.stdsci.v1 \
+     -warp_label MD09.200907.v1 \
+     -stack_label MD09.200906.v1 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  exit 0;
+endif # end of diffs
+
+if ("$mode" == "magic") then
+
+  # magic for June data
+  magictool -dbname gpc1 -definebyquery \
+  -workdir /data/ipp050.0/gpc1_destreak/MD09.200906.stdsci.v1 \
+  -rerun -label MD09.200906.v1 \
+  -diff_label MD09.200906.v1
+
+  # magic for July data (through July 3)
+  magictool -dbname gpc1 -definebyquery \
+  -workdir /data/ipp050.0/gpc1_destreak/MD09.200907.stdsci.v1 \
+  -rerun -label MD09.200907.v1 \
+  -diff_label MD09.200907.v1
+
+  exit 0
+endif # end of magic section
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v2/md08.v2.chip
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v2/md08.v2.chip	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v2/md08.v2.chip	(revision 25766)
@@ -0,0 +1,54 @@
+#!/bin/csh -f
+
+# run the MD08 data for April, May, June and July 2009:
+
+set options = "-simple -dbname gpc1 -definebyquery -set_end_stage warp -set_tess_id MD08 -set_reduction STDSCIENCE_V0 -comment MD08% -filter i.00000"
+
+# July 2209:
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-01T00:00:00 -dateobs_end 2009-07-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090701.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-02T00:00:00 -dateobs_end 2009-07-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090702.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-03T00:00:00 -dateobs_end 2009-07-03T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090703.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-04T00:00:00 -dateobs_end 2009-07-04T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090704.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-05T00:00:00 -dateobs_end 2009-07-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090705.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-06T00:00:00 -dateobs_end 2009-07-06T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090706.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-07T00:00:00 -dateobs_end 2009-07-07T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090707.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-08T00:00:00 -dateobs_end 2009-07-08T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090708.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-09T00:00:00 -dateobs_end 2009-07-09T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090709.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-17T00:00:00 -dateobs_end 2009-07-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090717.stdsci.v2
+chiptool $options -set_label MD08.200907.v2 -dateobs_begin 2009-07-22T00:00:00 -dateobs_end 2009-07-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090722.stdsci.v2
+
+# June 2009:
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-02T00:00:00 -dateobs_end 2009-06-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090602.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-03T00:00:00 -dateobs_end 2009-06-03T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090603.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-04T00:00:00 -dateobs_end 2009-06-04T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090604.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-05T00:00:00 -dateobs_end 2009-06-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090605.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-11T00:00:00 -dateobs_end 2009-06-11T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090611.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-13T00:00:00 -dateobs_end 2009-06-13T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090613.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-14T00:00:00 -dateobs_end 2009-06-14T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090614.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-15T00:00:00 -dateobs_end 2009-06-15T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090615.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-16T00:00:00 -dateobs_end 2009-06-16T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090616.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-17T00:00:00 -dateobs_end 2009-06-17T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090617.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-18T00:00:00 -dateobs_end 2009-06-18T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090618.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-20T00:00:00 -dateobs_end 2009-06-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090620.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-22T00:00:00 -dateobs_end 2009-06-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090622.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-25T00:00:00 -dateobs_end 2009-06-25T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090625.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-27T00:00:00 -dateobs_end 2009-06-27T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090627.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-28T00:00:00 -dateobs_end 2009-06-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090628.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-29T00:00:00 -dateobs_end 2009-06-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090629.stdsci.v2 
+chiptool $options -set_label MD08.200906.v2 -dateobs_begin 2009-06-30T00:00:00 -dateobs_end 2009-06-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090630.stdsci.v2 
+
+# May 2009:
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-01T00:00:00 -dateobs_end 2009-05-01T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090501.stdsci.v2
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-02T00:00:00 -dateobs_end 2009-05-02T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090502.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-05T00:00:00 -dateobs_end 2009-05-05T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090505.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-06T00:00:00 -dateobs_end 2009-05-06T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090506.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-10T00:00:00 -dateobs_end 2009-05-10T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090510.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-22T00:00:00 -dateobs_end 2009-05-22T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090522.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-28T00:00:00 -dateobs_end 2009-05-28T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090528.stdsci.v2 
+chiptool $options -set_label MD08.200905.v2 -dateobs_begin 2009-05-31T00:00:00 -dateobs_end 2009-05-31T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090531.stdsci.v2 
+
+# April 2009:
+chiptool $options -set_label MD08.200904.v2 -dateobs_begin 2009-04-19T00:00:00 -dateobs_end 2009-04-19T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090419.stdsci.v2 
+chiptool $options -set_label MD08.200904.v2 -dateobs_begin 2009-04-20T00:00:00 -dateobs_end 2009-04-20T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090420.stdsci.v2 
+chiptool $options -set_label MD08.200904.v2 -dateobs_begin 2009-04-29T00:00:00 -dateobs_end 2009-04-29T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090429.stdsci.v2 
+chiptool $options -set_label MD08.200904.v2 -dateobs_begin 2009-04-30T00:00:00 -dateobs_end 2009-04-30T23:59:59 -set_workdir neb://@HOST@.0/gpc1/20090430.stdsci.v2 
Index: branches/eam_branches/20090820/operations/stdscience/stdsci.v2/md08.v2.stk
===================================================================
--- branches/eam_branches/20090820/operations/stdscience/stdsci.v2/md08.v2.stk	(revision 25766)
+++ branches/eam_branches/20090820/operations/stdscience/stdsci.v2/md08.v2.stk	(revision 25766)
@@ -0,0 +1,139 @@
+#!/bin/csh -f
+
+set mode = magic
+
+if ("$mode" == "stack") then 
+  # we are making a stack using the best seeing data availble from April-July 2009.
+  # label these MD08.200906.v2 for convenience...
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 6.0 \
+   -select_filter g.00000 \
+   -min_num 4
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter r.00000 \
+   -min_num 4
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter i.00000 \
+   -min_num 4
+
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.7 \
+   -select_filter z.00000 \
+   -min_num 4
+  
+  stacktool -dbname gpc1 -definebyquery \
+   -label MD08.200906.v2 \
+   -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+   -select_label MD08.20090%.v2 \
+   -select_dateobs_begin 2009-04-01T00:00:00 \
+   -select_dateobs_end 2009-07-31T00:00:00 \
+   -select_good_frac_min 0.5 \
+   -select_fwhm_major_max 5.0 \
+   -select_filter y.00000 \
+   -min_num 4
+  
+  exit 0; 
+endif # end of stacks
+
+if ("$mode" == "diff") then 
+  # generate diffs using above stacks
+  
+  # diffs for July (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200907.v2 \
+     -workdir neb://@HOST@.0/gpc1/200907.stdsci.v2 \
+     -warp_label MD08.200907.v2 \
+     -stack_label MD08.200907.v2 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for June (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200906.v2 \
+     -workdir neb://@HOST@.0/gpc1/200906.stdsci.v2 \
+     -warp_label MD08.200906.v2 \
+     -stack_label MD08.200906.v2 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for May (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200905.v2 \
+     -workdir neb://@HOST@.0/gpc1/200905.stdsci.v2 \
+     -warp_label MD08.200905.v2 \
+     -stack_label MD08.200906.v2 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  # diffs for April (vs June)
+  difftool -dbname gpc1 -definewarpstack \
+     -label MD08.200904.v2 \
+     -workdir neb://@HOST@.0/gpc1/200904.stdsci.v2 \
+     -warp_label MD08.200904.v2 \
+     -stack_label MD08.200906.v2 \
+     -good_frac 0.2 \
+     -rerun -available
+
+  exit 0;
+endif # end of diffs
+
+if ("$mode" == "magic") then
+
+  # magic for April data
+   magictool -dbname gpc1 -definebyquery \
+   -workdir /data/ipp050.0/gpc1_destreak/MD08.200904.stdsci.v2 \
+   -rerun -label MD08.200904.v2 \
+   -diff_label MD08.200904.v2
+
+  # magic for May data
+  magictool -dbname gpc1 -definebyquery \
+  -workdir /data/ipp050.0/gpc1_destreak/MD08.200905.stdsci.v2 \
+  -rerun -label MD08.200905.v2 \
+  -diff_label MD08.200905.v2
+
+  # magic for June data
+   magictool -dbname gpc1 -definebyquery \
+   -workdir /data/ipp050.0/gpc1_destreak/MD08.200906.stdsci.v2 \
+   -rerun -label MD08.200906.v2 \
+   -diff_label MD08.200906.v2
+
+  # magic for July data
+   magictool -dbname gpc1 -definebyquery \
+   -workdir /data/ipp050.0/gpc1_destreak/MD08.200907.stdsci.v2 \
+   -rerun -label MD08.200907.v2 \
+   -diff_label MD08.200907.v2
+
+
+
+
+  exit 0
+endif # end of magic section
Index: branches/eam_branches/20090820/operations/summitcopy/ptolemy.rc
===================================================================
--- branches/eam_branches/20090820/operations/summitcopy/ptolemy.rc	(revision 25206)
+++ branches/eam_branches/20090820/operations/summitcopy/ptolemy.rc	(revision 25766)
@@ -2,5 +2,5 @@
 PANTASKS_SERVER_STDOUT  pantasks.stdout.log
 PANTASKS_SERVER_STDERR  pantasks.stderr.log
-PANTASKS_SERVER         ipp007
+PANTASKS_SERVER         ippc01
 PASSWORD                foobar
 
Index: branches/eam_branches/20090820/ppImage/src/Makefile.am
===================================================================
--- branches/eam_branches/20090820/ppImage/src/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/ppImage/src/Makefile.am	(revision 25766)
@@ -54,4 +54,5 @@
 	ppImageDefineFile.c \
 	ppImageSetMaskBits.c \
+	ppImageBurntoolMask.c \
 	ppImageParityFlip.c \
 	ppImageCheckCTE.c \
Index: branches/eam_branches/20090820/ppImage/src/ppImage.h
===================================================================
--- branches/eam_branches/20090820/ppImage/src/ppImage.h	(revision 25206)
+++ branches/eam_branches/20090820/ppImage/src/ppImage.h	(revision 25766)
@@ -26,4 +26,5 @@
     bool doMaskBuild;                   // Build internal mask
     bool doVarianceBuild;               // Build internal variance map
+    bool doMaskBurntool;                // mask potential burntool trails
     bool doMaskSat;                     // mask saturated pixels
     bool doMaskLow;                     // mask low pixels
@@ -74,5 +75,5 @@
     psImageMaskType darkMask;           // Mask value to give bad dark pixels
     psImageMaskType blankMask;          // Mask value to give blank pixels
-
+    psImageMaskType burntoolMask;       // Suspect pixels that fall where a burntool trail is expected.
     // non-linear correction parameters
     psDataType nonLinearType;
@@ -82,5 +83,5 @@
     // options for the analysis
     pmOverscanOptions *overscan;        // Overscan options
-
+    int burntoolTrails;
     // binning parameters
     int xBin1;                          // x-binning, scale 1
@@ -156,4 +157,6 @@
 bool ppImageCheckCTE(pmConfig *config, ppImageOptions *options, pmFPAview *view);
 
+bool ppImageBurntoolMask(pmConfig *config, ppImageOptions *options, pmFPAview *view, pmReadout *mask);
+
 // Record which detrend file was used for the detrending
 bool ppImageDetrendRecord(
Index: branches/eam_branches/20090820/ppImage/src/ppImageBurntoolMask.c
===================================================================
--- branches/eam_branches/20090820/ppImage/src/ppImageBurntoolMask.c	(revision 25766)
+++ branches/eam_branches/20090820/ppImage/src/ppImageBurntoolMask.c	(revision 25766)
@@ -0,0 +1,100 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* #define PPIMAGE_BURNTOOL_DEBUG 1 */
+
+#include "ppImage.h"
+
+bool ppImageBurntoolMask (pmConfig *config, ppImageOptions *options, pmFPAview *view,pmReadout *mask) {
+  bool status = true;
+  int burntool_cell;
+  /* Find input filename */
+  pmFPAfile *inputFile = psMetadataLookupPtr(&status , config->files, "PPIMAGE.INPUT");
+  if (!status) {
+    psError(PS_ERR_IO,false, "Unable to identify inputFile");
+    return(false);
+  }
+  psFits *fits = inputFile->fits;
+
+  /* Read input header, and find the burntool data table. */
+  if (!psFitsMoveExtName(fits,"burntool_areas")) {
+    psError(PS_ERR_IO,false, "Unable to find extension burntool_areas");
+    return(false);
+  }
+  long Nrows = psFitsTableSize(fits);  
+
+  long row = 0;
+
+  psLogMsg ("ppImageBurntoolMask", 4, "Inside burntool mask %ld", Nrows);
+
+  /* Redirects and Memory juggling. */
+  view->readout = 0;
+  psImage *image = mask->mask;
+
+  
+  /* Set the maskValue from the recipes. */
+  psImageMaskType maskValue = options->burntoolMask;
+#ifdef PPIMAGE_BURNTOOL_DEBUG
+  psLogMsg("ppImageBurntoolMask", 4, "Status: %ld %d\n",Nrows,maskValue);
+#endif
+
+  burntool_cell = view->cell;
+  burntool_cell = (view->cell % 8) * 8 + (view->cell - (view->cell % 8)) / 8;
+  psLogMsg("ppImageBurntoolMask", 4, "Cell mapping: %d %d %d\n",view->cell,burntool_cell,-1);
+  for (row = 0; row < Nrows; row++) {
+    psMetadata *rowMD = psFitsReadTableRow(fits,row);
+
+    if (psMetadataLookupS32(&status,rowMD,"cell") == burntool_cell) {
+      if (((options->burntoolTrails & 0x01)&&(psMetadataLookupS32(&status,rowMD,"nfit") == 0))||
+	  ((options->burntoolTrails & 0x02)&&(psMetadataLookupS32(&status,rowMD,"up") == 1))||
+	  ((options->burntoolTrails & 0x04)&&(psMetadataLookupS32(&status,rowMD,"up") == 0))) {
+	/*       If the fit fails, burntool reports zero here.  This
+		 signifies that it expected to see a trail (else why
+		 fit) but did not find it when it attempted to
+		 correct. */
+#ifdef PPIMAGE_BURNTOOL_DEBUG
+	psLogMsg ("ppImageBurntoolMask", 4, "Masking! %d (%d %d %d) %d %d",
+		  psMetadataLookupS32(&status,rowMD,"cell"),
+		  ((options->burntoolTrails & 0x0001)&&(psMetadataLookupS32(&status,rowMD,"nfit") == 0)),
+		  ((options->burntoolTrails & 0x02)&&(psMetadataLookupS32(&status,rowMD,"up") == 1)),
+		  ((options->burntoolTrails & 0x04)&&(psMetadataLookupS32(&status,rowMD,"up") == 0)),
+		  options->burntoolTrails,
+		  maskValue
+		  );
+#endif
+	for (int i = psMetadataLookupS32(&status,rowMD,"sxfit");
+	     i <= psMetadataLookupS32(&status,rowMD,"exfit");
+	     i++) {
+
+	  if (psMetadataLookupS32(&status,rowMD,"up") == 0) {
+	    for (int j = 0; j <= psMetadataLookupS32(&status,rowMD,"y1p"); j++) {
+/* #ifdef PPIMAGE_BURNTOOL_DEBUG */
+/* 	      psLogMsg("ppImageBurntoolMask", 4, "Noisy!: %d %d %d %d\n", */
+/* 		       i,j,image->data.PS_TYPE_IMAGE_MASK_DATA[j][i],maskValue); */
+/* #endif */
+	      image->data.PS_TYPE_IMAGE_MASK_DATA[j][i] |= maskValue;
+	    }
+	  }
+	  else {
+	    for (int j = psMetadataLookupS32(&status,rowMD,"y1m"); j < image->numRows ; j++) {
+/* #ifdef PPIMAGE_BURNTOOL_DEBUG */
+/* 	      psLogMsg("ppImageBurntoolMask", 4, "Noisy!: %d %d %d %d\n", */
+/* 		       i,j,image->data.PS_TYPE_IMAGE_MASK_DATA[j][i],maskValue); */
+/* #endif */
+	      image->data.PS_TYPE_IMAGE_MASK_DATA[j][i] |= maskValue;
+	    }
+	  }
+	}
+
+      }
+    }
+    psFree(rowMD);
+  }
+
+  return(status);
+}
+	    
+
+
+    
Index: branches/eam_branches/20090820/ppImage/src/ppImageDetrendReadout.c
===================================================================
--- branches/eam_branches/20090820/ppImage/src/ppImageDetrendReadout.c	(revision 25206)
+++ branches/eam_branches/20090820/ppImage/src/ppImageDetrendReadout.c	(revision 25766)
@@ -26,4 +26,8 @@
         pmMaskBadPixels(input, mask, options->maskValue);
     }
+    if (options->doMaskBurntool) {
+      ppImageBurntoolMask(config,options,view,input);
+    }
+
 
 # if 0
Index: branches/eam_branches/20090820/ppImage/src/ppImageOptions.c
===================================================================
--- branches/eam_branches/20090820/ppImage/src/ppImageOptions.c	(revision 25206)
+++ branches/eam_branches/20090820/ppImage/src/ppImageOptions.c	(revision 25766)
@@ -21,4 +21,5 @@
     options->doMaskSat       = false;   // mask saturated pixels
     options->doMaskLow       = false;   // mask low pixels
+    options->doMaskBurntool  = false;   // mask potential burntool trails
     options->doVarianceBuild = false;   // Build internal variance
     options->doMask          = false;   // Mask bad pixels
@@ -64,5 +65,6 @@
     options->blankMask       = 0x00;    // Blank (no data, cell gap) pixels (supplied to pmChipMosaic, pmFPAMosaic)
     options->markValue       = 0x00;    // A safe bit for internal marking
-
+    options->burntoolMask    = 0x00;    // Suspect pixels that fall where a burntool trail is expected.
+    options->burntoolTrails  = 0x07;    // Which types of burntool areas to mask.
     // crosstalk options
     options->doCrosstalkMeasure = false;   // measure crosstalk
@@ -219,4 +221,5 @@
     options->doMaskSat   = psMetadataLookupBool(NULL, recipe, "MASK.SATURATED");
     options->doMaskLow   = psMetadataLookupBool(NULL, recipe, "MASK.LOW");
+    options->doMaskBurntool = psMetadataLookupBool(NULL, recipe, "MASK.BURNTOOL");
     options->doVarianceBuild = psMetadataLookupBool(NULL, recipe, "VARIANCE.BUILD");
 
@@ -245,13 +248,20 @@
     options->applyParity = psMetadataLookupBool(NULL, recipe, "APPLY.CELL.PARITY");
 
+    options->burntoolTrails = psMetadataLookupS32(&status, recipe, "BURNTOOL.TRAILS");
+    fprintf(stderr,"TRAILS: %d %d %d\n",options->burntoolTrails,psMetadataLookupS32(&status,recipe,"BURNTOOL.TRAILS"),status);
+    if (!status) {
+      psWarning("BURNTOOL.TRAILS not found in recipe: setting to default value.\n");
+    }
+    
     // binned image options
     options->xBin1 = psMetadataLookupS32(&status, recipe, "BIN1.XBIN");
     if (!status) {
         psWarning("BIN1.XBIN not found in recipe: setting to default value.\n");
+	options->xBin1 = 4;
     }
     options->yBin1 = psMetadataLookupS32(&status, recipe, "BIN1.YBIN");
     if (!status) {
         psWarning("BIN1.YBIN not found in recipe: setting to default value.\n");
-        options->yBin1 = 16;
+        options->yBin1 = 4;
     }
 
Index: branches/eam_branches/20090820/ppImage/src/ppImageReplaceBackground.c
===================================================================
--- branches/eam_branches/20090820/ppImage/src/ppImageReplaceBackground.c	(revision 25206)
+++ branches/eam_branches/20090820/ppImage/src/ppImageReplaceBackground.c	(revision 25766)
@@ -74,5 +74,5 @@
     pmReadout *modelRO = NULL;
     pmFPAfile *modelFile = psMetadataLookupPtr(&status, config->files, "PSPHOT.BACKMDL"); // Background model
-    if (modelFile) {
+    if (modelFile && modelFile->fpa) {
         modelRO = pmFPAviewThisReadout(&roView, modelFile->fpa); // Background model
     }
Index: branches/eam_branches/20090820/ppImage/src/ppImageSetMaskBits.c
===================================================================
--- branches/eam_branches/20090820/ppImage/src/ppImageSetMaskBits.c	(revision 25206)
+++ branches/eam_branches/20090820/ppImage/src/ppImageSetMaskBits.c	(revision 25766)
@@ -38,4 +38,8 @@
     psAssert (options->lowMask, "low mask not set");
 
+    // mask for suspect regions due to burntool
+    options->burntoolMask = pmConfigMaskGet("BURNTOOL",config);
+    psAssert (options->burntoolMask, "burntool mask not set");
+    
     // save MASK and MARK on the PSPHOT recipe
     psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
Index: branches/eam_branches/20090820/ppMops/ICDlite.txt
===================================================================
--- branches/eam_branches/20090820/ppMops/ICDlite.txt	(revision 25206)
+++ branches/eam_branches/20090820/ppMops/ICDlite.txt	(revision 25766)
@@ -79,4 +79,5 @@
  * ASTRORMS added to make absolute (i.e., across exposures) astrometry errors more accurate
  * DE_MAGnn and DE_EFFnn replace DE1 through DE10, which were never well defined
+ * Removed LIMITMAG, which was never well defined, and is unnecessary given the DE_MAGnn and DE_EFFnn
 
 === Table ===
@@ -119,32 +120,73 @@
 
 
+=== Example ===
 
-
-                            Table 3: IPP-MOPS Transient Detection Keywords
-FITS Keyword      Precision                     Description
-FPA ID            char(20)                      IPP-assigned identifier that can be used to trace back to this FPA
-MJD-OBS           F64                           midpoint time of the exposure as a MJD and day fraction
-RA                HH:MM:SS.SSS                 field center RA at exposure midpoint, string
-DEC               sDD:MM:SS (s is + or -) field center declination at exposure midpoint, string
-EXPTIME           F64                          exposure time in seconds
-ROTANGLE          F64                          image rotation of the y-axis in degrees, from local N toward E
-FILTER            char(3)                       effective filter used for the exposure, one of g, r, i, z, y, B, V, w
-AIRMASS           F64                          airmass at exposure midpoint
-LIMITMAG          F64                           limiting magnitude of detections for this FPA
-DE1 through DE10  F64                           detection efficiency coefficients
-OBSCODE           char(5)                       MPC three-character observatory code
-TEL ALT           F64                          telescope altitude at exposure midpoint, in degrees
-TEL AZ            F64                          telescope azimuth at exposure midpoint, in degrees
-                         Table 4: IPP-MOPS Transient Detection Table Columns
-             Column       Precision Description
-             RA DEG       F64          detection center coordinates in degrees
-             RA SIG       F64          error in the detection center, in degrees
-             DEC DEG      F64          detection center coordinates in degrees
-             DEC SIG      F64          error in the detection center, in degrees
-             FLUX         F64          flux
-             FLUX SIG     F64          error in the flux value
-             STARPSF      F64          probability that the PSF matches a starlike PSF
-             ANG          F64          detectionâs elongation angle in degrees, local N toward E
-             ANG SIG      F64          error in the angle, in degrees
-             LEN          F64          elongation length of the detection in degrees
-             LEN SIG      F64          error in the length, in degrees
+{{{
+XTENSION= 'BINTABLE'           / binary table extension
+BITPIX  =                    8 / 8-bit bytes
+NAXIS   =                    2 / 2-dimensional binary table
+NAXIS1  =                   72 / width of table in bytes
+NAXIS2  =                42032 / number of rows in table
+PCOUNT  =                    0 / size of special data area
+GCOUNT  =                    1 / one data group (required keyword)
+TFIELDS =                   13 / number of fields in each row
+TTYPE1  = 'RA      '           / label for field   1
+TFORM1  = '1D      '           / data format of field: 8-byte DOUBLE
+TTYPE2  = 'RA_ERR  '           / label for field   2
+TFORM2  = '1D      '           / data format of field: 8-byte DOUBLE
+TTYPE3  = 'DEC     '           / label for field   3
+TFORM3  = '1D      '           / data format of field: 8-byte DOUBLE
+TTYPE4  = 'DEC_ERR '           / label for field   4
+TFORM4  = '1D      '           / data format of field: 8-byte DOUBLE
+TTYPE5  = 'MAG     '           / label for field   5
+TFORM5  = '1E      '           / data format of field: 4-byte REAL
+TTYPE6  = 'MAG_ERR '           / label for field   6
+TFORM6  = '1E      '           / data format of field: 4-byte REAL
+TTYPE7  = 'STARPSF '           / label for field   7
+TFORM7  = '1E      '           / data format of field: 4-byte REAL
+TTYPE8  = 'ANGLE   '           / label for field   8
+TFORM8  = '1E      '           / data format of field: 4-byte REAL
+TTYPE9  = 'ANGLE_ERR'          / label for field   9
+TFORM9  = '1E      '           / data format of field: 4-byte REAL
+TTYPE10 = 'LENGTH  '           / label for field  10
+TFORM10 = '1E      '           / data format of field: 4-byte REAL
+TTYPE11 = 'LENGTH_ERR'         / label for field  11
+TFORM11 = '1E      '           / data format of field: 4-byte REAL
+TTYPE12 = 'FLAGS   '           / label for field  12
+TFORM12 = '1J      '           / data format of field: 4-byte INTEGER
+TZERO12 =           2147483648 / offset for unsigned integers
+TSCAL12 =                    1 / data are not scaled
+TTYPE13 = 'DIFF_SKYFILE_ID'    / label for field  13
+TFORM13 = '1K      '           / data format of field: 8-byte INTEGER
+SWSOURCE= '60eb6cdc-a59c-4636-a4e0-dba66a9721fd' / Software source
+SWVERSN = 'branches/pap_mops/ppMops@25227' / Software version
+HISTORY ppMops at 2009-09-02T03:48:46.695783
+HISTORY psLib version: branches/pap_mops/psLib@25227
+HISTORY psLib source: 60eb6cdc-a59c-4636-a4e0-dba66a9721fd
+HISTORY ppMops version: branches/pap_mops/ppMops@25227
+HISTORY ppMops source: 60eb6cdc-a59c-4636-a4e0-dba66a9721fd
+EXP_NAME= 'o4995g0129o'        / Exposure name
+EXP_ID  =                77164 / Exposure identifier
+CHIP_ID =                24019 / Chip stage identifier
+CAM_ID  =                17726 / Cam stage identifier
+FAKE_ID =                10227 / Fake stage identifier
+WARP_ID =                 8842 / Warp stage identifier
+DIFF_ID =                    0 / Diff stage identifier
+DIFF_POS=                    F / Positive subtraction?
+MJD-OBS =     54995.4740598313 / MJD of exposure midpoint
+RA      = '18:25:01.988'       / Right Ascension of boresight
+DEC     = '-17:20:40.069'      / Declination of boresight
+TEL_ALT =            51.951873 / Telescope altitude
+TEL_AZ  =           179.483883 / Telescope azimuth
+EXPTIME =                  38. / Exposure time (sec)
+ROTANGLE=             333.1039 / Rotator position angle
+FILTER  = 'r.00000 '           / Filter name
+AIRMASS =                1.269 / Airmass of exposure
+OBSCODE = 'F51     '           / IAU Observatory code
+SEEING  =             1.678401 / Mean seeing
+MAGZP   =             28.65226 / Magnitude zero point
+MAGZPERR=             0.353063 / Error in magnitude zero point
+ASTRORMS=            0.3111496 / RMS of astrometric fit
+EXTNAME = 'MOPS_TRANSIENT_DETECTIONS'
+END
+}}}
Index: branches/eam_branches/20090820/ppMops/src/Makefile.am
===================================================================
--- branches/eam_branches/20090820/ppMops/src/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/ppMops/src/Makefile.am	(revision 25766)
@@ -28,5 +28,9 @@
 	ppMops.c		\
 	ppMopsVersion.c		\
-	ppMopsData.c			
+	ppMopsArguments.c	\
+	ppMopsDetections.c	\
+	ppMopsRead.c		\
+	ppMopsWrite.c		\
+	ppMopsMerge.c
 
 noinst_HEADERS = \
Index: branches/eam_branches/20090820/ppMops/src/ppMops.c
===================================================================
--- branches/eam_branches/20090820/ppMops/src/ppMops.c	(revision 25206)
+++ branches/eam_branches/20090820/ppMops/src/ppMops.c	(revision 25766)
@@ -6,22 +6,42 @@
 int main(int argc, char *argv[])
 {
-    if (argc != 7) {
-        fprintf(stderr, "Insufficient arguments.\n");
-        fprintf(stderr, "Usage: %s DETECTIONS ZP EXP_ID EXP_NAME DIRECTION OUTPUT\n", argv[0]);
+    psLibInit(NULL);
+
+    ppMopsArguments *args = ppMopsArgumentsParse(argc, argv); // Parsed arguments
+    if (!args) {
+        psErrorStackPrint(stderr, "Error parsing arguments");
         exit(PS_EXIT_CONFIG_ERROR);
     }
 
-    ppMopsData *data = ppMopsDataAlloc(); // Configuration data
-    data->detections = psStringCopy(argv[1]);
-    data->zp = atof(argv[2]);
-    data->exp_id = atoll(argv[3]);
-    data->exp_name = psStringCopy(argv[4]);
-    data->direction = atoi(argv[5]);
-    data->output = psStringCopy(argv[6]);
-
-    if (!isfinite(data->zp)) {
-        psErrorStackPrint(stderr, "Zero point is unknown\n");
-        exit(PS_EXIT_CONFIG_ERROR);
-    }
+    psArray *detections = ppMopsRead(args); // Detections from each input
+    if (!detections) {
+        psErrorStackPrint(stderr, "Unable to read detections");
+        exit(PS_EXIT_SYS_ERROR);
+    }
+
+    ppMopsDetections *merged = ppMopsMerge(detections); // Merged detections
+    psFree(detections);
+    if (!merged) {
+        psErrorStackPrint(stderr, "Unable to merge detections");
+        exit(PS_EXIT_SYS_ERROR);
+    }
+
+    if (!ppMopsWrite(merged, args)) {
+        psErrorStackPrint(stderr, "Unable to write detections");
+        exit(PS_EXIT_SYS_ERROR);
+    }
+
+    psFree(merged);
+    psFree(args);
+
+    psLibFinalize();
+
+    return PS_EXIT_SUCCESS;
+}
+
+
+#if 0
+    ps
+
 
     psArray *detections = NULL;         // Detections
@@ -211,4 +231,4 @@
     psFree(data);
 
-    return PS_EXIT_SUCCESS;
-}
+#endif
+
Index: branches/eam_branches/20090820/ppMops/src/ppMops.h
===================================================================
--- branches/eam_branches/20090820/ppMops/src/ppMops.h	(revision 25206)
+++ branches/eam_branches/20090820/ppMops/src/ppMops.h	(revision 25766)
@@ -11,17 +11,63 @@
                      PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_SKY_FAILURE) // Flags to exclude
 
-
 // Configuration data
 typedef struct {
-    psString detections;                // Detections filename
-    float zp;                           // Magnitude zero point
+    psArray *input;                     // Input filenames
+    psString exp_name;                  // Exposure name
     psS64 exp_id;                       // Exposure identifier
-    psString exp_name;                  // Exposure name
-    bool direction;                     // Direction of subtraction, 1=positive, 0=negative
+    psS64 chip_id;                      // Chip stage identifier
+    psS64 cam_id;                       // Camera stage identifier
+    psS64 fake_id;                      // Fake stage identifier
+    psS64 warp_id;                      // Warp stage identifier
+    psS64 diff_id;                      // Diff stage identifier
+    bool positive;                      // Sense of subtraction, T=positive, F=negative
+    float zp, zpErr;                    // Magnitude zero point and error
+    float rmsAstrom;                    // Astrometric solution RMS
     psString output;                    // Output filename
-} ppMopsData;
+} ppMopsArguments;
 
-// Allocator
-ppMopsData *ppMopsDataAlloc(void);
+/// Parse arguments
+ppMopsArguments *ppMopsArgumentsParse(int argc, char *argv[]);
+
+typedef struct {
+    psString raBoresight, decBoresight; // RA,Dec of telescope boresight
+    psString filter;                    // Filter for exposure
+    float airmass;                      // Airmass of exposure
+    float exptime;                      // Exposure time
+    double posangle;                    // Position angle
+    double alt, az;                     // Telescope altitude and azimuth
+    double mjd;                         // Modified Julian Date
+    float seeing;                       // Seeing of exposure
+    long num;                           // Number of detections
+    psVector *x, *y;                    // Image coordinates
+    psVector *ra, *dec;                 // Sky coordinates
+    psVector *raErr, *decErr;           // Error in sky coordinates
+    psVector *mag, *magErr;             // Magnitude and associated error
+    psVector *extended;                 // Measure of extendedness
+    psVector *angle, *angleErr;         // Angle of trail and associated error
+    psVector *length, *lengthErr;       // Length of trail and associated error
+    psVector *flags;                    // psphot flags
+    psVector *diffSkyfileId;            // Identifier for source image
+    psVector *naxis1, *naxis2;          // Size of image
+    psVector *mask;                     // Mask for detections
+} ppMopsDetections;
+
+ppMopsDetections *ppMopsDetectionsAlloc(long num);
+
+/// Copy a detection
+bool ppMopsDetectionsCopySingle(ppMopsDetections *target, const ppMopsDetections *source, long index);
+
+/// Purge the detections list of masked detections
+bool ppMopsDetectionsPurge(ppMopsDetections *detections);
+
+
+/// Read detections
+psArray *ppMopsRead(const ppMopsArguments *args);
+
+/// Merge detections
+ppMopsDetections *ppMopsMerge(const psArray *detections);
+
+/// Write detections
+bool ppMopsWrite(const ppMopsDetections *detections, const ppMopsArguments *args);
 
 
Index: branches/eam_branches/20090820/ppMops/src/ppMopsArguments.c
===================================================================
--- branches/eam_branches/20090820/ppMops/src/ppMopsArguments.c	(revision 25766)
+++ branches/eam_branches/20090820/ppMops/src/ppMopsArguments.c	(revision 25766)
@@ -0,0 +1,107 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppMops.h"
+
+// Print usage information and die
+static void usage(const char *program,  // Name of the program
+                  psMetadata *arguments // Command-line arguments
+                  )
+{
+    fprintf(stderr, "\nPan-STARRS IPP-MOPS detection translator\n\n");
+    fprintf(stderr, "Usage: %s INPUT_LIST OUTPUT_NAME\n", program);
+    fprintf(stderr, "\n");
+    psArgumentHelp(arguments);
+    psLibFinalize();
+    exit(PS_EXIT_CONFIG_ERROR);
+}
+
+static void mopsArgumentsFree(ppMopsArguments *args)
+{
+    psFree(args->input);
+    psFree(args->exp_name);
+    psFree(args->output);
+    return;
+}
+
+ppMopsArguments *ppMopsArgumentsAlloc(void)
+{
+    ppMopsArguments *args = psAlloc(sizeof(ppMopsArguments)); // Data to return
+    psMemSetDeallocator(args, (psFreeFunc)mopsArgumentsFree);
+
+    args->input = NULL;
+    args->exp_name = NULL;
+    args->exp_id = 0;
+    args->chip_id = 0;
+    args->cam_id = 0;
+    args->fake_id = 0;
+    args->warp_id = 0;
+    args->diff_id = 0;
+    args->zp = NAN;
+    args->positive = true;
+    args->zpErr = NAN;
+    args->rmsAstrom = NAN;
+    args->output = NULL;
+
+    return args;
+}
+
+
+ppMopsArguments *ppMopsArgumentsParse(int argc, char *argv[])
+{
+    assert(argv);
+
+    psTrace("ppMops.args", 1, "Parsing command-line arguments\n");
+
+    psArgumentVerbosity(&argc, argv);
+
+    psMetadata *arguments = psMetadataAlloc(); // Command-line arguments
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-exp_name", 0, "Exposure name", NULL);
+    psMetadataAddS64(arguments, PS_LIST_TAIL, "-exp_id", 0, "Exposure identifier", 0);
+    psMetadataAddS64(arguments, PS_LIST_TAIL, "-chip_id", 0, "Chip stage identifier", 0);
+    psMetadataAddS64(arguments, PS_LIST_TAIL, "-cam_id", 0, "Camera stage identifier", 0);
+    psMetadataAddS64(arguments, PS_LIST_TAIL, "-fake_id", 0, "Fake stage identifier", 0);
+    psMetadataAddS64(arguments, PS_LIST_TAIL, "-warp_id", 0, "Warp stage identifier", 0);
+    psMetadataAddS64(arguments, PS_LIST_TAIL, "-diff_id", 0, "Diff stage identifier", 0);
+    psMetadataAddBool(arguments, PS_LIST_TAIL, "-inverse", 0, "Inverse subtraction?", false);
+    psMetadataAddF32(arguments, PS_LIST_TAIL, "-zp", 0, "Magnitude zero point", NAN);
+    psMetadataAddF32(arguments, PS_LIST_TAIL, "-zp_error", 0, "Error in magnitude zero point", NAN);
+    psMetadataAddF32(arguments, PS_LIST_TAIL, "-astrom_rms", 0, "Astrometric solution RMS", NAN);
+
+    if (argc == 1 || !psArgumentParse(arguments, &argc, argv) || argc != 3) {
+        usage(argv[0], arguments);
+    }
+
+    ppMopsArguments *args = ppMopsArgumentsAlloc(); // Arguments, to return
+
+    psString inList = psSlurpFilename(argv[1]); // List of filenames
+    args->input = psStringSplitArray(inList, "\n", false);
+    psFree(inList);
+    if (!args->input || args->input->n == 0) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "No inputs provided.");
+        return NULL;
+    }
+    args->output = psStringCopy(argv[2]);
+
+    args->exp_name = psMetadataLookupStr(NULL, arguments, "-exp_name");
+    args->exp_id = psMetadataLookupS64(NULL, arguments, "-exp_id");
+    args->chip_id = psMetadataLookupS64(NULL, arguments, "-chip_id");
+    args->cam_id = psMetadataLookupS64(NULL, arguments, "-cam_id");
+    args->fake_id = psMetadataLookupS64(NULL, arguments, "-fake_id");
+    args->warp_id = psMetadataLookupS64(NULL, arguments, "-warp_id");
+    args->diff_id = psMetadataLookupS64(NULL, arguments, "-diff_id");
+    args->positive = !psMetadataLookupBool(NULL, arguments, "-inverse"); // NOTE: negated
+
+    args->zp = psMetadataLookupF32(NULL, arguments, "-zp");
+    args->zpErr = psMetadataLookupF32(NULL, arguments, "-zp_error");
+    args->rmsAstrom = psMetadataLookupF32(NULL, arguments, "-astrom_rms");
+
+    psTrace("ppMops.args", 1, "Done parsing command-line arguments\n");
+
+    return args;
+}
Index: branches/eam_branches/20090820/ppMops/src/ppMopsData.c
===================================================================
--- branches/eam_branches/20090820/ppMops/src/ppMopsData.c	(revision 25206)
+++ 	(revision )
@@ -1,32 +1,0 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <pslib.h>
-
-#include "ppMops.h"
-
-static void mopsDataFree(ppMopsData *data)
-{
-    psFree(data->detections);
-    psFree(data->exp_name);
-    psFree(data->output);
-    return;
-}
-
-ppMopsData *ppMopsDataAlloc(void)
-{
-    ppMopsData *data = psAlloc(sizeof(ppMopsData)); // Data to return
-    psMemSetDeallocator(data, (psFreeFunc)mopsDataFree);
-
-    data->detections = NULL;
-    data->zp = NAN;
-    data->exp_id = 0;
-    data->exp_name = NULL;
-    data->output = NULL;
-
-    return data;
-}
-
-
Index: branches/eam_branches/20090820/ppMops/src/ppMopsDetections.c
===================================================================
--- branches/eam_branches/20090820/ppMops/src/ppMopsDetections.c	(revision 25766)
+++ branches/eam_branches/20090820/ppMops/src/ppMopsDetections.c	(revision 25766)
@@ -0,0 +1,204 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+
+#include "ppMops.h"
+
+static void mopsDetectionsFree(ppMopsDetections *det)
+{
+    psFree(det->raBoresight);
+    psFree(det->decBoresight);
+    psFree(det->filter);
+    psFree(det->x);
+    psFree(det->y);
+    psFree(det->ra);
+    psFree(det->dec);
+    psFree(det->raErr);
+    psFree(det->decErr);
+    psFree(det->mag);
+    psFree(det->magErr);
+    psFree(det->extended);
+    psFree(det->angle);
+    psFree(det->angleErr);
+    psFree(det->length);
+    psFree(det->lengthErr);
+    psFree(det->flags);
+    psFree(det->diffSkyfileId);
+    psFree(det->naxis1);
+    psFree(det->naxis2);
+    psFree(det->mask);
+    return;
+}
+
+ppMopsDetections *ppMopsDetectionsAlloc(long num)
+{
+    ppMopsDetections *det = psAlloc(sizeof(ppMopsDetections)); // Detections, to return
+    psMemSetDeallocator(det, (psFreeFunc)mopsDetectionsFree);
+
+    det->raBoresight = NULL;
+    det->decBoresight = NULL;
+    det->filter = NULL;
+    det->airmass = NAN;
+    det->exptime = NAN;
+    det->posangle = NAN;
+    det->alt = NAN;
+    det->az = NAN;
+    det->mjd = NAN;
+    det->seeing = NAN;
+    det->num = 0;
+    det->x = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->y = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->ra = psVectorAllocEmpty(num, PS_TYPE_F64);
+    det->dec = psVectorAllocEmpty(num, PS_TYPE_F64);
+    det->raErr = psVectorAllocEmpty(num, PS_TYPE_F64);
+    det->decErr = psVectorAllocEmpty(num, PS_TYPE_F64);
+    det->mag = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->magErr = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->extended = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->angle = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->angleErr = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->length = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->lengthErr = psVectorAllocEmpty(num, PS_TYPE_F32);
+    det->flags = psVectorAllocEmpty(num, PS_TYPE_U32);
+    det->diffSkyfileId = psVectorAllocEmpty(num, PS_TYPE_S64);
+    det->naxis1 = psVectorAllocEmpty(num, PS_TYPE_S32);
+    det->naxis2 = psVectorAllocEmpty(num, PS_TYPE_S32);
+    det->mask = psVectorAllocEmpty(num, PS_TYPE_U8);
+
+    return det;
+}
+
+
+ppMopsDetections *ppMopsDetectionsRealloc(ppMopsDetections *det, long num)
+{
+    det->x = psVectorRealloc(det->x, num);
+    det->y = psVectorRealloc(det->y, num);
+    det->ra = psVectorRealloc(det->ra, num);
+    det->dec = psVectorRealloc(det->dec, num);
+    det->raErr = psVectorRealloc(det->raErr, num);
+    det->decErr = psVectorRealloc(det->decErr, num);
+    det->mag = psVectorRealloc(det->mag, num);
+    det->magErr = psVectorRealloc(det->magErr, num);
+    det->extended = psVectorRealloc(det->extended, num);
+    det->angle = psVectorRealloc(det->angle, num);
+    det->angleErr = psVectorRealloc(det->angleErr, num);
+    det->length = psVectorRealloc(det->length, num);
+    det->lengthErr = psVectorRealloc(det->lengthErr, num);
+    det->flags = psVectorRealloc(det->flags, num);
+    det->diffSkyfileId = psVectorRealloc(det->diffSkyfileId, num);
+    det->naxis1 = psVectorRealloc(det->naxis1, num);
+    det->naxis2 = psVectorRealloc(det->naxis2, num);
+    det->mask = psVectorRealloc(det->mask, num);
+
+    return det;
+}
+
+
+bool ppMopsDetectionsAdd(ppMopsDetections *det, float x, float y, double ra, double dec,
+                         double raErr, double decErr, float mag, float magErr, float extended,
+                         float angle, float angleErr, float length, float lengthErr,
+                         psU32 flags, psS64 diffSkyfileId, int naxis1, int naxis2)
+{
+    psVectorAppend(det->x, x);
+    psVectorAppend(det->y, y);
+    psVectorAppend(det->ra, ra);
+    psVectorAppend(det->dec, dec);
+    psVectorAppend(det->raErr, raErr);
+    psVectorAppend(det->decErr, decErr);
+    psVectorAppend(det->mag, mag);
+    psVectorAppend(det->magErr, magErr);
+    psVectorAppend(det->extended, extended);
+    psVectorAppend(det->angle, angle);
+    psVectorAppend(det->angleErr, angleErr);
+    psVectorAppend(det->length, length);
+    psVectorAppend(det->lengthErr, lengthErr);
+    psVectorAppend(det->flags, flags);
+    psVectorAppend(det->diffSkyfileId, diffSkyfileId);
+    psVectorAppend(det->naxis1, naxis1);
+    psVectorAppend(det->naxis2, naxis2);
+    psVectorAppend(det->mask, 0);
+    return true;
+}
+
+
+bool ppMopsDetectionsCopySingle(ppMopsDetections *target, const ppMopsDetections *source, long index)
+{
+    psVectorAppend(target->x, source->x->data.F32[index]);
+    psVectorAppend(target->y, source->y->data.F32[index]);
+    psVectorAppend(target->ra, source->ra->data.F64[index]);
+    psVectorAppend(target->dec, source->dec->data.F64[index]);
+    psVectorAppend(target->raErr, source->raErr->data.F64[index]);
+    psVectorAppend(target->decErr, source->decErr->data.F64[index]);
+    psVectorAppend(target->mag, source->mag->data.F32[index]);
+    psVectorAppend(target->magErr, source->magErr->data.F32[index]);
+    psVectorAppend(target->extended, source->extended->data.F32[index]);
+    psVectorAppend(target->angle, source->angle->data.F32[index]);
+    psVectorAppend(target->angleErr, source->angleErr->data.F32[index]);
+    psVectorAppend(target->length, source->length->data.F32[index]);
+    psVectorAppend(target->lengthErr, source->lengthErr->data.F32[index]);
+    psVectorAppend(target->flags, source->flags->data.U32[index]);
+    psVectorAppend(target->diffSkyfileId, source->diffSkyfileId->data.S64[index]);
+    psVectorAppend(target->naxis1, source->naxis1->data.S32[index]);
+    psVectorAppend(target->naxis2, source->naxis2->data.S32[index]);
+    psVectorAppend(target->mask, 0);
+    target->num++;
+    return true;
+}
+
+
+bool ppMopsDetectionsPurge(ppMopsDetections *det)
+{
+    long num = 0;
+    for (long i = 0; i < det->num; i++) {
+        if (!det->mask->data.U8[i]) {
+            if (i == num) {
+                // No need to copy
+                num++;
+                continue;
+            }
+            det->x->data.F32[num] = det->x->data.F32[i];
+            det->y->data.F32[num] = det->y->data.F32[i];
+            det->ra->data.F64[num] = det->ra->data.F64[i];
+            det->dec->data.F64[num] = det->dec->data.F64[i];
+            det->raErr->data.F64[num] = det->raErr->data.F64[i];
+            det->decErr->data.F64[num] = det->decErr->data.F64[i];
+            det->mag->data.F32[num] = det->mag->data.F32[i];
+            det->magErr->data.F32[num] = det->magErr->data.F32[i];
+            det->extended->data.F32[num] = det->extended->data.F32[i];
+            det->angle->data.F32[num] = det->angle->data.F32[i];
+            det->angleErr->data.F32[num] = det->angleErr->data.F32[i];
+            det->length->data.F32[num] = det->length->data.F32[i];
+            det->lengthErr->data.F32[num] = det->lengthErr->data.F32[i];
+            det->flags->data.U32[num] = det->flags->data.U32[i];
+            det->diffSkyfileId->data.S64[num] = det->diffSkyfileId->data.S64[i];
+            det->naxis1->data.S32[num] = det->naxis1->data.S32[i];
+            det->naxis2->data.S32[num] = det->naxis2->data.S32[i];
+            det->mask->data.U8[num] = 0;
+            num++;
+        }
+    }
+    det->x->n = num;
+    det->y->n = num;
+    det->ra->n = num;
+    det->dec->n = num;
+    det->raErr->n = num;
+    det->decErr->n = num;
+    det->mag->n = num;
+    det->magErr->n = num;
+    det->extended->n = num;
+    det->angle->n = num;
+    det->angleErr->n = num;
+    det->length->n = num;
+    det->lengthErr->n = num;
+    det->flags->n = num;
+    det->diffSkyfileId->n = num;
+    det->naxis1->n = num;
+    det->naxis2->n = num;
+    det->mask->n = num;
+    det->num = num;
+    return true;
+}
+
Index: branches/eam_branches/20090820/ppMops/src/ppMopsMerge.c
===================================================================
--- branches/eam_branches/20090820/ppMops/src/ppMopsMerge.c	(revision 25766)
+++ branches/eam_branches/20090820/ppMops/src/ppMopsMerge.c	(revision 25766)
@@ -0,0 +1,171 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <string.h>
+
+#include "ppMops.h"
+
+#define LEAF_SIZE 4                     // Size of leaf
+#define MATCH_RADIUS SEC_TO_RAD(1.0)    // Matching radius
+#define MJD_TOL 1.0/3600.0/24.0         // Tolerance for MJD matching
+#define BORESIGHT_TOL SEC_TO_RAD(1.0)   // Tolerance for boresight matching
+#define EXPTIME_TOL 1.0e-3              // Tolerance for exposure time matching
+#define POSANGLE_TOL SEC_TO_RAD(1.0)    // Tolerance for position angle matching
+#define AIRMASS_TOL 1.0e-3              // Tolerance for airmass matching
+
+// Get distance from detection to centre of image
+static float mergeDistance(const ppMopsDetections *detections, // Detections of interest
+                           long index                          // Index for source of interest
+    )
+{
+    float dx = detections->x->data.F32[index] - detections->naxis1->data.S32[index] / 2.0;
+    float dy = detections->y->data.F32[index] - detections->naxis2->data.S32[index] / 2.0;
+    return PS_SQR(dx) + PS_SQR(dy);
+}
+
+
+ppMopsDetections *ppMopsMerge(const psArray *detections)
+{
+    PS_ASSERT_ARRAY_NON_NULL(detections, NULL);
+
+    psTrace("ppMops.merge", 1, "Merging detections from %ld inputs\n", detections->n);
+
+    ppMopsDetections *merged = NULL;    // Merged list
+    int num = 1;                                                         // Number of merged files
+    for (int i = 0; i < detections->n; i++) {
+        ppMopsDetections *det = detections->data[i]; // Detections of interest
+        if (!det) {
+            psTrace("ppMops.merge", 3, "Ignoring NULL input %d\n", i);
+            continue;
+        } else if (det->num == 0) {
+            psTrace("ppMops.merge", 3, "Ignoring empty input %d\n", i);
+            continue;
+        }
+        num++;
+        if (!merged) {
+            psTrace("ppMops.merge", 3, "Accepting %ld detections from input %d\n", det->num, i);
+            merged = psMemIncrRefCounter(det);
+            continue;
+        }
+        psTrace("ppMops.merge", 3, "Merging %ld detections from input %d\n", det->num, i);
+
+        // XXX compare exposure properties
+        if (strcmp(merged->raBoresight, det->raBoresight) != 0) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure RA values differ: %s vs %s",
+                    merged->raBoresight, det->raBoresight);
+            return NULL;
+        }
+        if (strcmp(merged->decBoresight, det->decBoresight) != 0) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure Dec values differ: %s vs %s",
+                    merged->decBoresight, det->decBoresight);
+            return NULL;
+        }
+        if (strcmp(merged->filter, det->filter) != 0) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure filter values differ: %s vs %s",
+                    merged->filter, det->filter);
+            return NULL;
+        }
+
+        if (fabsf(merged->airmass - det->airmass) > AIRMASS_TOL) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure airmass values differ: %f vs %f",
+                    merged->airmass, det->airmass);
+            return NULL;
+        }
+        if (fabsf(merged->exptime - det->exptime) > EXPTIME_TOL) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure exposure time values differ: %f vs %f",
+                    merged->exptime, det->exptime);
+            return NULL;
+        }
+        if (fabs(merged->posangle - det->posangle) > POSANGLE_TOL) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure position angle values differ: %f vs %f",
+                    merged->posangle, det->posangle);
+            return NULL;
+        }
+        if (fabs(merged->alt - det->alt) > BORESIGHT_TOL) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure altitude values differ: %lf vs %lf",
+                    merged->alt, det->alt);
+            return NULL;
+        }
+        if (fabs(merged->az - det->az) > BORESIGHT_TOL) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure azimuth values differ: %lf vs %lf",
+                    merged->az, det->az);
+            return NULL;
+        }
+        if (fabs(merged->mjd - det->mjd) > MJD_TOL) {
+            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure MJD values differ: %lf vs %lf",
+                    merged->mjd, det->mjd);
+            return NULL;
+        }
+
+        merged->seeing += det->seeing;  // Taking average
+
+        psTree *tree = psTreePlant(2, LEAF_SIZE, PS_TREE_SPHERICAL, merged->ra, merged->dec); // kd tree
+        if (!tree) {
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate kd tree");
+            psFree(merged);
+            return NULL;
+        }
+
+        psVector *coords = psVectorAlloc(2, PS_TYPE_F64); // Coordinates of interest
+        for (int j = 0; j < det->num; j++) {
+            coords->data.F64[0] = det->ra->data.F64[j];
+            coords->data.F64[1] = det->dec->data.F64[j];
+            psVector *indices = psTreeAllWithin(tree, coords, MATCH_RADIUS); // Indices for matching sources
+            if (!indices) {
+                psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to search for matches");
+                psFree(coords);
+                psFree(tree);
+                psFree(merged);
+                return NULL;
+            }
+            if (indices->n == 0) {
+                psTrace("ppMops.merge", 9, "No matches for source %d in input %d\n", j, i);
+                psFree(indices);
+                ppMopsDetectionsCopySingle(merged, det, j);
+                continue;
+            }
+            psTrace("ppMops.merge", 5, "%ld matches for source %d from input %d\n", indices->n, j, i);
+
+            // Which one do we keep?
+            float bestDistance = INFINITY; // Best distance to centre
+            long bestIndex = -1;           // Index with best distance
+            for (int k = 0; k < indices->n; k++) {
+                long index = indices->data.S64[k]; // Index of point
+                float distance = mergeDistance(merged, index); // Distance to centre of image
+                if (distance < bestDistance) {
+                    bestDistance = distance;
+                    bestIndex = index;
+                }
+            }
+
+            float distance = mergeDistance(det, j); // Distance to centre of image
+            if (distance < bestDistance) {
+                psTrace("ppMops.merge", 6, "New source clobbers old sources\n");
+                // Blow away existing sources
+                for (int k = 0; k < indices->n; k++) {
+                    long index = indices->data.S64[k]; // Index of point
+                    merged->mask->data.U8[index] = 0xFF;
+                }
+                ppMopsDetectionsCopySingle(merged, det, j);
+            } else {
+                psTrace("ppMops.merge", 6, "Old sources clobber new source\n");
+            }
+            psFree(indices);
+        }
+
+        psTrace("ppMops.merge", 3, "Done merging input %d, %ld merged sources\n", i, merged->num);
+
+        psFree(tree);
+        ppMopsDetectionsPurge(merged);
+    }
+
+    psTrace("ppMops.merge", 2, "%ld sources in merged detections list\n", merged->num);
+
+    merged->seeing /= num;
+
+    return merged;
+}
+
Index: branches/eam_branches/20090820/ppMops/src/ppMopsRead.c
===================================================================
--- branches/eam_branches/20090820/ppMops/src/ppMopsRead.c	(revision 25766)
+++ branches/eam_branches/20090820/ppMops/src/ppMopsRead.c	(revision 25766)
@@ -0,0 +1,166 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+
+#include "ppMops.h"
+
+psArray *ppMopsRead(const ppMopsArguments *args)
+{
+    psTrace("ppMops.read", 1, "Reading input detections\n");
+
+    psArray *inNames = args->input;          // Input names
+    long num = inNames->n;                   // Number of inputs
+    psArray *detections = psArrayAlloc(num); // Array of detections, to return
+    for (int i = 0; i < num; i++) {
+        psFits *fits = psFitsOpen(inNames->data[i], "r"); // FITS file
+        if (!fits) {
+            psError(PS_ERR_IO, false, "Unable to open input %d", i);
+            return false;
+        }
+        psMetadata *header = psFitsReadHeader(NULL, fits); // Primary header
+        if (!header) {
+            psError(PS_ERR_IO, false, "Unable to read header %d", i);
+            return false;
+        }
+
+        psS64 diffSkyfileId = psMetadataLookupS64(NULL, header, "IMAGEID"); // Identifier for image
+        if (diffSkyfileId == 0) {
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find identifier for image %d", i);
+            return false;
+        }
+
+        if (!psFitsMoveExtName(fits, "SkyChip.psf")) {
+            psError(PS_ERR_IO, false, "Unable to move to HDU with detections");
+            return false;
+        }
+
+        long size = psFitsTableSize(fits); // Size of table
+        if (size <= 0) {
+            psErrorStackPrint(stderr, "Unable to determine size of table %d", i);
+            psErrorClear();
+            psWarning("Ignoring input %d", i);
+            psFree(header);
+            psFitsClose(fits);
+            continue;
+        }
+        ppMopsDetections *det = ppMopsDetectionsAlloc(size);
+
+        psTrace("ppMops.read", 3, "Reading %ld rows from %s\n", size, (const char*)inNames->data[i]);
+
+        det->raBoresight = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.RA"));
+        det->decBoresight = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.DEC"));
+        det->filter = psMemIncrRefCounter(psMetadataLookupStr(NULL, header, "FPA.FILTER"));
+        det->airmass = psMetadataLookupF32(NULL, header, "AIRMASS");
+        det->exptime = psMetadataLookupF32(NULL, header, "EXPTIME");
+        det->posangle = psMetadataLookupF64(NULL, header, "FPA.POSANGLE");
+        det->alt = psMetadataLookupF64(NULL, header, "FPA.ALT");
+        det->az = psMetadataLookupF64(NULL, header, "FPA.AZ");
+        det->mjd = psMetadataLookupF64(NULL, header, "MJD-OBS") + det->exptime / 2.0 / 3600 / 24;
+
+        det->seeing = 0.5 * (psMetadataLookupF32(NULL, header, "FWHM_MAJ") +
+                             psMetadataLookupF32(NULL, header, "FWHM_MIN"));
+
+        int naxis1 = psMetadataLookupS32(NULL, header, "IMNAXIS1"); // Number of columns
+        int naxis2 = psMetadataLookupS32(NULL, header, "IMNAXIS2"); // Number of rows
+
+        psFree(header);
+
+        psArray *table = psFitsReadTable(fits); // Table of interest
+        if (!table) {
+            psError(PS_ERR_IO, false, "Unable to read table %d", i);
+            return false;
+        }
+        psFitsClose(fits);
+
+        double plateScale = 0.0;        // Plate scale
+        long numGood = 0;               // Number of good rows
+        for (long j = 0; j < size; j++) {
+            psMetadata *row = table->data[j]; // Row of interest
+
+            psU32 flags = psMetadataLookupU32(NULL, row, "FLAGS");
+            if (flags & SOURCE_MASK) {
+                continue;
+            }
+
+            det->x->data.F32[numGood] = psMetadataLookupF32(NULL, row, "X_PSF");
+            det->y->data.F32[numGood] = psMetadataLookupF32(NULL, row, "Y_PSF");
+            det->ra->data.F64[numGood] = DEG_TO_RAD(psMetadataLookupF64(NULL, row, "RA_PSF"));
+            det->dec->data.F64[numGood] = DEG_TO_RAD(psMetadataLookupF64(NULL, row, "DEC_PSF"));
+            det->mag->data.F32[numGood] = psMetadataLookupF32(NULL, row, "PSF_INST_MAG");
+            det->magErr->data.F32[numGood] = psMetadataLookupF32(NULL, row, "PSF_INST_MAG_SIG");
+            det->extended->data.F32[numGood] = psMetadataLookupF32(NULL, row, "EXT_NSIGMA");
+            det->angle->data.F32[numGood] = 0.0;
+            det->angleErr->data.F32[numGood] = 0.0;
+            det->length->data.F32[numGood] = 0.0;
+            det->lengthErr->data.F32[numGood] = 0.0;
+            det->flags->data.U32[numGood] = psMetadataLookupU32(NULL, row, "FLAGS");
+            det->diffSkyfileId->data.S64[numGood] = diffSkyfileId;
+            det->naxis1->data.S32[numGood] = naxis1;
+            det->naxis2->data.S32[numGood] = naxis2;
+
+            // Calculate error in RA, Dec
+            double xErr = psMetadataLookupF64(NULL, row, "X_PSF_SIG");
+            double yErr = psMetadataLookupF64(NULL, row, "Y_PSF_SIG");
+            double scale = psMetadataLookupF64(NULL, row, "PLTSCALE");
+            double angle = psMetadataLookupF64(NULL, row, "POSANGLE");
+
+            if (!isfinite(det->x->data.F32[numGood]) || !isfinite(det->y->data.F32[numGood]) ||
+                !isfinite(det->ra->data.F64[numGood]) || !isfinite(det->dec->data.F64[numGood]) ||
+                !isfinite(det->mag->data.F32[numGood]) || !isfinite(det->magErr->data.F32[numGood]) ||
+                !isfinite(xErr) || !isfinite(yErr) || !isfinite(scale) || !isfinite(angle) ||
+                (det->flags->data.U32[numGood] & SOURCE_MASK)) {
+                continue;
+            }
+
+            // XXX Not at all sure I've got the angles around the right way here...
+            double cosAngle = cos(angle), sinAngle = sin(angle);
+            double cosAngle2 = PS_SQR(cosAngle), sinAngle2 = PS_SQR(sinAngle);
+            double xErr2 = PS_SQR(xErr), yErr2 = PS_SQR(yErr);
+            double errScale = scale / 3600.0;
+            det->raErr->data.F64[numGood] = errScale * sqrt(cosAngle2 * xErr2 + sinAngle2 * yErr2);
+            det->decErr->data.F64[numGood] = errScale * sqrt(sinAngle2 * xErr2 + cosAngle2 * yErr2);
+
+            det->mask->data.U8[numGood] = 0;
+            plateScale += scale;
+            numGood++;
+        }
+        det->seeing *= plateScale / numGood;
+
+        det->x->n = numGood;
+        det->y->n = numGood;
+        det->ra->n = numGood;
+        det->dec->n = numGood;
+        det->raErr->n = numGood;
+        det->decErr->n = numGood;
+        det->mag->n = numGood;
+        det->magErr->n = numGood;
+        det->extended->n = numGood;
+        det->angle->n = numGood;
+        det->angleErr->n = numGood;
+        det->length->n = numGood;
+        det->lengthErr->n = numGood;
+        det->flags->n = numGood;
+        det->diffSkyfileId->n = numGood;
+        det->naxis1->n = numGood;
+        det->naxis2->n = numGood;
+        det->mask->n = numGood;
+
+        det->num = numGood;
+
+        if (isfinite(args->zp) && numGood > 0) {
+            psBinaryOp(det->mag, det->mag, "+", psScalarAlloc(args->zp, PS_TYPE_F32));
+        }
+
+        psTrace("ppMops.read", 2, "Read %ld good rows from %s\n", numGood, (const char*)inNames->data[i]);
+
+        psFree(table);
+        detections->data[i] = det;
+    }
+
+    psTrace("ppMops.read", 1, "Done reading input detections\n");
+
+    return detections;
+}
Index: branches/eam_branches/20090820/ppMops/src/ppMopsWrite.c
===================================================================
--- branches/eam_branches/20090820/ppMops/src/ppMopsWrite.c	(revision 25766)
+++ branches/eam_branches/20090820/ppMops/src/ppMopsWrite.c	(revision 25766)
@@ -0,0 +1,119 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+
+#include "ppMops.h"
+
+bool ppMopsWrite(const ppMopsDetections *det, const ppMopsArguments *args)
+{
+    psTrace("ppMops.write", 1, "Writing %ld rows to %s", det->num, args->output);
+
+    psFits *fits = psFitsOpen(args->output, "w"); // FITS file
+    if (!fits) {
+        psError(PS_ERR_IO, false, "Unable to open output file.");
+        return false;
+    }
+
+
+    psMetadata *header = psMetadataAlloc(); // Header to write
+    psString source = ppMopsSource(), version = ppMopsVersion();
+    psMetadataAddStr(header, PS_LIST_TAIL, "SWSOURCE", 0, "Software source", source);
+    psMetadataAddStr(header, PS_LIST_TAIL, "SWVERSN", 0, "Software version", version);
+    ppMopsVersionHeader(header);
+    psFree(source);
+    psFree(version);
+
+    psMetadataAddStr(header, PS_LIST_TAIL, "EXP_NAME", 0, "Exposure name", args->exp_name);
+    psMetadataAddS64(header, PS_LIST_TAIL, "EXP_ID", 0, "Exposure identifier", args->exp_id);
+    psMetadataAddS64(header, PS_LIST_TAIL, "CHIP_ID", 0, "Chip stage identifier", args->chip_id);
+    psMetadataAddS64(header, PS_LIST_TAIL, "CAM_ID", 0, "Cam stage identifier", args->cam_id);
+    psMetadataAddS64(header, PS_LIST_TAIL, "FAKE_ID", 0, "Fake stage identifier", args->fake_id);
+    psMetadataAddS64(header, PS_LIST_TAIL, "WARP_ID", 0, "Warp stage identifier", args->warp_id);
+    psMetadataAddS64(header, PS_LIST_TAIL, "DIFF_ID", 0, "Diff stage identifier", args->diff_id);
+    psMetadataAddBool(header, PS_LIST_TAIL, "DIFF_POS", 0, "Positive subtraction?", args->positive);
+
+    psMetadataAddF64(header, PS_LIST_TAIL, "MJD-OBS", 0, "MJD of exposure midpoint", det->mjd);
+    psMetadataAddStr(header, PS_LIST_TAIL, "RA", 0, "Right Ascension of boresight", det->raBoresight);
+    psMetadataAddStr(header, PS_LIST_TAIL, "DEC", 0, "Declination of boresight", det->decBoresight);
+    psMetadataAddF64(header, PS_LIST_TAIL, "TEL_ALT", 0, "Telescope altitude", det->alt);
+    psMetadataAddF64(header, PS_LIST_TAIL, "TEL_AZ", 0, "Telescope azimuth", det->az);
+    psMetadataAddF64(header, PS_LIST_TAIL, "EXPTIME", 0, "Exposure time (sec)", det->exptime);
+    psMetadataAddF64(header, PS_LIST_TAIL, "ROTANGLE", 0, "Rotator position angle", det->posangle);
+    psMetadataAddStr(header, PS_LIST_TAIL, "FILTER", 0, "Filter name", det->filter);
+    psMetadataAddF32(header, PS_LIST_TAIL, "AIRMASS", 0, "Airmass of exposure", det->airmass);
+    psMetadataAddStr(header, PS_LIST_TAIL, "OBSCODE", 0, "IAU Observatory code", OBSERVATORY_CODE);
+    psMetadataAddF32(header, PS_LIST_TAIL, "SEEING", 0, "Mean seeing", det->seeing);
+    psMetadataAddF32(header, PS_LIST_TAIL, "MAGZP", 0, "Magnitude zero point", args->zp);
+    psMetadataAddF32(header, PS_LIST_TAIL, "MAGZPERR", 0, "Error in magnitude zero point", args->zpErr);
+    psMetadataAddF32(header, PS_LIST_TAIL, "ASTRORMS", 0, "RMS of astrometric fit", args->rmsAstrom);
+
+    if (det->num == 0) {
+        // Write dummy table
+        psMetadata *row = psMetadataAlloc(); // Output row
+        psMetadataAddF64(row, PS_LIST_TAIL, "RA", 0, "Right ascension (degrees)", NAN);
+        psMetadataAddF64(row, PS_LIST_TAIL, "RA_ERR", 0, "Right ascension error (degrees)", NAN);
+        psMetadataAddF64(row, PS_LIST_TAIL, "DEC", 0, "Declination (degrees)", NAN);
+        psMetadataAddF64(row, PS_LIST_TAIL, "DEC_ERR", 0, "Declination error (degrees)", NAN);
+        psMetadataAddF32(row, PS_LIST_TAIL, "MAG", 0, "Magnitude", NAN);
+        psMetadataAddF32(row, PS_LIST_TAIL, "MAG_ERR", 0, "Magnitude error", NAN);
+        psMetadataAddF32(row, PS_LIST_TAIL, "STARPSF", 0, "EXT_NSIGMA", NAN);
+        psMetadataAddF32(row, PS_LIST_TAIL, "ANGLE", 0, "Position angle of trail (degrees)", NAN);
+        psMetadataAddF32(row, PS_LIST_TAIL, "ANGLE_ERR", 0, "Position angle error (degrees)", NAN);
+        psMetadataAddF32(row, PS_LIST_TAIL, "LENGTH", 0, "Length of trail (arcsec)", NAN);
+        psMetadataAddF32(row, PS_LIST_TAIL, "LENGTH_ERR", 0, "Length error (arcsec)", NAN);
+        psMetadataAddU32(row, PS_LIST_TAIL, "FLAGS", 0, "Detection bit flags", 0);
+        psMetadataAddS64(row, PS_LIST_TAIL, "DIFF_SKYFILE_ID", 0, "Identifier for diff skyfile", 0);
+        if (!psFitsWriteTableEmpty(fits, header, row, OUT_EXTNAME)) {
+            psErrorStackPrint(stderr, "Unable to write empty table.");
+            psFree(header);
+            psFree(row);
+            return false;
+        }
+        psFree(row);
+    } else {
+        psArray *table = psArrayAlloc(det->num); // Table to write
+        for (long i = 0; i < det->num; i++) {
+            psMetadata *row = psMetadataAlloc(); // Output row
+            psMetadataAddF64(row, PS_LIST_TAIL, "RA", 0, "Right ascension (degrees)",
+                             RAD_TO_DEG(det->ra->data.F64[i]));
+            psMetadataAddF64(row, PS_LIST_TAIL, "RA_ERR", 0, "Right ascension error (degrees)",
+                             det->raErr->data.F64[i]);
+            psMetadataAddF64(row, PS_LIST_TAIL, "DEC", 0, "Declination (degrees)",
+                             RAD_TO_DEG(det->dec->data.F64[i]));
+            psMetadataAddF64(row, PS_LIST_TAIL, "DEC_ERR", 0, "Declination error (degrees)",
+                             det->decErr->data.F64[i]);
+            psMetadataAddF32(row, PS_LIST_TAIL, "MAG", 0, "Magnitude", det->mag->data.F32[i]);
+            psMetadataAddF32(row, PS_LIST_TAIL, "MAG_ERR", 0, "Magnitude error", det->magErr->data.F32[i]);
+            psMetadataAddF32(row, PS_LIST_TAIL, "STARPSF", 0, "EXT_NSIGMA", det->extended->data.F32[i]);
+            psMetadataAddF32(row, PS_LIST_TAIL, "ANGLE", 0, "Position angle of trail (degrees)",
+                             det->angle->data.F32[i]);
+            psMetadataAddF32(row, PS_LIST_TAIL, "ANGLE_ERR", 0, "Position angle error (degrees)",
+                             det->angleErr->data.F32[i]);
+            psMetadataAddF32(row, PS_LIST_TAIL, "LENGTH", 0, "Length of trail (arcsec)",
+                             det->length->data.F32[i]);
+            psMetadataAddF32(row, PS_LIST_TAIL, "LENGTH_ERR", 0, "Length error (arcsec)",
+                             det->lengthErr->data.F32[i]);
+            psMetadataAddU32(row, PS_LIST_TAIL, "FLAGS", 0, "Detection bit flags", det->flags->data.U32[i]);
+            psMetadataAddS64(row, PS_LIST_TAIL, "DIFF_SKYFILE_ID", 0, "Identifier for diff skyfile",
+                             det->diffSkyfileId->data.S64[i]);
+            table->data[i] = row;
+        }
+        if (!psFitsWriteTable(fits, header, table, OUT_EXTNAME)) {
+            psErrorStackPrint(stderr, "Unable to write table.");
+            psFree(header);
+            psFree(table);
+            return false;
+        }
+        psFree(table);
+    }
+
+    psFree(header);
+    psFitsClose(fits);
+
+    psTrace("ppMops.write", 1, "Done writing %ld rows to %s", det->num, args->output);
+
+    return true;
+}
Index: branches/eam_branches/20090820/ppSim/src/ppSimLoadStars.c
===================================================================
--- branches/eam_branches/20090820/ppSim/src/ppSimLoadStars.c	(revision 25206)
+++ branches/eam_branches/20090820/ppSim/src/ppSimLoadStars.c	(revision 25766)
@@ -41,5 +41,5 @@
     psMetadataAdd(astroRecipe, PS_LIST_TAIL, "DEC_MIN", PS_DATA_F32 | PS_META_REPLACE, "", dec0 - radius);
     psMetadataAdd(astroRecipe, PS_LIST_TAIL, "DEC_MAX", PS_DATA_F32 | PS_META_REPLACE, "", dec0 + radius);
-    psArray *refStars = psastroLoadRefstars(config, "PSASTRO.INPUT");
+    psArray *refStars = psastroLoadRefstars(config, "PPSIM.OUTPUT");
     if (!refStars) {
         psError(PS_ERR_UNKNOWN, false, "Unable to find reference stars.");
Index: branches/eam_branches/20090820/ppSim/src/ppSimLoop.c
===================================================================
--- branches/eam_branches/20090820/ppSim/src/ppSimLoop.c	(revision 25206)
+++ branches/eam_branches/20090820/ppSim/src/ppSimLoop.c	(revision 25766)
@@ -30,4 +30,9 @@
     ppSimType type = ppSimTypeFromString (typeStr); // Type of image to simulate
     int binning = psMetadataLookupS32(NULL, recipe, "BINNING"); // Binning in x and y
+
+    ppSimUpdateConceptsFPA (fpa, config);
+    if (fpa->hdu) { // XXX only do this if there is no INPUT image
+        if (!ppSimInitHeader(config, fpa, NULL, NULL)) ESCAPE (PS_ERR_UNKNOWN, "problem setting output header");
+    }
 
     psArray *stars = psArrayAllocEmpty (1);
@@ -57,9 +62,4 @@
         psFree(view);
         return false;
-    }
-
-    ppSimUpdateConceptsFPA (fpa, config);
-    if (fpa->hdu) { // XXX only do this if there is no INPUT image
-        if (!ppSimInitHeader(config, fpa, NULL, NULL)) ESCAPE (PS_ERR_UNKNOWN, "problem setting output header");
     }
 
Index: branches/eam_branches/20090820/ppSim/src/ppSimMakeStars.c
===================================================================
--- branches/eam_branches/20090820/ppSim/src/ppSimMakeStars.c	(revision 25206)
+++ branches/eam_branches/20090820/ppSim/src/ppSimMakeStars.c	(revision 25766)
@@ -61,5 +61,5 @@
 	if (!status) {
 	    refMag = brightMag;
-	    refSum = 1;
+	    refSum = starsDensity * xSize * ySize * PS_SQR(scale * 180.0 / M_PI);
 	}
     } else {
Index: branches/eam_branches/20090820/ppStack/src/ppStackCamera.c
===================================================================
--- branches/eam_branches/20090820/ppStack/src/ppStackCamera.c	(revision 25206)
+++ branches/eam_branches/20090820/ppStack/src/ppStackCamera.c	(revision 25766)
@@ -85,16 +85,4 @@
         psFree(runVars);
 
-        psArray *runPSF = pmFPAfileDefineMultipleFromRun(&status, runImages, config,
-                                                         "PPSTACK.INPUT.PSF"); // Input PSFs
-        if (!status) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to define input PSFs from RUN metadata.");
-            psFree(runImages);
-            return false;
-        }
-        if (runPSF) {
-            havePSFs = true;
-        }
-        psFree(runPSF);
-
         psArray *runSrc = pmFPAfileDefineMultipleFromRun(&status, runImages, config,
                                                          "PPSTACK.INPUT.SOURCES"); // Input sources
@@ -112,18 +100,34 @@
 
         if (convolve) {
-            psArray *runKernel = pmFPAfileDefineMultipleFromRun(&status, runImages, config,
-                                                                "PPSTACK.CONV.KERNEL"); // Convolution kernels
-            if (!status) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to define convolution kernels from RUN metadata.");
-                psFree(runImages);
-                return false;
-            }
-            if (!runKernel) {
-                psError(PS_ERR_UNEXPECTED_NULL, true,
-                        "Unable to define convolution kernels from RUN metadata.");
-                psFree(runImages);
-                return false;
-            }
-            psFree(runKernel);
+            {
+                psArray *runPSF = pmFPAfileDefineMultipleFromRun(&status, runImages, config,
+                                                         "PPSTACK.INPUT.PSF"); // Input PSFs
+                if (!status) {
+                    psError(PS_ERR_UNKNOWN, false, "Unable to define input PSFs from RUN metadata.");
+                    psFree(runImages);
+                    return false;
+                }
+                if (runPSF) {
+                    havePSFs = true;
+                }
+                psFree(runPSF);
+            }
+            {
+
+                psArray *runKernel = pmFPAfileDefineMultipleFromRun(&status, runImages, config,
+                                                                    "PPSTACK.CONV.KERNEL"); // Conv'n kernels
+                if (!status) {
+                    psError(PS_ERR_UNKNOWN, false, "Unable to define convolution kernels from RUN metadata.");
+                    psFree(runImages);
+                    return false;
+                }
+                if (!runKernel) {
+                    psError(PS_ERR_UNEXPECTED_NULL, true,
+                            "Unable to define convolution kernels from RUN metadata.");
+                    psFree(runImages);
+                    return false;
+                }
+                psFree(runKernel);
+            }
         }
 
Index: branches/eam_branches/20090820/ppStack/src/ppStackLoop.c
===================================================================
--- branches/eam_branches/20090820/ppStack/src/ppStackLoop.c	(revision 25206)
+++ branches/eam_branches/20090820/ppStack/src/ppStackLoop.c	(revision 25766)
@@ -80,8 +80,6 @@
         return false;
     }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 2: Generate Convolutions and Save: %f sec",
-             psTimerClear("PPSTACK_STEPS"));
     ppStackMemDump("convolve");
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 4: Make Initial Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 3: Make Initial Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
 
 
@@ -94,5 +92,5 @@
         return false;
     }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 5: Pixel Rejection: %f sec", psTimerClear("PPSTACK_STEPS"));
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 4: Pixel Rejection: %f sec", psTimerClear("PPSTACK_STEPS"));
     ppStackMemDump("reject");
 
@@ -106,5 +104,5 @@
         return false;
     }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 6: Final Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 5: Final Stack: %f sec", psTimerClear("PPSTACK_STEPS"));
     ppStackMemDump("final");
 
@@ -118,5 +116,5 @@
         return false;
     }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: WCS & JPEGS: %f sec", psTimerClear("PPSTACK_STEPS"));
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 6: WCS & JPEGS: %f sec", psTimerClear("PPSTACK_STEPS"));
     ppStackMemDump("cleanup");
 
@@ -131,5 +129,5 @@
         return false;
     }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS"));
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 7: Photometry Analysis: %f sec", psTimerClear("PPSTACK_STEPS"));
     ppStackMemDump("photometry");
 
@@ -142,5 +140,5 @@
         return false;
     }
-    psLogMsg("ppStack", PS_LOG_INFO, "Stage 9: Final output: %f sec", psTimerClear("PPSTACK_STEPS"));
+    psLogMsg("ppStack", PS_LOG_INFO, "Stage 8: Final output: %f sec", psTimerClear("PPSTACK_STEPS"));
     ppStackMemDump("finish");
 
Index: branches/eam_branches/20090820/ppStack/src/ppStackMatch.c
===================================================================
--- branches/eam_branches/20090820/ppStack/src/ppStackMatch.c	(revision 25206)
+++ branches/eam_branches/20090820/ppStack/src/ppStackMatch.c	(revision 25766)
@@ -14,6 +14,6 @@
 #define FAKE_SIZE 1                     // Size of fake convolution kernel
 #define SOURCE_MASK (PM_SOURCE_MODE_FAIL | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_SATURATED | \
-                     PM_SOURCE_MODE_CR_LIMIT) // Mask to apply to input sources
-#define FAINT_SOURCE_FRAC 1.0e-4         // Set minimum flux to this fraction of faintest source flux
+                     PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT) // Mask to apply to input sources
+#define NOISE_FRACTION 0.01             // Set minimum flux to this fraction of noise
 #define COVAR_FRAC 0.01                 // Truncation fraction for covariance matrix
 
@@ -87,5 +87,5 @@
     x->n = y->n = numGood;
 
-    psTree *tree = psTreePlant(2, 2, x, y); // kd tree
+    psTree *tree = psTreePlant(2, 2, PS_TREE_EUCLIDEAN, x, y); // kd tree
 
     psArray *filtered = psArrayAllocEmpty(numGood); // Filtered list of sources
@@ -162,4 +162,38 @@
 }
 
+// Renormalise a readout's variance map
+bool stackRenormaliseReadout(const pmConfig *config, // Configuration
+                             pmReadout *readout      // Readout to renormalise
+    )
+{
+    bool mdok; // Status of metadata lookups
+
+    psMetadata *recipe = psMetadataLookupPtr(NULL, config->recipes, PPSTACK_RECIPE); // Recipe for ppStack
+    psAssert(recipe, "Need PPSTACK recipe");
+
+    if (!psMetadataLookupBool(&mdok, recipe, "RENORM")) return true;
+
+    int num = psMetadataLookupS32(&mdok, recipe, "RENORM.NUM");
+    if (!mdok) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.NUM is not set in the recipe");
+        return false;
+    }
+    float minValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MIN");
+    if (!mdok) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.MIN is not set in the recipe");
+        return false;
+    }
+    float maxValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MAX");
+    if (!mdok) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.MAX is not set in the recipe");
+        return false;
+    }
+
+    psImageMaskType maskBad = pmConfigMaskGet("BLANK", config); // Bits to mask
+
+    return pmReadoutVarianceRenormalise(readout, maskBad, num, minValid, maxValid);
+}
+
+
 
 bool ppStackMatch(pmReadout *readout, ppStackOptions *options, int index, const pmConfig *config)
@@ -232,6 +266,8 @@
             psRegion *region = psMetadataLookupPtr(NULL, conv->analysis,
                                                    PM_SUBTRACTION_ANALYSIS_REGION); // Convolution region
-
-            pmSubtractionAnalysis(readout->analysis, kernels, region,
+            pmSubtractionKernels *kernels = psMetadataLookupPtr(NULL, conv->analysis,
+                                                                PM_SUBTRACTION_ANALYSIS_KERNEL);
+
+            pmSubtractionAnalysis(readout->analysis, NULL, kernels, region,
                                   readout->image->numCols, readout->image->numRows);
 
@@ -283,4 +319,19 @@
             pmReadout *fake = pmReadoutAlloc(NULL); // Fake readout with target PSF
 
+            psStats *bg = psStatsAlloc(PS_STAT_ROBUST_STDEV); // Statistics for background
+            psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
+            if (!psImageBackground(bg, NULL, readout->image, readout->mask, maskVal | maskBad, rng)) {
+                psError(PS_ERR_UNKNOWN, false, "Can't measure background for image.");
+                psFree(fake);
+                psFree(optWidths);
+                psFree(conv);
+                psFree(bg);
+                psFree(rng);
+                return false;
+            }
+            float minFlux = NOISE_FRACTION * bg->robustStdev; // Minimum flux level for fake image
+            psFree(rng);
+            psFree(bg);
+
             // For the sake of stamps, remove nearby sources
             psArray *stampSources = stackSourcesFilter(options->sourceLists->data[index],
@@ -288,6 +339,6 @@
 
             if (!pmReadoutFakeFromSources(fake, readout->image->numCols, readout->image->numRows,
-                                          stampSources, NULL, NULL, options->psf, NAN, footprint + size,
-                                          false, true)) {
+                                          stampSources, SOURCE_MASK, NULL, NULL, options->psf,
+                                          minFlux, footprint + size, false, true)) {
                 psError(PS_ERR_UNKNOWN, false, "Unable to generate fake image with target PSF.");
                 psFree(fake);
@@ -335,5 +386,5 @@
                                                                PM_SUBTRACTION_ANALYSIS_KERNEL); // Conv kernel
             if (kernel) {
-                if (!pmSubtractionMatchPrecalc(conv, NULL, readout, fake, readout->analysis,
+                if (!pmSubtractionMatchPrecalc(NULL, conv, fake, readout, readout->analysis,
                                                stride, sysError, maskVal, maskBad, maskPoor,
                                                poorFrac, badFrac)) {
@@ -349,10 +400,10 @@
                 }
             } else {
-                if (!pmSubtractionMatch(conv, NULL, readout, fake, footprint, stride, regionSize, spacing,
+                if (!pmSubtractionMatch(NULL, conv, fake, readout, footprint, stride, regionSize, spacing,
                                         threshold, stampSources, stampsName, type, size, order, widths,
                                         orders, inner, ringsOrder, binning, penalty,
                                         optimum, optWidths, optOrder, optThresh, iter, rej, sysError,
                                         maskVal, maskBad, maskPoor, poorFrac, badFrac,
-                                        PM_SUBTRACTION_MODE_1)) {
+                                        PM_SUBTRACTION_MODE_2)) {
                     psError(PS_ERR_UNKNOWN, false, "Unable to match images.");
                     psFree(fake);
@@ -502,4 +553,9 @@
     }
 
+    if (!stackRenormaliseReadout(config, readout)) {
+        psFree(rng);
+        psFree(bg);
+        return false;
+    }
 
     // Measure the variance level for the weighting
Index: branches/eam_branches/20090820/ppStack/src/ppStackPSF.c
===================================================================
--- branches/eam_branches/20090820/ppStack/src/ppStackPSF.c	(revision 25206)
+++ branches/eam_branches/20090820/ppStack/src/ppStackPSF.c	(revision 25766)
@@ -9,7 +9,10 @@
 #include "ppStack.h"
 
+//#define TESTING
+
 pmPSF *ppStackPSF(const pmConfig *config, int numCols, int numRows,
                   const psArray *psfs, const psVector *inputMask)
 {
+#ifndef TESTING
     // Get the recipe values
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
@@ -35,4 +38,12 @@
         return NULL;
     }
+#else
+    // Dummy PSF
+    pmPSF *psf = pmPSFBuildSimple("PS_MODEL_PS1_V1", 4.0, 4.0, 0.0, 1.0);
+    if (!psf) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to build dummy PSF.");
+        return NULL;
+    }
+#endif
 
     return psf;
Index: branches/eam_branches/20090820/ppStack/src/ppStackReject.c
===================================================================
--- branches/eam_branches/20090820/ppStack/src/ppStackReject.c	(revision 25206)
+++ branches/eam_branches/20090820/ppStack/src/ppStackReject.c	(revision 25766)
@@ -9,4 +9,6 @@
 #include "ppStack.h"
 #include "ppStackLoop.h"
+
+//#define TESTING
 
 bool ppStackReject(ppStackOptions *options, pmConfig *config)
Index: branches/eam_branches/20090820/ppStack/src/ppStackSources.c
===================================================================
--- branches/eam_branches/20090820/ppStack/src/ppStackSources.c	(revision 25206)
+++ branches/eam_branches/20090820/ppStack/src/ppStackSources.c	(revision 25766)
@@ -123,5 +123,5 @@
         pmReadout *fake = pmReadoutAlloc(NULL); // Fake readout
         pmPSF *psf = psMetadataLookupPtr(NULL, config->arguments, "PSF.TARGET"); // PSF for fake image
-        pmReadoutFakeFromSources(fake, FAKE_COLS, FAKE_ROWS, sourceLists->data[i],
+        pmReadoutFakeFromSources(fake, FAKE_COLS, FAKE_ROWS, sourceLists->data[i], 0,
                                  NULL, NULL, psf, 5, 0, false, true);
         psString name = NULL;
Index: branches/eam_branches/20090820/ppSub/src/ppSubVarianceRescale.c
===================================================================
--- branches/eam_branches/20090820/ppSub/src/ppSubVarianceRescale.c	(revision 25206)
+++ branches/eam_branches/20090820/ppSub/src/ppSubVarianceRescale.c	(revision 25766)
@@ -28,178 +28,30 @@
     bool mdok; // Status of metadata lookups
 
-    psMetadata *ppSubRecipe = psMetadataLookupPtr(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSub
-    psAssert(ppSubRecipe, "Need PPSUB recipe");
+    psMetadata *recipe = psMetadataLookupPtr(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSub
+    psAssert(recipe, "Need PPSUB recipe");
 
-    if (!psMetadataLookupBool(&mdok, ppSubRecipe, "VARIANCE.RESCALE")) return true; 
+    if (!psMetadataLookupBool(&mdok, recipe, "RENORM")) return true;
+
+    int num = psMetadataLookupS32(&mdok, recipe, "RENORM.NUM");
+    if (!mdok) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.NUM is not set in the recipe");
+        return false;
+    }
+    float minValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MIN");
+    if (!mdok) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.MIN is not set in the recipe");
+        return false;
+    }
+    float maxValid = psMetadataLookupF32(&mdok, recipe, "RENORM.MAX");
+    if (!mdok) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "RENORM.MAX is not set in the recipe");
+        return false;
+    }
 
     psImageMaskType maskBad = pmConfigMaskGet("BLANK", config); // Bits to mask
 
     pmFPAview *view = ppSubViewReadout(); // View to readout
-    pmReadout *outRO = pmFPAfileThisReadout(config->files, view, "PPSUB.OUTPUT"); // Output image
+    pmReadout *readout = pmFPAfileThisReadout(config->files, view, "PPSUB.OUTPUT"); // Output image
 
-    psImage *image    = outRO->image;	 // Image of interest
-    psImage *variance = outRO->variance; // Variance image
-    psImage *mask     = outRO->mask;	 // Mask of interest
-
-    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);
-
-    psLogMsg("psLib.psImageBackground", PS_LOG_DETAIL, "Generating the signal-to-noise image");
-
-    // generate an image representing the signal/noise:
-    psImage *SN = psImageCopy (NULL, outRO->image, PS_TYPE_F32); 
-
-    int nx = image->numCols; // Size of image
-    int ny = image->numRows; // Size of image
-
-    for (int y = 0; y < ny; y++) {
-        for (int x = 0; x < nx; x++) {
-            if (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskBad) {
-                SN->data.F32[y][x] = 0.0;
-		continue;
-            } 
-            if (!isfinite(image->data.F32[y][x])) {
-                SN->data.F32[y][x] = 0.0;
-		continue;
-            } 
-            if (!isfinite(variance->data.F32[y][x]) || (variance->data.F32[y][x] < 0.0)) {
-                SN->data.F32[y][x] = 0.0;
-		continue;
-            } 
-	    SN->data.F32[y][x] = image->data.F32[y][x] / sqrt(variance->data.F32[y][x]);
-        }
-    }
-
-    // these should not be chosen by the user: only a ROBUST version makes sense
-    psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
-
-    int Nsubset = psMetadataLookupS32(&mdok, ppSubRecipe, "VARIANCE.RESCALE.NSAMPLE");
-    psAssert (mdok, "missing VARIANCE.RESCALE.NSAMPLE in ppSub recipe");
-    
-    const int Npixels = nx*ny; // Total number of pixels
-    Nsubset = PS_MIN(Nsubset, Npixels); // Number of pixels in subset
-    psLogMsg("psLib.psImageBackground", PS_LOG_DETAIL, "Searching for %d pixels in S/N image", Nsubset);
-
-    psVector *values = psVectorAllocEmpty(Nsubset, PS_TYPE_F32); // Vector containing subsample
-
-    // Minimum and maximum values
-    float min = +PS_MAX_F32;
-    float max = -PS_MAX_F32;
-
-    // select a subset of the image pixels to measure the stats
-    long n = 0;                         // Number of actual pixels in subset
-    if (Nsubset >= Npixels) {
-	// if we have an image smaller than Nsubset, just loop over the image pixels
-	for (int iy = 0; iy < ny; iy++) {
-	    for (int ix = 0; ix < nx; ix++) {
-		if (!isfinite(image->data.F32[iy][ix]) || (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskBad)) {
-		    continue;
-		}
-
-		float value = SN->data.F32[iy][ix];
-		min = PS_MIN(value, min);
-		max = PS_MAX(value, max);
-		values->data.F32[n] = value;
-		n++;
-	    }
-	}
-    } else {
-	for (long i = 0; i < Nsubset; i++) {
-	    double frnd = psRandomUniform(rng);
-	    int pixel = Npixels * frnd;
-	    int ix = pixel % nx;
-	    int iy = pixel / nx;
-
-	    if (!isfinite(image->data.F32[iy][ix]) || (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskBad)) {
-		continue;
-	    }
-
-	    float value = SN->data.F32[iy][ix];
-	    min = PS_MIN(value, min);
-	    max = PS_MAX(value, max);
-	    values->data.F32[n] = value;
-	    n++;
-	}
-    }
-    if (n < 0.01*Nsubset) {
-        psLogMsg("psLib.psImageBackground", PS_LOG_DETAIL, "Unable to measure image background: too few data points (%ld)", n);
-        psFree(values);
-        return false;
-    }
-    values->n = n;
-    psFree (SN);
-
-    psLogMsg("psLib.psImageBackground", PS_LOG_DETAIL, "Using for %ld pixels in S/N image", values->n);
-
-    if (!psVectorStats (stats, values, NULL, NULL, 0)) {
-	if (psTraceGetLevel("psLib.imageops") >= 5) {
-	    FILE *f = fopen ("vector.dat", "w");
-	    int fd = fileno(f);
-	    p_psVectorPrint (fd, values, "values");
-	    fclose (f);
-	}
-	psError(PS_ERR_UNKNOWN, false, "Unable to measure statistics for image background "
-		"(%dx%d, (row0,col0) = (%d,%d)",
-		image->numRows, image->numCols, image->row0, image->col0);
-	psFree(values);
-	return false;
-    }
-    if (psTraceGetLevel("psLib.imageops") >= 6) {
-	FILE *f = fopen ("vector.dat", "w");
-	int fd = fileno(f);
-	p_psVectorPrint (fd, values, "values");
-	fclose (f);
-    }
-    psFree (values);
-    psLogMsg ("ppSub", PS_LOG_INFO, "background stdev %f\n", stats->robustStdev);
-
-    float minValid = psMetadataLookupF32(&mdok, ppSubRecipe, "VARIANCE.RESCALE.MIN.VALID");
-    psAssert (mdok, "missing VARIANCE.RESCALE.MIN.VALID in ppSub recipe");
-
-    float maxValid = psMetadataLookupF32(&mdok, ppSubRecipe, "VARIANCE.RESCALE.MAX.VALID");
-    psAssert (mdok, "missing VARIANCE.RESCALE.MAX.VALID in ppSub recipe");
-
-    psLogMsg("psLib.psImageBackground", PS_LOG_DETAIL, "Stdev of S/N image: %f (mean: %f)", stats->robustStdev, stats->robustMedian);
-
-    // valid range of correction; 0.66 to 1.5 (skip if in range 0.98 to 1.02)
-    if ((stats->robustStdev < minValid) || (stats->robustStdev > maxValid)) {
-	psWarning ("background stdev (%f) is out of allowed range; not correcting\n", stats->robustStdev);
-	// XXX set quality to poor
-	psFree (stats);
-	return true;
-    }
-
-    // valid range of correction; 0.66 to 1.5 (skip if in range 0.98 to 1.02)
-    // if ((stats->robustStdev > 0.98) && (stats->robustStdev > 1.02)) {
-    // 	psLogMsg ("ppSub", PS_LOG_INFO, "background stdev (%f) is close to 1.0; do not modify variance\n", stats->robustStdev);
-    // 	// XXX set quality to poor
-    // 	psFree (stats);
-    // 	return true;
-    // }
-
-    float varianceFactor = PS_SQR(stats->robustStdev);
-    psLogMsg ("ppSub", PS_LOG_INFO, "background stdev is not 1.0: multiplying variance by %f\n", varianceFactor);
-    for (int y = 0; y < ny; y++) {
-        for (int x = 0; x < nx; x++) {
-            if (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskBad) {
-		continue;
-            } 
-            if (!isfinite(image->data.F32[y][x])) {
-		continue;
-            } 
-            if (!isfinite(variance->data.F32[y][x]) || (variance->data.F32[y][x] < 0.0)) {
-		continue;
-            } 
-	    variance->data.F32[y][x] *= varianceFactor;
-        }
-    }
-
-    pmFPA *outFPA = outRO->parent->parent->parent;
-    pmHDU *outHDU = outFPA->hdu;        // Output HDU
-
-    char history[80];
-    snprintf (history, 80, "Rescaled variance by %6.4f (stdev by %6.4f)", varianceFactor, stats->robustStdev);
-    psMetadataAddStr(outHDU->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, history);
-
-    psFree (stats);
-    return true;
+    return pmReadoutVarianceRenormalise(readout, maskBad, num, minValid, maxValid);
 }
Index: branches/eam_branches/20090820/psLib/src/db/psDB.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/db/psDB.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/db/psDB.c	(revision 25766)
@@ -2261,4 +2261,5 @@
     PS_DB_OP_LE,
     PS_DB_OP_GE,
+    PS_DB_OP_NE,
 } psDBOpValue;
 
@@ -2308,6 +2309,10 @@
             opStr = "<";
             op = PS_DB_OP_LT;
-        }
-    }
+        } else if (strstr(item->comment, "!=")) {
+            opStr = "!=";
+            op = PS_DB_OP_NE;
+        }
+    }
+
 
     // XXX why are >, < searches not supported here????
@@ -2341,4 +2346,7 @@
         case PS_DB_OP_EQ:
             psStringAppend(&query, "(ABS(%s - %.8f) < %.8f)", itemName, (float)(item->data.F32), PS_DB_FLT_PAD);
+            break;
+        case PS_DB_OP_NE:
+            psStringAppend(&query, "(ABS(%s - %.8f) >= %.8f)", itemName, (float)(item->data.F32), PS_DB_FLT_PAD);
             break;
         case PS_DB_OP_LE:
@@ -2360,4 +2368,7 @@
             psStringAppend(&query, "(ABS(%s - %.17f) < %.17f)", itemName, (float)(item->data.F64), PS_DB_DBL_PAD);
             break;
+        case PS_DB_OP_NE:
+            psStringAppend(&query, "(ABS(%s - %.17f) >= %.17f)", itemName, (float)(item->data.F64), PS_DB_DBL_PAD);
+            break;
         case PS_DB_OP_LE:
         case PS_DB_OP_LT:
@@ -2376,4 +2387,7 @@
         case PS_DB_OP_EQ:
             psStringAppend(&query, "%s = %d", itemName, (int)(item->data.B));
+            break;
+        case PS_DB_OP_NE:
+            psStringAppend(&query, "%s != %d", itemName, (int)(item->data.B));
             break;
         default:
@@ -2397,5 +2411,5 @@
                 psStringAppend(&query, "%s LIKE '%s'", itemName, item->data.str);
             } else {
-                psStringAppend(&query, "%s = '%s'", itemName, item->data.str);
+                psStringAppend(&query, "%s %s '%s'", itemName, opStr, item->data.str);
             }
         }
Index: branches/eam_branches/20090820/psLib/src/fits/psFits.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/fits/psFits.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/fits/psFits.c	(revision 25766)
@@ -344,6 +344,8 @@
 // Therefore, we implement our own version of moving to an extension specified by name.  The pure cfitsio
 // version is used if "conventions.compression" handling is turned off in the psFits structure.
-bool psFitsMoveExtName(const psFits* fits,
-                       const char* extname)
+static bool fitsMoveExtName(const psFits* fits, // FITS file
+                            const char* extname, // Extension name
+                            bool errors // Generate errors?
+    )
 {
     PS_ASSERT_FITS_NON_NULL(fits, false);
@@ -356,5 +358,7 @@
         // User wants to use cfitsio.  Good luck to them!
         if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
-            psFitsError(status, true, _("Could not find HDU '%s'"), extname);
+            if (errors) {
+                psFitsError(status, true, _("Could not find HDU '%s'"), extname);
+            }
             return false;
         }
@@ -378,5 +382,7 @@
         if (fits_movabs_hdu(fits->fd, i, &hdutype, &status)) {
             // We've run off the end
-            psFitsError(status, true, _("Could not find HDU with %s = '%s'"), extword, extname);
+            if (errors) {
+                psFitsError(status, true, _("Could not find HDU with %s = '%s'"), extword, extname);
+            }
             return false;
         }
@@ -406,4 +412,15 @@
     }
     psAbort("Should never reach here.");
+}
+
+
+bool psFitsMoveExtName(const psFits* fits, const char* extname)
+{
+    return fitsMoveExtName(fits, extname, true);
+}
+
+bool psFitsMoveExtNameClean(const psFits* fits, const char* extname)
+{
+    return fitsMoveExtName(fits, extname, false);
 }
 
@@ -878,4 +895,15 @@
         break;
 
+    case PS_TYPE_U64:
+        bitpix = LONGLONG_IMG;
+        bzero = -1.0 * INT64_MIN;
+        datatype = TLONGLONG;
+        break;
+
+    case PS_TYPE_S64:
+        bitpix = LONGLONG_IMG;
+        datatype = TLONGLONG;
+        break;
+
     case PS_TYPE_F32:
         bitpix = FLOAT_IMG;
@@ -904,4 +932,13 @@
                     _("Specified type, %s, is not supported."),
                     typeStr);
+            if (bitPix) {
+                *bitPix = 0;
+            }
+            if (dataType) {
+                *dataType = 0;
+            }
+            if (bZero) {
+                *bZero = 0;
+            }
             return false;
         }
@@ -943,2 +980,82 @@
     return PS_FITS_COMPRESS_NONE;
 }
+
+
+
+#if 0
+/// Options for FITS I/O
+typedef struct {
+    char *extword;                      ///< user-specified word to name extensions (NULL implies EXTNAME)
+    struct {
+        bool compression;               ///< Compression convention: handling of compressed images
+        bool psBitpix;                  ///< Custom floating-point image
+    } conventions;                      ///< Conventions to honour
+    // The following options are particular to writing images; they needn't be set for anything else.
+    psFitsFloat floatType;              ///< Desired custom floating-point for output images
+    int bitpix;                         ///< Desired BITPIX for output images; 0 to use as provided
+    psFitsScaling scaling;              ///< Scaling scheme to use when quantising floating-point values
+    bool fuzz;                          ///< Fuzz the values when quantising floating-point values?
+    double bscale, bzero;               ///< Manually specified BSCALE and BZERO (for SCALE_MANUAL)
+    double mean, stdev;                 ///< Mean and standard deviation of image
+    int stdevBits;                      ///< Number of bits to sample a standard deviation (for SCALE_STDEV_*)
+    float stdevNum;                     ///< Number of standard deviations to pad off the edge
+} psFitsOptions;
+
+bool psFitsCopyCompression(psFits *target, psFits *source)
+{
+    PS_ASSERT_FITS_NON_NULL(target, false);
+    PS_ASSERT_FITS_NON_NULL(source, false);
+
+    psMetadata *header = psMetadataReadHeader(NULL, source); // Header of source file
+
+    bool mdok;                          // Status of MD lookup
+    psString compTypeStr = psMetadataLookupStr(&mdok, header, "ZCMPTYPE"); // Compression type
+    psFitsCompressionType compType = psFitsCompressionTypeFromString(compTypeStr); // Compression type
+
+    if (!target->options) {
+        target->options = psFitsOptionsAlloc();
+    }
+
+    target->options->floatType = psFitsFloatImageCheck(source); // Custom floating-point type
+
+
+
+
+
+    target->options = psFitsOptionsAlloc();
+    target->options->scaling = PS_FITS_SCALE_MANUAL;
+    target->options->fuzz = false;
+    target->options->bitpix = bitpix;
+    target->options->bscale = bscale;
+    target->options->bzero = bzero;
+
+    psFitsSetCompression(sfile->fits, compType, tiles, 8, 0, 0);
+
+
+
+
+    // Get current BITPIX, BSCALE, BZERO, EXTNAME
+    // Probably not necessary to look the numerical values up in this
+    // way, but guards against changes to psLib and cfitsio FITS
+    // handling.
+    psMetadataItem *bitpixItem = psMetadataLookup(in->header, "BITPIX");
+    psAssert(bitpixItem, "Every FITS image should have BITPIX");
+    int bitpix = psMetadataItemParseS32(bitpixItem);
+    psMetadataItem *bscaleItem = psMetadataLookup(in->header, "BSCALE");
+
+    float bscale;
+    if (!bscaleItem) {
+        psWarning("BSCALE isn't set; defaulting to unity");
+        bscale = 1.0;
+    } else {
+        bscale = psMetadataItemParseF32(bscaleItem);
+    }
+    psMetadataItem *bzeroItem = psMetadataLookup(in->header, "BZERO");
+    float bzero;
+    if (!bzeroItem) {
+        psWarning("BZERO isn't set; defaulting to zero");
+        bzero = 0.0;
+    } else {
+        bzero = psMetadataItemParseF32(bzeroItem);
+    }
+#endif
Index: branches/eam_branches/20090820/psLib/src/fits/psFits.h
===================================================================
--- branches/eam_branches/20090820/psLib/src/fits/psFits.h	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/fits/psFits.h	(revision 25766)
@@ -245,4 +245,14 @@
 );
 
+/** Moves the FITS HDU to the specified extension name without generating errors.
+ *
+ *  @return bool        TRUE if the extension name was found and move was
+ *                      successful, otherwise FALSE
+ */
+bool psFitsMoveExtNameClean(
+    const psFits* fits,                ///< the psFits object to move
+    const char* extname                ///< the extension name
+);
+
 /** Moves the FITS HDU to the specified extension number
  *
Index: branches/eam_branches/20090820/psLib/src/fits/psFitsScale.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/fits/psFitsScale.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/fits/psFitsScale.c	(revision 25766)
@@ -319,7 +319,7 @@
                     value = (value - zero) * scale; \
                     if (options->fuzz) { \
-                       /* Add random factor [0,1): adds a variance of 1/12, */ \
+                       /* Add random factor [-0.5,0.5): adds a variance of 1/12, */ \
                        /* but preserves the expectation value */ \
-                        value += psRandomUniform(rng); \
+                        value += psRandomUniform(rng) - 0.5; \
                     } \
                     /* Check for underflow and overflow; set either to max */ \
Index: branches/eam_branches/20090820/psLib/src/imageops/psImageConvolve.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/imageops/psImageConvolve.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/imageops/psImageConvolve.c	(revision 25766)
@@ -678,4 +678,137 @@
 }
 
+static bool imageSmoothMaskPixels(psVector *out, const psImage *image, const psImage *mask,
+                                  psImageMaskType maskVal, const psVector *x, const psVector *y,
+                                  const psVector *gaussNorm, float minGauss, int size, int start, int stop)
+{
+    const psF32 *gauss = &gaussNorm->data.F32[size]; // Gaussian convolution kernel
+    int numCols = image->numCols, numRows = image->numRows; // Size of image
+    int xLast = numCols - 1, yLast = numRows - 1; // Last index
+    for (int i = start; i < stop; i++) {
+        int xPix = x->data.S32[i], yPix = y->data.S32[i]; // Pixel coordinates for smoothing
+
+        int yMin = PS_MAX(yPix - size, 0);
+        int yMax = PS_MIN(yPix + size, yLast);
+        int xMin = PS_MAX(xPix - size, 0);
+        int xMax = PS_MIN(xPix + size, xLast);
+
+        const float *yGauss = &gauss[yMin - yPix];
+
+        double ySumIG = 0.0, ySumG = 0.0;
+        for (int v = yMin; v <= yMax; v++, yGauss++) {
+            const float *xGauss = &gauss[xMin - xPix];
+            double xSumIG = 0.0, xSumG = 0.0;
+            const psImageMaskType *maskData = &mask->data.PS_TYPE_IMAGE_MASK_DATA[v][xMin];
+            const psF32 *imageData = &image->data.F32[v][xMin];
+            for (int u = xMin; u <= xMax; u++, xGauss++, imageData++, maskData++) {
+                if (*maskData & maskVal) {
+                    continue;
+                }
+                xSumIG += *imageData * *xGauss;
+                xSumG += *xGauss;
+            }
+            if (xSumG > minGauss) {
+                ySumIG += xSumIG * *yGauss;
+                ySumG += xSumG * *yGauss;
+            }
+        }
+
+        out->data.F32[i] = ySumG > minGauss ? ySumIG / ySumG : NAN;
+    }
+
+    return true;
+}
+
+static bool psImageSmoothMaskPixelsThread(psThreadJob *job)
+{
+    PS_ASSERT_THREAD_JOB_NON_NULL(job, false);
+    psAssert(job->args, "programming error: no job arguments");
+    psAssert(job->args->n == 11, "programming error: wrong number of job arguments");
+
+    psVector *out = job->args->data[0]; // Output vector
+    const psImage *image  = job->args->data[1]; // Input image
+    const psImage *mask   = job->args->data[2]; // Input mask
+    psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[3], PS_TYPE_IMAGE_MASK_DATA);
+    const psVector *x = job->args->data[4];
+    const psVector *y = job->args->data[5];
+    const psVector *gaussNorm = job->args->data[6];
+    float minGauss = PS_SCALAR_VALUE(job->args->data[7], F32);
+    int size = PS_SCALAR_VALUE(job->args->data[8], S32);
+    int start = PS_SCALAR_VALUE(job->args->data[9], S32);
+    int stop = PS_SCALAR_VALUE(job->args->data[10], S32);
+    return imageSmoothMaskPixels(out, image, mask, maskVal, x, y, gaussNorm,
+                                 minGauss, size, start, stop);
+}
+
+
+psVector *psImageSmoothMaskPixels(const psImage *image, const psImage *mask, psImageMaskType maskVal,
+                                  const psVector *x, const psVector *y,
+                                  float sigma, float numSigma, float minGauss)
+{
+    PS_ASSERT_IMAGE_NON_NULL(image, NULL);
+    PS_ASSERT_IMAGE_NON_NULL(mask, NULL);
+    PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_IMAGE_MASK, NULL);
+    PS_ASSERT_IMAGES_SIZE_EQUAL(image, mask, NULL);
+    PS_ASSERT_VECTOR_NON_NULL(x, NULL);
+    PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_S32, NULL);
+    PS_ASSERT_VECTOR_NON_NULL(y, NULL);
+    PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_S32, NULL);
+    PS_ASSERT_VECTORS_SIZE_EQUAL(x, y, NULL);
+
+    int size = sigma * numSigma + 0.5;  // Half-size of kernel
+
+    int num = x->n;                     // Number of pixels to smooth
+    psVector *out = psVectorAlloc(num, PS_TYPE_F32); // Output results
+
+    // Generate normalized gaussian
+    IMAGE_SMOOTH_GAUSS(gaussNorm, size, sigma, F32);
+
+    // Columns
+    if (threaded) {
+        int numThreads = psThreadPoolSize(); // Number of threads
+        int delta = (numThreads) ? num / numThreads + 1 : num; // Block of cols to do at once
+        for (int start = 0; start < num; start += delta) {
+            int stop = PS_MIN(start + delta, num);  // End of block
+
+            psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_SMOOTHMASK_PIXELS");
+            psArrayAdd(job->args, 1, out);
+            psArrayAdd(job->args, 1, (psImage*)image);
+            psArrayAdd(job->args, 1, (psImage*)mask);
+            PS_ARRAY_ADD_SCALAR(job->args, maskVal, PS_TYPE_IMAGE_MASK);
+            psArrayAdd(job->args, 1, (psVector*)x);
+            psArrayAdd(job->args, 1, (psVector*)y);
+            psArrayAdd(job->args, 1, gaussNorm);
+            PS_ARRAY_ADD_SCALAR(job->args, minGauss, PS_TYPE_F32);
+            PS_ARRAY_ADD_SCALAR(job->args, size, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, start, PS_TYPE_S32);
+            PS_ARRAY_ADD_SCALAR(job->args, stop, PS_TYPE_S32);
+            if (!psThreadJobAddPending(job)) {
+                psFree(job);
+                psFree(gaussNorm);
+                psFree(out);
+                return NULL;
+            }
+            psFree(job);
+        }
+    } else if (!imageSmoothMaskPixels(out, image, mask, maskVal, x, y,
+                                      gaussNorm, minGauss, size, 0, num)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to smooth pixels.");
+        psFree(gaussNorm);
+        psFree(out);
+        return NULL;
+    }
+
+    if (threaded && !psThreadPoolWait(true)) {
+        psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
+        psFree(gaussNorm);
+        psFree(out);
+        return NULL;
+    }
+
+    psFree(gaussNorm);
+    return out;
+}
+
+
 // Smooth an image with masked pixels
 // The calculation and calcMask images are *deliberately* backwards (row,col instead of col,row or
@@ -1325,7 +1458,7 @@
     if (threaded) {
         int numThreads = psThreadPoolSize(); // Number of threads
-        int deltaRows = (numThreads) ? numRows / numThreads : numRows; // Block of rows to do at once
+        int deltaRows = (numThreads) ? numRows / numThreads + 1 : numRows; // Block of rows to do at once
         for (int start = 0; start < numRows; start += deltaRows) {
-            int stop = PS_MIN (start + deltaRows, numRows);  // end of row block
+            int stop = PS_MIN(start + deltaRows, numRows);  // end of row block
 
             psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK");
@@ -1363,7 +1496,7 @@
     if (threaded) {
         int numThreads = psThreadPoolSize(); // Number of threads
-        int deltaCols = (numThreads) ? numCols / numThreads : numCols; // Block of cols to do at once
+        int deltaCols = (numThreads) ? numCols / numThreads + 1 : numCols; // Block of cols to do at once
         for (int start = 0; start < numCols; start += deltaCols) {
-            int stop = PS_MIN (start + deltaCols, numCols);  // end of col block
+            int stop = PS_MIN(start + deltaCols, numCols);  // end of col block
 
             psThreadJob *job = psThreadJobAlloc("PSLIB_IMAGE_CONVOLVE_MASK");
@@ -1486,4 +1619,10 @@
             psFree(task);
         }
+        {
+            psThreadTask *task = psThreadTaskAlloc("PSLIB_IMAGE_SMOOTHMASK_PIXELS", 9);
+            task->function = &psImageSmoothMaskPixelsThread;
+            psThreadTaskAdd(task);
+            psFree(task);
+        }
     } else if (!set && threaded) {
         psThreadTaskRemove("PSLIB_IMAGE_CONVOLVE_MASK");
Index: branches/eam_branches/20090820/psLib/src/imageops/psImageConvolve.h
===================================================================
--- branches/eam_branches/20090820/psLib/src/imageops/psImageConvolve.h	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/imageops/psImageConvolve.h	(revision 25766)
@@ -222,4 +222,18 @@
     );
 
+/// Smooth particular pixels on an image, allowing for masked pixels
+///
+/// Applies a circularly symmetric Gaussian smoothing first in x and then in y
+/// directions with just a vector.  This process is 2N faster than 2D convolutions (in general).
+psVector *psImageSmoothMaskPixels(
+    const psImage *image,               ///< Input image (F32)
+    const psImage *mask,                ///< Mask image
+    psImageMaskType maskVal,            ///< Value to mask
+    const psVector *x,                  ///< x coordinates
+    const psVector *y,                  ///< y coordinates
+    float sigma,                        ///< Width of the smoothing kernel (pixels)
+    float numSigma,                     ///< Size of the smoothing box (sigma)
+    float minGauss                      ///< Minimum fraction of Gaussian to accept
+    );
 
 psImage *psImageSmoothMask_Threaded(psImage *output,
Index: branches/eam_branches/20090820/psLib/src/imageops/psImageMap.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/imageops/psImageMap.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/imageops/psImageMap.c	(revision 25766)
@@ -386,2 +386,32 @@
     return result;
 }
+
+bool psImageMapCleanup (psImageMap *map) {
+
+    if ((map->map->numRows == 1) && (map->map->numCols == 1)) return true;
+
+    // find the weighted average of all pixels
+    float Sum = 0.0;
+    float Wt = 0.0;
+    for (int j = 0; j < map->map->numRows; j++) {
+        for (int i = 0; i < map->map->numCols; i++) {
+            if (!isfinite(map->map->data.F32[j][i])) continue;
+            Sum += map->map->data.F32[j][i] * map->error->data.F32[j][i];
+            Wt += map->error->data.F32[j][i];
+        }
+    }
+
+    float Mean = Sum / Wt;
+
+    // do any of the pixels in the map need to be repaired?
+    // XXX for now, we are just replacing bad pixels with the Mean
+    for (int j = 0; j < map->map->numRows; j++) {
+        for (int i = 0; i < map->map->numCols; i++) {
+            if (isfinite(map->map->data.F32[j][i]) &&
+                (map->error->data.F32[j][i] > 0.0)) continue;
+            map->map->data.F32[j][i] = Mean;
+        }
+    }
+    return true;
+}
+
Index: branches/eam_branches/20090820/psLib/src/imageops/psImageMap.h
===================================================================
--- branches/eam_branches/20090820/psLib/src/imageops/psImageMap.h	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/imageops/psImageMap.h	(revision 25766)
@@ -79,4 +79,6 @@
 psVector *psImageMapEvalVector (const psImageMap *map, const psVector *mask, psMaskType maskValue, const psVector *x, const psVector *y);
 
+bool psImageMapCleanup (psImageMap *map);
+
 /// @}
 #endif // #ifndef PS_IMAGE_MAP_H
Index: branches/eam_branches/20090820/psLib/src/imageops/psImageMapFit.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/imageops/psImageMapFit.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/imageops/psImageMapFit.c	(revision 25766)
@@ -33,4 +33,5 @@
 #include "psStats.h"
 #include "psImageBinning.h"
+#include "psImageStructManip.h"
 #include "psImageMap.h"
 // #include "psImagePixelInterpolate.h"
@@ -752,2 +753,65 @@
 }
 
+// this function repairs an image with NAN pixels (only valid for a small-scale map -- no robust mean)
+bool psImageMapRepair (psImage *image) {
+
+    // we are going to repair the image by:
+    // 1) finding NAN pixels
+    // 2) if any of the neighbors are valid,
+    //    replace with the mean of the neighbors
+    // 3) otherwise, replace with the image mean
+
+    // copy the image so the repaired pixels do not affect the input
+    psImage *fixed = psImageCopy (NULL, image, PS_TYPE_F32);
+
+    // find the global mean
+    float mean = 0.0;
+    float npix = 0.0;
+    for (int iy = 0; iy < image->numRows; iy++) {
+	for (int ix = 0; ix < image->numCols; ix++) {
+	    if (!isfinite(image->data.F32[iy][ix])) continue;
+	    mean += image->data.F32[iy][ix];
+	    npix += 1.0;
+	}
+    }
+    mean /= npix;
+
+    // find the NAN pixels:
+    for (int iy = 0; iy < image->numRows; iy++) {
+	for (int ix = 0; ix < image->numCols; ix++) {
+	    if (isfinite(image->data.F32[iy][ix])) {
+		fixed->data.F32[iy][ix] = image->data.F32[iy][ix];
+		continue;
+	    }
+
+	    // find mean of all possible neighbors
+	    float meanLocal = 0.0;
+	    float npixLocal = 0.0;
+	    for (int jy = -1; jy <= +1; jy++) {
+		int ny = iy + jy;
+		if (ny < 0) continue;
+		if (ny >= image->numRows) continue;
+		for (int jx = -1; jx <= +1; jx++) {
+		    int nx = ix + jx;
+		    if (nx < 0) continue;
+		    if (nx >= image->numCols) continue;
+		    if (!isfinite(image->data.F32[ny][nx])) continue;
+		    meanLocal += image->data.F32[ny][nx];
+		    npixLocal += 1.0;
+		}
+	    }
+	    meanLocal = (npixLocal > 0.0) ? meanLocal / npixLocal : mean;
+	    fixed->data.F32[iy][ix] = meanLocal;
+	}
+    }
+    
+    // find the NAN pixels:
+    for (int iy = 0; iy < image->numRows; iy++) {
+	for (int ix = 0; ix < image->numCols; ix++) {
+	    image->data.F32[iy][ix] = fixed->data.F32[iy][ix];
+	}
+    }
+    psFree (fixed);
+
+    return true;
+}
Index: branches/eam_branches/20090820/psLib/src/imageops/psImageMapFit.h
===================================================================
--- branches/eam_branches/20090820/psLib/src/imageops/psImageMapFit.h	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/imageops/psImageMapFit.h	(revision 25766)
@@ -46,3 +46,5 @@
     );
 
+bool psImageMapRepair (psImage *image);
+
 #endif
Index: branches/eam_branches/20090820/psLib/src/imageops/psImageMaskOps.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/imageops/psImageMaskOps.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/imageops/psImageMaskOps.c	(revision 25766)
@@ -223,4 +223,41 @@
     psError(PS_ERR_BAD_PARAMETER_VALUE,true,
 	    "The logical operation specified is incorrect\n");
+    return;
+}
+
+// perform the mask operation on the image pixels
+void psImageMaskPixels(psImage *image,
+                       const char *op,
+                       psImageMaskType maskValue)
+{
+    if (image == NULL) {
+        psError(PS_ERR_BAD_PARAMETER_NULL, true, "Invalid image input.  Image is NULL.\n");
+        return;
+    }
+
+# define MASK_IT_IMAGE(OP) \
+    for (int iy = 0; iy < image->numRows; iy++) { \
+        for (int ix = 0; ix < image->numCols; ix++) { \
+	    image->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] OP maskValue; \
+	} }
+
+    if ( !strncmp(op, "&", 2) || !strncmp(op, "AND", 5) ) {
+      MASK_IT_IMAGE (&=);
+      return;
+    } 
+    if ( !strncmp(op, "|", 2) || !strncmp(op, "OR", 5) ) {
+      MASK_IT_IMAGE (|=);
+      return;
+    } 
+    if ( !strncmp(op, "=", 2) || !strncmp(op, "EQUAL", 5) ) {
+      MASK_IT_IMAGE (=);
+      return;
+    } 
+    if ( !strncmp(op, "^", 2) || !strncmp(op, "XOR", 5) ) {
+      MASK_IT_IMAGE (^=);
+      return;
+    } 
+
+    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "The logical operation specified is incorrect\n");
     return;
 }
Index: branches/eam_branches/20090820/psLib/src/imageops/psImageMaskOps.h
===================================================================
--- branches/eam_branches/20090820/psLib/src/imageops/psImageMaskOps.h	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/imageops/psImageMaskOps.h	(revision 25766)
@@ -22,4 +22,13 @@
 #include "psStats.h"
 #include "psPixels.h"
+
+/** Perform the mask opertion on all image pixels
+ *
+ *  The pixels are set by combining the existing pixel value and the given maskValue
+ *  with a logical operation.  The allowed operations are =, AND, OR, and XOR.
+ */
+void psImageMaskPixels(psImage *image,
+                       const char *op,
+                       psImageMaskType maskValue);
 
 /** Sets the bits inside the region, ignoring pixels outside.
Index: branches/eam_branches/20090820/psLib/src/math/psPolynomialUtils.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/math/psPolynomialUtils.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/math/psPolynomialUtils.c	(revision 25766)
@@ -178,4 +178,6 @@
 }
 
+// XXX min position is relative to the pixel index; in psModules/src/objects/pmPeaks.c:AddPeak, we offset by 0.5,0.5
+// to get to pixel coordinates...
 psPlane psImageBicubeMin(const psPolynomial2D *poly)
 {
Index: branches/eam_branches/20090820/psLib/src/sys/psType.h
===================================================================
--- branches/eam_branches/20090820/psLib/src/sys/psType.h	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/sys/psType.h	(revision 25766)
@@ -141,5 +141,5 @@
 } psDataType;
 
-// macros to abstract the generic mask type : these values must be consistent 
+// macros to abstract the generic mask type : these values must be consistent
 #define PS_TYPE_MASK PS_TYPE_U8        /**< the psElemType to use for mask image */
 #define PS_TYPE_MASK_DATA U8           /**< the data member to use for mask image */
@@ -152,8 +152,8 @@
 // alternate versions if needed
 // #define PS_NOT_MASK(A)(UINT16_MAX-(A))
-// #define PS_NOT_MASK(A)(UINT32_MAX-(A)) 
+// #define PS_NOT_MASK(A)(UINT32_MAX-(A))
 // #define PS_NOT_MASK(A)(UINT64_MAX-(A))
 
-// macros to abstract the vector mask type : these values must be consistent 
+// macros to abstract the vector mask type : these values must be consistent
 #define PS_TYPE_VECTOR_MASK PS_TYPE_U8        /**< the psElemType to use for mask image */
 #define PS_TYPE_VECTOR_MASK_DATA U8           /**< the data member to use for mask image */
@@ -161,11 +161,11 @@
 #define PS_MIN_VECTOR_MASK_TYPE 0             /**< minimum valid Vector Mask value */
 #define PS_MAX_VECTOR_MASK_TYPE UINT8_MAX     /**< maximum valid Vector Mask value */
-typedef psU8 psVectorMaskType;			  ///< the C datatype for a mask image
+typedef psU8 psVectorMaskType;                    ///< the C datatype for a mask image
 #define PS_NOT_VECTOR_MASK(A)(UINT8_MAX-(A))
 
-// macros to abstract the image mask type : these values must be consistent 
-#define PS_TYPE_IMAGE_MASK PS_TYPE_U16	     /**< the psElemType to use for mask image */
-#define PS_TYPE_IMAGE_MASK_DATA U16	     /**< the data member to use for mask image */
-#define PS_TYPE_IMAGE_MASK_NAME "psU16"	     /**< the data type for mask as a string */
+// macros to abstract the image mask type : these values must be consistent
+#define PS_TYPE_IMAGE_MASK PS_TYPE_U16       /**< the psElemType to use for mask image */
+#define PS_TYPE_IMAGE_MASK_DATA U16          /**< the data member to use for mask image */
+#define PS_TYPE_IMAGE_MASK_NAME "psU16"      /**< the data type for mask as a string */
 #define PS_MIN_IMAGE_MASK_TYPE 0             /**< minimum valid Image Mask value */
 #define PS_MAX_IMAGE_MASK_TYPE UINT16_MAX    /**< maximum valid Image Mask value */
@@ -246,16 +246,4 @@
 };
 
-/// Macro to get the bad pixel reason code (stored as part of mask value)
-#define PS_BADPIXEL_BITMASK 0x0f
-#define PS_GET_BADPIXEL(maskValue) (maskValue & PS_BADPIXEL_BITMASK)
-
-#define PS_IS_BADPIXEL(maskValue) (PS_GET_BADPIXEL(maskValue) != 0)
-
-/// Macro to apply a bad pixel reason code to mask image
-#define PS_SET_BADPIXEL(maskValue, reasonCode) \
-{ \
-    maskValue = (psMaskType)((reasonCode & PS_BADPIXEL_BITMASK) | (maskValue & ~PS_BADPIXEL_BITMASK)); \
-}
-
 /// Macro to determine if the psElemType is an integer.
 #define PS_IS_PSELEMTYPE_INT(x) ((x & 0x100) == 0x100)
Index: branches/eam_branches/20090820/psLib/src/types/psMetadata.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/types/psMetadata.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/types/psMetadata.c	(revision 25766)
@@ -996,5 +996,4 @@
     if (metadataItem->type == PS_DATA_METADATA_MULTI) {
         // if multiple keys found, use the first.
-        //        metadataItem = (psMetadataItem*)((metadataItem->data.list)->head);
         metadataItem = (psMetadataItem*)(metadataItem->data.list->head->data);
         if (status) {
@@ -1082,5 +1081,4 @@
     } \
     \
-    /* psFree(metadataItem); currently, the lookup doesn't increment the ref count */ \
     return value; \
 }
@@ -1101,4 +1099,44 @@
 psMetadataLookupNumTYPE(VectorMaskType,VectorMask)
 psMetadataLookupNumTYPE(ImageMaskType,ImageMask)
+
+#define psMetadataLookupPtrTYPE(TYPENAME,NAME,TYPE,VAL) \
+TYPENAME psMetadataLookup##NAME(bool *status, const psMetadata *md, const char *key) \
+{ \
+    PS_ASSERT_METADATA_NON_NULL(md, NULL); \
+    PS_ASSERT_STRING_NON_EMPTY(key, NULL); \
+    psMetadataItem *item = psMetadataLookup((psMetadata*)md, key); /* The item of interest */ \
+    if (!item) { \
+        if (status) { \
+            *status = false; \
+        } else { \
+            psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n", key); \
+        } \
+        return NULL; \
+    } \
+    \
+    if (item->type == PS_DATA_METADATA_MULTI) { \
+        /* if multiple keys found, use the first. */ \
+        item = item->data.list->head->data; \
+    } \
+    if (item->type != TYPE) { \
+        if (status) { \
+            *status = false; \
+        } else { \
+            psLogMsg(__func__, PS_LOG_DETAIL, "%s isn't of type PS_DATA_META, as expected.\n", key); \
+        } \
+        return NULL; \
+    } \
+    \
+    if (status) { \
+        *status = true; \
+    } \
+    return item->data.VAL; \
+}
+
+psMetadataLookupPtrTYPE(psMetadata*, Metadata, PS_DATA_METADATA, md)
+psMetadataLookupPtrTYPE(psString, Str, PS_DATA_STRING, str)
+psMetadataLookupPtrTYPE(psTime*, Time, PS_DATA_TIME, V)
+psMetadataLookupPtrTYPE(psVector*, Vector, PS_DATA_VECTOR, V)
+
 
 psMetadataItem* psMetadataGet(const psMetadata *md,
@@ -1257,105 +1295,7 @@
 }
 
-psMetadata *psMetadataLookupMetadata(bool *status,
-                                     const psMetadata *md,
-                                     const char *key)
-{
-    PS_ASSERT_METADATA_NON_NULL(md,NULL);
-    psMetadataItem *item = psMetadataLookup((psMetadata*)md, key); // The metadata with instruments
-    psMetadata *value = NULL;  // The value to return
-    if (!item) {
-        // The given key isn't in the metadata
-        if (status) {
-            *status = false;
-        } else {
-            psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n", key);
-        }
-    } else if (item->type != PS_DATA_METADATA) {
-        // The value at the key isn't metadata
-        if (status) {
-            *status = false;
-        } else {
-            psLogMsg(__func__, PS_LOG_DETAIL, "%s isn't of type PS_DATA_META, as expected.\n", key);
-        }
-        //        value = NULL;
-    } else {
-        // We have the requested metadata
-        if (status) {
-            *status = true;
-        }
-        value = item->data.md; // The requested metadata
-    }
-    return value;
-}
-
-psTime *psMetadataLookupTime(bool *status,
-                             const psMetadata *md,
-                             const char *key)
-{
-    PS_ASSERT_METADATA_NON_NULL(md,NULL);
-
-    psMetadataItem *item = psMetadataLookup((psMetadata*)md, key);
-    if (!item) {
-        // The given key isn't in the metadata
-        if (status) {
-            *status = false;
-        } else {
-            psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n", key);
-        }
-        return NULL;
-    }
-
-    if (item->type != PS_DATA_TIME) {
-        // The value at the key isn't metadata
-        if (status) {
-            *status = false;
-        } else {
-            psLogMsg(__func__, PS_LOG_DETAIL, "%s isn't of type PS_DATA_TIME, as expected.\n", key);
-        }
-        return NULL;
-    }
-
-    // We have the requested metadata
-    if (status) {
-        *status = true;
-    }
-
-    return item->data.V;
-}
-
-
-psString psMetadataLookupStr(bool *status,
-                             const psMetadata *md,
-                             const char *key)
-{
-    PS_ASSERT_METADATA_NON_NULL(md,NULL);
-
-    psMetadataItem *item = psMetadataLookup((psMetadata*)md, key); // The metadata with instruments
-    //    char *value = NULL;   // The value to return
-    psString value = NULL;
-    if (!item) {
-        // The given key isn't in the metadata
-        if (status) {
-            *status = false;
-        } else {
-            psError(PS_ERR_IO, true, "Couldn't find %s in the metadata.\n", key);
-        }
-    } else if (item->type != PS_DATA_STRING) {
-        // The value at the key isn't of the desired type
-        if (status) {
-            *status = false;
-        } else {
-            psLogMsg(__func__, PS_LOG_DETAIL, "%s isn't of type PS_DATA_STRING, as expected.\n", key);
-        }
-        //        value = NULL;
-    } else {
-        // We have the requested metadata
-        if (status) {
-            *status = true;
-        }
-        value = item->data.V;
-    }
-    return value;
-}
+
+
+
 
 psList *psMetadataKeys(psMetadata *md)
Index: branches/eam_branches/20090820/psLib/src/types/psMetadata.h
===================================================================
--- branches/eam_branches/20090820/psLib/src/types/psMetadata.h	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/types/psMetadata.h	(revision 25766)
@@ -717,4 +717,5 @@
 PS_METADATA_LOOKUP_TYPE_DECL(Ptr, psPtr);
 PS_METADATA_LOOKUP_TYPE_DECL(Str, psString);
+PS_METADATA_LOOKUP_TYPE_DECL(Vector, psVector*);
 PS_METADATA_LOOKUP_TYPE_DECL(Metadata, psMetadata*);
 PS_METADATA_LOOKUP_TYPE_DECL(Time, psTime*);
Index: branches/eam_branches/20090820/psLib/src/types/psTree.c
===================================================================
--- branches/eam_branches/20090820/psLib/src/types/psTree.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/types/psTree.c	(revision 25766)
@@ -14,4 +14,6 @@
 #include "psTree.h"
 
+//#define INPUT_CHECK                   // Check inputs for functions that may be in a tight loop?
+
 
 // XXX Upgrades:
@@ -84,5 +86,5 @@
 }
 
-psTree *psTreeAlloc(int dim, int maxLeafContents, long numNodes)
+psTree *psTreeAlloc(int dim, int maxLeafContents, psTreeType type, long numNodes)
 {
     psAssert(dim > 0, "Dimensionality (%d) must be positive", dim);
@@ -95,4 +97,5 @@
     tree->dim = dim;
     tree->maxLeafContents = maxLeafContents;
+    tree->type = type;
 
     tree->numNodes = numNodes;
@@ -115,5 +118,5 @@
 
 
-psTree *psTreePlant(int dim, int maxLeafContents, ...)
+psTree *psTreePlant(int dim, int maxLeafContents, psTreeType type, ...)
 {
     PS_ASSERT_INT_POSITIVE(dim, NULL);
@@ -122,5 +125,5 @@
     // Parse coordinate list
     va_list args;                       // Variable argument list
-    va_start(args, maxLeafContents);
+    va_start(args, type);
     psArray *coords = psArrayAlloc(dim); // Array of coordinates
     long numData = 0;                   // Number of data points
@@ -145,8 +148,8 @@
         long pow2;                      // Smallest power of two >= numData
         for (pow2 = 1; pow2 < numData; pow2 <<= 1);
-        numNodes = PS_MIN(pow2 - 1, 2 * numData - pow2 / 2 - 1);
-    }
-
-    psTree *tree = psTreeAlloc(dim, maxLeafContents, numNodes);
+        numNodes = PS_MAX(PS_MIN(pow2 - 1, 2 * numData - pow2 / 2 - 1), 1);
+    }
+
+    psTree *tree = psTreeAlloc(dim, maxLeafContents, type, numNodes);
     tree->data = psTreeCoordArrayAlloc(numData, dim);
     tree->numData = numData;
@@ -199,4 +202,9 @@
     }
 
+    if (numData <= maxLeafContents) {
+        // Don't need to do any more work
+        return tree;
+    }
+
     psArray *work = psArrayAlloc(numNodes); // Work queue
     work->data[0] = root;
@@ -365,5 +373,5 @@
 psTreeNode *psTreeLeaf(const psTree *tree, const psVector *coords)
 {
-#if 1 // Might be in a tight loop
+#ifdef INPUT_CHECK // Might be in a tight loop
     PS_ASSERT_TREE_NON_NULL(tree, NULL);
     PS_ASSERT_VECTOR_NON_NULL(coords, NULL);
@@ -403,20 +411,41 @@
 {
     int dim = tree->dim;                // Dimensionality
-    switch (dim) {
-      case 2:
-        return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
-            PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]);
-      case 3:
-        return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
-            PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]) +
-            PS_SQR(coords->data.F64[2] - tree->data->F64[index][2]);
-      default: {
-          double distance2 = 0.0;             // Distance of interest
-          for (int i = 0; i < dim; i++) {
-              distance2 += PS_SQR(coords->data.F64[i] - tree->data->F64[index][i]);
+    switch (tree->type) {
+      case PS_TREE_EUCLIDEAN:
+        switch (dim) {
+          case 2:
+            return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
+                PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]);
+          case 3:
+            return PS_SQR(coords->data.F64[0] - tree->data->F64[index][0]) +
+                PS_SQR(coords->data.F64[1] - tree->data->F64[index][1]) +
+                PS_SQR(coords->data.F64[2] - tree->data->F64[index][2]);
+          default: {
+              double distance2 = 0.0;             // Distance of interest
+              for (int i = 0; i < dim; i++) {
+                  distance2 += PS_SQR(coords->data.F64[i] - tree->data->F64[index][i]);
+              }
+              return distance2;
           }
-          return distance2;
-      }
-    }
+        }
+        break;
+      case PS_TREE_SPHERICAL:
+        switch (dim) {
+          case 2: {
+              // Haversine formula
+              double dphi = coords->data.F64[1] - tree->data->F64[index][1];
+              double sindphi = sin(dphi / 2.0);
+              double dlambda = coords->data.F64[0] - tree->data->F64[index][0];
+              double sindlambda = sin(dlambda / 2.0);
+              return PS_SQR(sindphi) +
+                  cos(coords->data.F64[1]) * cos(tree->data->F64[index][1]) * PS_SQR(sindlambda);
+          }
+          default:
+            psAbort("Spherical distances not supported for more than 2 dimensions");
+        }
+      default:
+        psAbort("Unrecognised type: %x", tree->type);
+    }
+
     return NAN;
 }
@@ -430,10 +459,32 @@
         double minDiff = tree->min->F64[index][i] - coords->data.F64[i];
         if (minDiff > 0) {
-            distance += PS_SQR(minDiff);
+            switch (tree->type) {
+              case PS_TREE_EUCLIDEAN:
+                distance += PS_SQR(minDiff);
+                break;
+              case PS_TREE_SPHERICAL: {
+                  double sinDiff = sin(minDiff / 2.0);
+                  distance += PS_SQR(sinDiff);
+                  break;
+              }
+              default:
+                psAbort("Unrecognised type: %x", tree->type);
+            }
             continue;
         }
         double maxDiff = coords->data.F64[i] - tree->max->F64[index][i];
         if (maxDiff > 0) {
-            distance += PS_SQR(maxDiff);
+            switch (tree->type) {
+              case PS_TREE_EUCLIDEAN:
+                distance += PS_SQR(maxDiff);
+                break;
+              case PS_TREE_SPHERICAL: {
+                  double sinDiff = sin(maxDiff / 2.0);
+                  distance += PS_SQR(sinDiff);
+                  break;
+              }
+              default:
+                psAbort("Unrecognised type: %x", tree->type);
+            }
             continue;
         }
@@ -479,12 +530,12 @@
 }
 
-// Return the index of the nearest neighbour to given coordinates, within some radius
+// Return the index of the nearest neighbour to given coordinates, within some distance measure
 // This is the engine for psTreeNearest() and psTreeNearestWithin()
 static inline long treeNearestWithin(const psTree *tree, // Tree
                                      const psVector *coordinates, // Coordinates of interest
-                                     double bestDistance // Distance (radius-squared) to best point
+                                     double bestDistance // Distance measure to best point
     )
 {
-#if 1 // Might be in a tight loop
+#ifdef INPUT_CHECK // Might be in a tight loop
     PS_ASSERT_TREE_NON_NULL(tree, -1);
     PS_ASSERT_VECTOR_NON_NULL(coordinates, -1);
@@ -545,12 +596,31 @@
 
 
+// Convert a radius to our internal "distance measure"
+// Often, we're given a search radius, but for efficiency reasons, we don't use that internally.
+static double treeRadiusToDistance(const psTree *tree, double radius)
+{
+    switch (tree->type) {
+      case PS_TREE_EUCLIDEAN:
+        // Using the square of the distance as the distance measure
+        return PS_SQR(radius);
+      case PS_TREE_SPHERICAL: {
+          // Using a rearrangement of the Haversine formula
+          double sindist = sin(radius / 2.0);
+          return PS_SQR(sindist);
+      }
+      default:
+        psAbort("Unrecognised type: %x", tree->type);
+    }
+}
+
+
 long psTreeNearestWithin(const psTree *tree, const psVector *coords, double radius)
 {
-    return treeNearestWithin(tree, coords, PS_SQR(radius));
-}
-
-
-// Search a leaf node for points within radius squared
-static inline long treeLeafSearchWithin(double radius2, // Radius squared to search
+    return treeNearestWithin(tree, coords, treeRadiusToDistance(tree, radius));
+}
+
+
+// Search a leaf node for points within distance
+static inline long treeLeafSearchWithin(double distance, // Distance to search
                                         const psTree *tree, // Tree of interest
                                         const psTreeNode *leaf, // Leaf to search
@@ -561,6 +631,5 @@
     for (int i = 0; i < leaf->num; i++) {
         long index = leaf->contents[i]; // Index of point
-        double distance = treeContentDistance(tree, index, coords); // Distance to point
-        if (distance < radius2) {
+        if (treeContentDistance(tree, index, coords) < distance) {
             num++;
         }
@@ -572,5 +641,5 @@
 long psTreeWithin(const psTree *tree, const psVector *coordinates, double radius)
 {
-#if 1 // Might be in a tight loop
+#ifdef INPUT_CHECK // Might be in a tight loop
     PS_ASSERT_TREE_NON_NULL(tree, -1);
     PS_ASSERT_VECTOR_NON_NULL(coordinates, -1);
@@ -581,5 +650,5 @@
                         psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
 
-    radius *= radius;                   // We work with the radius-squared
+    double distance = treeRadiusToDistance(tree, radius); // Distance measure
     long num = 0;                       // Number of points in circle
 
@@ -588,5 +657,5 @@
     // Find the closest point in the leaf that contains the point of interest
     psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
-    num += treeLeafSearchWithin(radius, tree, leaf, coords);
+    num += treeLeafSearchWithin(distance, tree, leaf, coords);
 
     psArray *work = psArrayAlloc(tree->numNodes); // Work queue
@@ -605,5 +674,5 @@
             }
             // Leaf node
-            num += treeLeafSearchWithin(radius, tree, node, coords);
+            num += treeLeafSearchWithin(distance, tree, node, coords);
             work->data[workIndex] = NULL;
             workIndex--;
@@ -618,28 +687,28 @@
 }
 
-// Search a leaf node for any points within radius squared
-static inline bool treeLeafSearchWithinAny(double radius2, // Radius squared to search
-                                           const psTree *tree, // Tree of interest
-                                           const psTreeNode *leaf, // Leaf to search
-                                           const psVector *coords // Coordinates of interest
+// Search a leaf node for points within distance
+static inline void treeLeafSearchAllWithin(psVector *result,       // Result vector
+                                          double distance, // Distance to search
+                                          const psTree *tree, // Tree of interest
+                                          const psTreeNode *leaf, // Leaf to search
+                                          const psVector *coords // Coordinates of interest
     )
 {
     for (int i = 0; i < leaf->num; i++) {
         long index = leaf->contents[i]; // Index of point
-        double distance = treeContentDistance(tree, index, coords); // Distance to point
-        if (distance < radius2) {
-            return true;
-        }
-    }
-    return false;
-}
-
-// Given an arbitrary point and a matching radius, return whether there are any points within that radius
-bool psTreeWithinAny(const psTree *tree, const psVector *coordinates, double radius)
-{
-#if 1 // Might be in a tight loop
-    PS_ASSERT_TREE_NON_NULL(tree, false);
-    PS_ASSERT_VECTOR_NON_NULL(coordinates, false);
-    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, false);
+        if (treeContentDistance(tree, index, coords) < distance) {
+            psVectorAppend(result, index);
+        }
+    }
+    return;
+}
+
+// Given an arbitrary point and a matching radius, return the index of all points within that radius
+psVector *psTreeAllWithin(const psTree *tree, const psVector *coordinates, double radius)
+{
+#ifdef INPUT_CHECK // Might be in a tight loop
+    PS_ASSERT_TREE_NON_NULL(tree, NULL);
+    PS_ASSERT_VECTOR_NON_NULL(coordinates, NULL);
+    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, NULL);
 #endif
 
@@ -647,14 +716,13 @@
                         psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
 
-    radius *= radius;                   // We work with the radius-squared
-
-    // This is essentially the same as psTreeWithin, except we can bail as soon as we find something
+    double distance = treeRadiusToDistance(tree, radius); // Distance measure
+
+    psVector *result = psVectorAllocEmpty(4, PS_TYPE_S64); // Indices of points within match radius
+
+    // This is essentially the same as psTreeNearest, except we're not allowed to prune
 
     // Find the closest point in the leaf that contains the point of interest
     psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
-    if (treeLeafSearchWithinAny(radius, tree, leaf, coords)) {
-        psFree(coords);
-        return true;
-    }
+    treeLeafSearchAllWithin(result, distance, tree, leaf, coords);
 
     psArray *work = psArrayAlloc(tree->numNodes); // Work queue
@@ -673,5 +741,72 @@
             }
             // Leaf node
-            if (treeLeafSearchWithinAny(radius, tree, node, coords)) {
+            treeLeafSearchAllWithin(result, distance, tree, node, coords);
+            work->data[workIndex] = NULL;
+            workIndex--;
+        }
+
+        leaf = up;
+    }
+    psFree(work);
+    psFree(coords);
+
+    return result;
+}
+
+// Search a leaf node for any points within distance measure
+static inline bool treeLeafSearchWithinAny(double distance, // Distance to search
+                                           const psTree *tree, // Tree of interest
+                                           const psTreeNode *leaf, // Leaf to search
+                                           const psVector *coords // Coordinates of interest
+    )
+{
+    for (int i = 0; i < leaf->num; i++) {
+        long index = leaf->contents[i]; // Index of point
+        if (treeContentDistance(tree, index, coords) < distance) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// Given an arbitrary point and a matching radius, return whether there are any points within that radius
+bool psTreeWithinAny(const psTree *tree, const psVector *coordinates, double radius)
+{
+#ifdef INPUT_CHECK // Might be in a tight loop
+    PS_ASSERT_TREE_NON_NULL(tree, false);
+    PS_ASSERT_VECTOR_NON_NULL(coordinates, false);
+    PS_ASSERT_VECTOR_SIZE(coordinates, (long)tree->dim, false);
+#endif
+
+    psVector *coords = (coordinates->type.type == PS_TYPE_F64 ? psMemIncrRefCounter((psVector*)coordinates) :
+                        psVectorCopy(NULL, coordinates, PS_TYPE_F64)); // F64 version of coordinates
+
+    double distance = treeRadiusToDistance(tree, radius); // Distance measure
+
+    // This is essentially the same as psTreeWithin, except we can bail as soon as we find something
+
+    // Find the closest point in the leaf that contains the point of interest
+    psTreeNode *leaf = psTreeLeaf(tree, coords); // Leaf containing the point of interest
+    if (treeLeafSearchWithinAny(distance, tree, leaf, coords)) {
+        psFree(coords);
+        return true;
+    }
+
+    psArray *work = psArrayAlloc(tree->numNodes); // Work queue
+    while (leaf->up) {
+        psTreeNode *up = leaf->up;      // Parent node
+
+        long workIndex = 0;
+        work->data[workIndex] = (leaf == up->left ? up->right : up->left); // The other node
+        while (workIndex >= 0) {
+            psTreeNode *node = work->data[workIndex];
+            if (node->left) {
+                // Branch node
+                work->data[workIndex] = node->right;
+                work->data[++workIndex] = node->left;
+                continue;
+            }
+            // Leaf node
+            if (treeLeafSearchWithinAny(distance, tree, node, coords)) {
                 // Clear out the work queue
                 memset(work->data, 0, (workIndex + 1) * sizeof(void));
@@ -695,5 +830,5 @@
 psVector *psTreeCoords(psVector *out, const psTree *tree, long index)
 {
-#if 1 // Might be in a tight loop
+#ifdef INPUT_CHECK // Might be in a tight loop
     PS_ASSERT_TREE_NON_NULL(tree, NULL);
     PS_ASSERT_INT_NONNEGATIVE(index, NULL);
Index: branches/eam_branches/20090820/psLib/src/types/psTree.h
===================================================================
--- branches/eam_branches/20090820/psLib/src/types/psTree.h	(revision 25206)
+++ branches/eam_branches/20090820/psLib/src/types/psTree.h	(revision 25766)
@@ -16,4 +16,12 @@
 } psTreeCoordArray;
 
+/// Type of tree
+///
+/// Specifies how distances are measured
+typedef enum {
+    PS_TREE_EUCLIDEAN,                  // d^2 = dx^2 + dy^2 + ...
+    PS_TREE_SPHERICAL,                  // sin(dist/2)^2 = sin(dphi/2)^2 + cos(phi1)cos(phi2)sin(dlambda/2)^2
+} psTreeType;
+
 /// A simple kd-tree implementation
 ///
@@ -23,4 +31,5 @@
     int dim;                            ///< Dimensionality
     int maxLeafContents;                ///< Maximum number of points on a leaf
+    psTreeType type;                    ///< Type of tree
     long numNodes;                      ///< Number of nodes
     long numData;                       ///< Number of data points
@@ -67,4 +76,5 @@
 psTree *psTreeAlloc(int dim,            ///< Dimensionality
                     int maxLeafContents,///< Maximum number of points on a leaf
+                    psTreeType type,    ///< Type of tree
                     long numNodes       ///< Number of nodes in tree
                     );
@@ -75,4 +85,5 @@
 psTree *psTreePlant(int dim,            ///< Dimensionality
                     int maxLeafContents,///< Maximum number of points on a leaf
+                    psTreeType type,    ///< Type of tree
                     ...                 ///< psVector for each coordinate
                     );
@@ -108,4 +119,10 @@
                      );
 
+/// Return the index of all points within some radius of given coordinates
+psVector *psTreeAllWithin(const psTree *tree,          ///< Tree
+                          const psVector *coordinates, ///< Coordinates of interest
+                          double radius                ///< Radius of interest
+                          );
+
 /// Return the coordinates of a point in the tree, specified by its index
 psVector *psTreeCoords(psVector *out,   ///< Output vector, or NULL
Index: branches/eam_branches/20090820/psLib/test/types/tap_psTree.c
===================================================================
--- branches/eam_branches/20090820/psLib/test/types/tap_psTree.c	(revision 25206)
+++ branches/eam_branches/20090820/psLib/test/types/tap_psTree.c	(revision 25766)
@@ -3,11 +3,13 @@
 #include "pstap.h"
 
-#define NUM 10000                       // Number of points
+#define NUM 1000000                      // Number of points
+#define SPHERICAL_DISTANCE 3.0          // Distance of interest for spherical test
 
 int main(int argc, char *argv[])
 {
     psLibInit(NULL);
-    plan_tests(6);
+    plan_tests(13);
 
+    // Euclidean geometry: 6 tests
     {
         psMemId id = psMemGetId();
@@ -23,5 +25,5 @@
         psFree(rng);
 
-        psTree *tree = psTreePlant(2, 2, x, y);
+        psTree *tree = psTreePlant(2, 2, PS_TREE_EUCLIDEAN, x, y);
 
         ok(tree, "Tree planted");
@@ -35,5 +37,5 @@
             long closeIndex = psTreeNearest(tree, coords);
             psFree(coords);
-            ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found point: %ld", closeIndex);
+            ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found closest point: %ld", closeIndex);
 
             long bestIndex = -1;
@@ -68,4 +70,89 @@
     }
 
+    // Spherical geometry: 7 tests
+    {
+        psMemId id = psMemGetId();
+
+        psVector *ra = psVectorAlloc(NUM, PS_TYPE_F64);
+        psVector *dec = psVectorAlloc(NUM, PS_TYPE_F64);
+
+        psRandom *rng = psRandomAllocSpecific(PS_RANDOM_TAUS, 0);
+        for (int i = 0; i < NUM; i++) {
+            // Using http://mathworld.wolfram.com/SpherePointPicking.html
+            ra->data.F64[i] = psRandomUniform(rng);
+            dec->data.F64[i] = acos(2.0 * psRandomUniform(rng) - 1.0) - M_PI_2;
+        }
+
+        psTree *tree = psTreePlant(2, 2, PS_TREE_SPHERICAL, ra, dec);
+
+        ok(tree, "Tree planted");
+        skip_start(!tree, 4, "tree died");
+        {
+            //            psTreePrint(stderr, tree);
+
+            psVector *coords = psVectorAlloc(2, PS_TYPE_F64);
+            coords->data.F64[0] = psRandomUniform(rng);
+            coords->data.F64[1] = acos(2.0 * psRandomUniform(rng) - 1.0) - M_PI_2;
+
+            psVector *indices = psTreeAllWithin(tree, coords, DEG_TO_RAD(SPHERICAL_DISTANCE));
+            ok(indices && indices->type.type == PS_TYPE_S64, "got list of indices (%ld points)", indices->n);
+            long closeIndex = psTreeNearest(tree, coords);
+            ok(closeIndex >= 0 && closeIndex < tree->numNodes, "found closest point: %ld", closeIndex);
+
+            ok(psVectorSortInPlace(indices), "sorted indices");
+
+            bool allgood = true;        // All points in the appropriate place?
+            double bestDistance = INFINITY; // Distance to best point
+            long bestIndex = -1;        // Index of best point
+            for (long i = 0, j = 0; i < NUM; i++) {
+#if 1
+                // Traditional formula
+                double dist = acos(sin(coords->data.F64[1]) * sin(dec->data.F64[i]) +
+                                   cos(coords->data.F64[1]) * cos(dec->data.F64[i]) *
+                                   cos(coords->data.F64[0] - ra->data.F64[i]));
+#else
+                // Haversine formula: used in psTree
+                double dphi = coords->data.F64[1] - dec->data.F64[i];
+                double sindphi = sin(dphi/2.0);
+                double dlambda = coords->data.F64[0] - ra->data.F64[i];
+                double sindlambda = sin(dlambda/2.0);
+                double dist = 2.0 * asin(sqrt(PS_SQR(sindphi) +
+                                              cos(coords->data.F64[1]) * cos(dec->data.F64[i]) *
+                                              PS_SQR(sindlambda)));
+#endif
+                                              if (dist < bestDistance) {
+                    bestDistance = dist;
+                    bestIndex = i;
+                }
+                if (i == indices->data.S64[j]) {
+                    j++;
+                    if (dist > DEG_TO_RAD(SPHERICAL_DISTANCE)) {
+                        diag("%ld is in the list, but shouldn't be (%lf vs %lf)",
+                             i, RAD_TO_DEG(dist), SPHERICAL_DISTANCE);
+                        allgood = false;
+                    }
+                } else if (dist <= DEG_TO_RAD(SPHERICAL_DISTANCE)) {
+                    diag("%ld is not in the list, but should be (%lf vs %lf)",
+                         i, RAD_TO_DEG(dist), SPHERICAL_DISTANCE);
+                    allgood = false;
+                }
+            }
+            ok(allgood, "list is acurate");
+            ok(bestIndex == closeIndex, "correct point: %ld vs %ld", closeIndex, bestIndex);
+
+            psFree(coords);
+            psFree(indices);
+
+        }
+        skip_end();
+
+        psFree(rng);
+        psFree(tree);
+        psFree(ra);
+        psFree(dec);
+
+        ok(!psMemCheckLeaks(id, NULL, NULL, false), "no memory leaks");
+    }
+
     psLibFinalize();
 }
Index: branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryVisual.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryVisual.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryVisual.c	(revision 25766)
@@ -1209,6 +1209,11 @@
     KapaClearPlots (kapa2);
 
-    graphdata.color = KapaColorByName ("black");
-    graphdata.ptype = 2;
+    KapaSendLabel (kapa2, "X", KAPA_LABEL_XM);
+    KapaSendLabel (kapa2, "Y", KAPA_LABEL_YM);
+    KapaSendLabel (kapa2, "Chip Coordinates. Black = Raw Stars. Red = Ref Stars. Blue = Matched Stars", KAPA_LABEL_XP);
+
+    // X vs Y by mag (ref)
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 7;
     graphdata.style = 2;
 
@@ -1217,42 +1222,7 @@
     psFree (zVec);
 
-    xVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);
-    yVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);
-    zVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);
-
-    // X vs Y by mag (raw)
-    n = 0;
-    for (int i = 0; i < rawstars->n; i++) {
-        pmAstromObj *raw = rawstars->data[i];
-        if (!isfinite(raw->Mag)) continue;
-        if (raw->Mag < iMagMin) continue;
-        if (raw->Mag > iMagMax) continue;
-
-        xVec->data.F32[n] = raw->chip->x;
-        yVec->data.F32[n] = raw->chip->y;
-        zVec->data.F32[n] = raw->Mag;
-        n++;
-    }
-    xVec->n = yVec->n = zVec->n = n;
-
-    KapaSendLabel (kapa2, "X", KAPA_LABEL_XM);
-    KapaSendLabel (kapa2, "Y", KAPA_LABEL_YM);
-    KapaSendLabel (kapa2,
-                   "Chip Coordinates. Black = Raw Stars. Red = Ref Stars. Blue = Matched Stars"
-                   , KAPA_LABEL_XP);
-    pmVisualTriplePlot (kapa2, &graphdata, xVec, yVec, zVec, false);
-
-    // X vs Y by mag (ref)
-    psFree (xVec);
-    psFree (yVec);
-    psFree (zVec);
-
     xVec = psVectorAlloc (refstars->n, PS_TYPE_F32);
     yVec = psVectorAlloc (refstars->n, PS_TYPE_F32);
     zVec = psVectorAlloc (refstars->n, PS_TYPE_F32);
-
-    graphdata.color = KapaColorByName ("red");
-    graphdata.ptype = 7;
-    graphdata.style = 2;
 
     n = 0;
@@ -1269,5 +1239,5 @@
     }
     xVec->n = yVec->n = zVec->n = n;
-    pmVisualTripleOverplot (kapa2, &graphdata, xVec, yVec, zVec, false);
+    pmVisualTriplePlot (kapa2, &graphdata, xVec, yVec, zVec, false);
 
     //rescale the graph to include all points
@@ -1282,4 +1252,35 @@
     graphdata.ymax = PS_MAX(ymax, graphdata.ymax);
     KapaSetLimits (kapa2, &graphdata);
+
+    bool plotTweak;
+    pmVisualAskUser(&plotTweak);
+
+    // X vs Y by mag (raw)
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ptype = 2;
+    graphdata.style = 2;
+
+    psFree (xVec);
+    psFree (yVec);
+    psFree (zVec);
+
+    xVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);
+    yVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);
+    zVec = psVectorAlloc (rawstars->n, PS_TYPE_F32);
+
+    n = 0;
+    for (int i = 0; i < rawstars->n; i++) {
+        pmAstromObj *raw = rawstars->data[i];
+        if (!isfinite(raw->Mag)) continue;
+        if (raw->Mag < iMagMin) continue;
+        if (raw->Mag > iMagMax) continue;
+
+        xVec->data.F32[n] = raw->chip->x;
+        yVec->data.F32[n] = raw->chip->y;
+        zVec->data.F32[n] = raw->Mag;
+        n++;
+    }
+    xVec->n = yVec->n = zVec->n = n;
+    pmVisualTripleOverplot (kapa2, &graphdata, xVec, yVec, zVec, false);
 
     //overplot matched stars in blue
Index: branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryWCS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryWCS.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryWCS.c	(revision 25766)
@@ -289,4 +289,5 @@
     // test the CDELTi varient
     if (pcKeys) {
+        wcs->wcsCDkeys = 0;
         wcs->cdelt1 = psMetadataLookupF64 (&status, header, "CDELT1");
         wcs->cdelt2 = psMetadataLookupF64 (&status, header, "CDELT2");
@@ -334,4 +335,6 @@
     // test the CDi_j varient
     if (cdKeys) {
+        wcs->wcsCDkeys = 1;
+
         wcs->trans->x->coeff[1][0] = psMetadataLookupF64 (&status, header, "CD1_1"); // == PC1_1
         wcs->trans->x->coeff[0][1] = psMetadataLookupF64 (&status, header, "CD1_2"); // == PC1_2
@@ -375,42 +378,59 @@
     // XXX make it optional to write out CDi_j terms, or other versions
     // apply CDELT1,2 (degrees / pixel) to yield PCi,j terms of order unity
-    double cdelt1 = wcs->cdelt1;
-    double cdelt2 = wcs->cdelt2;
-    psMetadataAddF64 (header, PS_LIST_TAIL, "CDELT1", PS_META_REPLACE, "", cdelt1);
-    psMetadataAddF64 (header, PS_LIST_TAIL, "CDELT2", PS_META_REPLACE, "", cdelt2);
-
-    // test the PC00i00j varient:
-    psMetadataAddF64 (header, PS_LIST_TAIL, "PC001001", PS_META_REPLACE, "", wcs->trans->x->coeff[1][0] / cdelt1); // == PC1_1
-    psMetadataAddF64 (header, PS_LIST_TAIL, "PC001002", PS_META_REPLACE, "", wcs->trans->x->coeff[0][1] / cdelt2); // == PC1_2
-    psMetadataAddF64 (header, PS_LIST_TAIL, "PC002001", PS_META_REPLACE, "", wcs->trans->y->coeff[1][0] / cdelt1); // == PC2_1
-    psMetadataAddF64 (header, PS_LIST_TAIL, "PC002002", PS_META_REPLACE, "", wcs->trans->y->coeff[0][1] / cdelt2); // == PC2_2
-
-    // Elixir-style polynomial terms
-    // XXX currently, Elixir/DVO cannot accept mixed orders
-    // XXX need to respect the masks
-    // XXX is wcs->cdelt1,2 always consistent?
-    int fitOrder = wcs->trans->x->nX;
-    if (fitOrder > 1) {
+    if (!(wcs->wcsCDkeys)) {
+
+      double cdelt1 = wcs->cdelt1;
+      double cdelt2 = wcs->cdelt2;
+      psMetadataAddF64 (header, PS_LIST_TAIL, "CDELT1", PS_META_REPLACE, "", cdelt1);
+      psMetadataAddF64 (header, PS_LIST_TAIL, "CDELT2", PS_META_REPLACE, "", cdelt2);
+      
+      // test the PC00i00j varient:
+      psMetadataAddF64 (header, PS_LIST_TAIL, "PC001001", PS_META_REPLACE, "", wcs->trans->x->coeff[1][0] / cdelt1); // == PC1_1
+      psMetadataAddF64 (header, PS_LIST_TAIL, "PC001002", PS_META_REPLACE, "", wcs->trans->x->coeff[0][1] / cdelt2); // == PC1_2
+      psMetadataAddF64 (header, PS_LIST_TAIL, "PC002001", PS_META_REPLACE, "", wcs->trans->y->coeff[1][0] / cdelt1); // == PC2_1
+      psMetadataAddF64 (header, PS_LIST_TAIL, "PC002002", PS_META_REPLACE, "", wcs->trans->y->coeff[0][1] / cdelt2); // == PC2_2
+      
+      // Elixir-style polynomial terms
+      // XXX currently, Elixir/DVO cannot accept mixed orders
+      // XXX need to respect the masks
+      // XXX is wcs->cdelt1,2 always consistent?
+      int fitOrder = wcs->trans->x->nX;
+      if (fitOrder > 1) {
         for (int i = 0; i <= fitOrder; i++) {
-            for (int j = 0; j <= fitOrder; j++) {
-                if (i + j < 2)
-                    continue;
-                if (i + j > fitOrder)
-                    continue;
-                sprintf (name, "PCA1X%1dY%1d", i, j);
-                psMetadataAddF64 (header, PS_LIST_TAIL, name, PS_META_REPLACE, "", wcs->trans->x->coeff[i][j] / pow(cdelt1, i) / pow(cdelt2, j));
-                sprintf (name, "PCA2X%1dY%1d", i, j);
-                psMetadataAddF64 (header, PS_LIST_TAIL, name, PS_META_REPLACE, "", wcs->trans->y->coeff[i][j] / pow(cdelt1, i) / pow(cdelt2, j));
-            }
+	  for (int j = 0; j <= fitOrder; j++) {
+	    if (i + j < 2)
+	      continue;
+	    if (i + j > fitOrder)
+	      continue;
+	    sprintf (name, "PCA1X%1dY%1d", i, j);
+	    psMetadataAddF64 (header, PS_LIST_TAIL, name, PS_META_REPLACE, "", wcs->trans->x->coeff[i][j] / pow(cdelt1, i) / pow(cdelt2, j));
+	    sprintf (name, "PCA2X%1dY%1d", i, j);
+	    psMetadataAddF64 (header, PS_LIST_TAIL, name, PS_META_REPLACE, "", wcs->trans->y->coeff[i][j] / pow(cdelt1, i) / pow(cdelt2, j));
+	  }
         }
         psMetadataAddS32 (header, PS_LIST_TAIL, "NPLYTERM", PS_META_REPLACE, "", fitOrder);
-    }
-
-    // remove any existing 'CDi_j style' wcs keywords
-    if (psMetadataLookup(header, "CD1_1")) {
+      }
+      
+      // remove any existing 'CDi_j style' wcs keywords
+      if (psMetadataLookup(header, "CD1_1")) {
         psMetadataRemoveKey(header, "CD1_1");
         psMetadataRemoveKey(header, "CD1_2");
         psMetadataRemoveKey(header, "CD2_1");
         psMetadataRemoveKey(header, "CD2_2");
+      }
+    }
+    if (wcs->wcsCDkeys) {
+
+      psMetadataAddF64 (header, PS_LIST_TAIL, "CD1_1", PS_META_REPLACE, "", wcs->trans->x->coeff[1][0]);
+      psMetadataAddF64 (header, PS_LIST_TAIL, "CD1_2", PS_META_REPLACE, "", wcs->trans->x->coeff[0][1]);
+      psMetadataAddF64 (header, PS_LIST_TAIL, "CD2_1", PS_META_REPLACE, "", wcs->trans->y->coeff[1][0]);
+      psMetadataAddF64 (header, PS_LIST_TAIL, "CD2_2", PS_META_REPLACE, "", wcs->trans->y->coeff[0][1]);
+
+      if (psMetadataLookup(header, "PC001001")) {
+	psMetadataRemoveKey(header, "PC001001");
+	psMetadataRemoveKey(header, "PC001002");
+	psMetadataRemoveKey(header, "PC002001");
+	psMetadataRemoveKey(header, "PC002002");
+      }
     }
 
@@ -535,4 +555,6 @@
         fpa->toSky->R -= 2.0*M_PI;
 
+    fpa->wcsCDkeys = wcs->wcsCDkeys;
+
     psTrace ("psastro", 5, "toFPA: %f %f  (%f,%f),(%f,%f)\n",
              chip->toFPA->x->coeff[0][0], chip->toFPA->y->coeff[0][0],
@@ -704,4 +726,5 @@
     wcs->cdelt2 = hypot (wcs->trans->y->coeff[1][0], wcs->trans->y->coeff[0][1]);
 
+    wcs->wcsCDkeys = fpa->wcsCDkeys;
     psFree (toTPA);
 
@@ -944,4 +967,5 @@
     wcs->trans = psPlaneTransformAlloc (nXorder, nYorder);
     wcs->toSky = NULL;
+    wcs->wcsCDkeys = 0;
 
     memset (wcs->ctype1, 0, PM_ASTROM_WCS_TYPE_SIZE);
Index: branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryWCS.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryWCS.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/astrom/pmAstrometryWCS.h	(revision 25766)
@@ -23,4 +23,5 @@
     double crpix1, crpix2;
     double cdelt1, cdelt2;
+    bool wcsCDkeys;
     psProjection *toSky;
     psPlaneTransform *trans;
Index: branches/eam_branches/20090820/psModules/src/camera/pmFPA.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/camera/pmFPA.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/camera/pmFPA.h	(revision 25766)
@@ -48,4 +48,5 @@
     psPlaneTransform *toTPA;  ///< Transformation from focal plane to tangent plane, or NULL
     psProjection *toSky;         ///< Projection from tangent plane to sky, or NULL
+    bool wcsCDkeys;
     // Information
     psMetadata *concepts;               ///< FPA-level concepts
Index: branches/eam_branches/20090820/psModules/src/camera/pmFPAMaskWeight.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/camera/pmFPAMaskWeight.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/camera/pmFPAMaskWeight.c	(revision 25766)
@@ -111,6 +111,6 @@
         // psError(PS_ERR_IO, true, "CELL.SATURATION is not set --- unable to set mask.\n");
         // return false;
-	psWarning("CELL.SATURATION is not set --- completely masking cell.\n");
-	saturation = NAN;
+        psWarning("CELL.SATURATION is not set --- completely masking cell.\n");
+        saturation = NAN;
     }
     float bad = psMetadataLookupF32(&mdok, cell->concepts, "CELL.BAD"); // Bad level
@@ -118,10 +118,10 @@
         // psError(PS_ERR_IO, true, "CELL.BAD is not set --- unable to set mask.\n");
         // return false;
-	psWarning("CELL.BAD is not set --- completely masking cell.\n");
-	bad = NAN;
+        psWarning("CELL.BAD is not set --- completely masking cell.\n");
+        bad = NAN;
     }
     psTrace("psModules.camera", 5, "Saturation: %f, bad: %f\n", saturation, bad);
 
-    // if CELL.GAIN or CELL.READNOISE are not set, then the variance will be set to NAN; 
+    // if CELL.GAIN or CELL.READNOISE are not set, then the variance will be set to NAN;
     // in this case, we have to set the mask as well
     float gain = psMetadataLookupF32(&mdok, cell->concepts, "CELL.GAIN"); // Cell gain
@@ -140,6 +140,6 @@
     // completely mask if SATURATION or BAD are invalid
     if (isnan(saturation) || isnan(bad) || isnan(gain) || isnan(readnoise)) {
-	psImageInit(mask, badMask);
-	return true;
+        psImageInit(mask, badMask);
+        return true;
     }
 
@@ -230,5 +230,5 @@
         // return false;
         psWarning("CELL.GAIN is not set --- setting variance to NAN\n");
-	gain = NAN;
+        gain = NAN;
     }
     float readnoise = psMetadataLookupF32(&mdok, cell->concepts, "CELL.READNOISE"); // Cell read noise
@@ -237,5 +237,5 @@
         // return false;
         psWarning("CELL.READNOISE is not set --- setting variance to NAN\n");
-	readnoise = NAN;
+        readnoise = NAN;
     }
     // if we have a non-NAN readnoise, then we need to ensure it has been updated (not necessary if NAN)
@@ -248,10 +248,10 @@
     if (isnan(gain) || isnan(readnoise)) {
         if (!readout->variance) {
-	    // generate the image if needed
+            // generate the image if needed
             readout->variance = psImageAlloc(readout->image->numCols, readout->image->numRows, PS_TYPE_F32);
         }
-	// XXX need to set the mask, if defined
+        // XXX need to set the mask, if defined
         psImageInit(readout->variance, NAN);
-	return true;
+        return true;
     }
 
@@ -262,5 +262,5 @@
 
         // a negative variance is non-sensical. if the image value drops below 1, the variance must be 1.
-	// XXX this calculation is wrong: limit is 1 e-, but this is in DN
+        // XXX this calculation is wrong: limit is 1 e-, but this is in DN
         readout->variance = (psImage*)psUnaryOp(readout->variance, readout->variance, "abs");
         readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "max",
@@ -276,9 +276,9 @@
     // apply a supplied readnoise map (NOTE: in DN, not electrons):
     if (noiseMap) {
-	psImage *rdVar = (psImage*)psBinaryOp(NULL, (const psPtr) noiseMap, "*", (const psPtr) noiseMap);
-	readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", rdVar);
-	psFree (rdVar);
+        psImage *rdVar = (psImage*)psBinaryOp(NULL, (const psPtr) noiseMap, "*", (const psPtr) noiseMap);
+        readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", rdVar);
+        psFree (rdVar);
     } else {
-	readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", psScalarAlloc(readnoise*readnoise/gain/gain, PS_TYPE_F32));
+        readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", psScalarAlloc(readnoise*readnoise/gain/gain, PS_TYPE_F32));
     }
 
@@ -362,6 +362,6 @@
 
 
-bool pmReadoutVarianceRenormPixels(const pmReadout *readout, psImageMaskType maskVal,
-                                 psStatsOptions meanStat, psStatsOptions stdevStat, psRandom *rng)
+bool pmReadoutVarianceRenormalise(const pmReadout *readout, psImageMaskType maskVal,
+                                  int sample, float minValid, float maxValid)
 {
     PM_ASSERT_READOUT_NON_NULL(readout, false);
@@ -371,263 +371,80 @@
     psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout parts
 
-    if (!psMemIncrRefCounter(rng)) {
-        rng = psRandomAlloc(PS_RANDOM_TAUS);
-    }
-
-    psStats *varianceStats = psStatsAlloc(meanStat);// Statistics for mean
-    if (!psImageBackground(varianceStats, NULL, variance, mask, maskVal, rng)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to measure mean variance for image");
-        psFree(varianceStats);
-        psFree(rng);
-        return false;
-    }
-    float meanVariance = varianceStats->robustMedian; // Mean variance
-    psFree(varianceStats);
-
-    psStats *imageStats = psStatsAlloc(stdevStat);// Statistics for mean
-    if (!psImageBackground(imageStats, NULL, image, mask, maskVal, rng)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to measure stdev of image");
-        psFree(imageStats);
-        psFree(rng);
-        return false;
-    }
-    float stdevImage = imageStats->robustStdev; // Standard deviation of image
-    psFree(imageStats);
-    psFree(rng);
-
-    float correction = PS_SQR(stdevImage) / meanVariance; // Correction to take variance to what it should be
-    psLogMsg("psModules.camera", PS_LOG_INFO, "Renormalising variance map by %f", correction);
-    psBinaryOp(variance, variance, "*", psScalarAlloc(correction, PS_TYPE_F32));
-
-    return true;
-}
-
-
-bool pmReadoutVarianceRenormPhot(const pmReadout *readout, psImageMaskType maskVal, int num, float width,
-                               psStatsOptions meanStat, psStatsOptions stdevStat, psRandom *rng)
-{
-    PM_ASSERT_READOUT_NON_NULL(readout, false);
-    PM_ASSERT_READOUT_IMAGE(readout, false);
-    PM_ASSERT_READOUT_VARIANCE(readout, false);
-
-    if (!psMemIncrRefCounter(rng)) {
-        rng = psRandomAlloc(PS_RANDOM_TAUS);
-    }
-
-    psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout images
-
-    // Measure background
-    psStats *bgStats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);// Statistics for background
-    if (!psImageBackground(bgStats, NULL, image, mask, maskVal, rng)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to measure background for image");
-        psFree(bgStats);
-        psFree(rng);
-        return false;
-    }
-    float bgMean = bgStats->robustMedian; // Background level
-    float bgNoise = bgStats->robustStdev; // Background standard deviation
-    psFree(bgStats);
-    psTrace("psModules.camera", 5, "Background is %f +/- %f\n", bgMean, bgNoise);
-
-
-    // Construct kernels for flux measurement
-    // We use N(0,width) and N(0,width/sqrt(2)) kernels, following psphotSignificanceImage.
-    float sigFactor = 4.0 * M_PI * PS_SQR(width); // Factor for conversion from im/wt ratio to significance
-    int size = RENORM_NUM_SIGMA, fullSize = 2 * size + 1; // Half-size and full size of Gaussian
-    psVector *gauss = psVectorAlloc(fullSize, PS_TYPE_F32); // Gaussian for weighting
-    psVector *gauss2 = psVectorAlloc(fullSize, PS_TYPE_F32); // Gaussian squared
-    for (int i = 0, x = -size; i < fullSize; i++, x++) {
-        gauss->data.F32[i] = expf(-0.5 * PS_SQR(x) / PS_SQR(width));
-        gauss2->data.F32[i] = expf(-PS_SQR(x) / PS_SQR(width));
-    }
-
-    // Size of image
-    int numCols = image->numCols, numRows = image->numRows; // Size of images
-    int xSize = numCols - fullSize, ySize = numRows - fullSize; // Size of consideration
-    int xOffset = size, yOffset = size;       // Offset to region of consideration
-
-    // Measure fluxes
-    float peakFlux = RENORM_PEAK * bgNoise;     // Peak flux for fake sources
-    psVector *noise = psVectorAlloc(num, PS_TYPE_F32); // Measurements of the noise
-    psVector *source = psVectorAlloc(num, PS_TYPE_F32); // Measurements of fake sources
-    psVector *guess = psVectorAlloc(num, PS_TYPE_F32); // Guess at significance
-    psVector *photMask = psVectorAlloc(num, PS_TYPE_VECTOR_MASK); // Mask for fluxes
-    for (int i = 0; i < num; i++) {
-        // Coordinates of interest
-        int xPix = psRandomUniform(rng) * xSize + xOffset + 0.5;
-        int yPix = psRandomUniform(rng) * ySize + yOffset + 0.5;
-        psAssert(xPix - size >= 0 && xPix + size < numCols &&
-                 yPix - size >= 0 && yPix + size < numRows,
-                 "Bad pixel position: %d,%d", xPix, yPix);
-
-        // Weighted aperture photometry
-        // This has the same effect as smoothing the image by the window function
-        float sumNoise = 0.0;       // Sum for noise measurement
-        float sumSource = 0.0;      // Sum for source measurement
-        float sumVariance = 0.0;      // Sum for variance measurement
-        float sumGauss = 0.0, sumGauss2 = 0.0; // Sums of Gaussian kernels
-        for (int v = 0, y = yPix - size; v < fullSize; v++, y++) {
-            float xSumNoise = 0.0;  // Sum for noise measurement in x
-            float xSumSource = 0.0; // Sum for source measurement in x
-            float xSumVariance = 0.0; // Sum for variance measurement in x
-            float xSumGauss = 0.0, xSumGauss2 = 0.0; // Sums of Gaussian kernels in x
-            float yGauss = gauss->data.F32[v]; // Value of Gaussian in y
-            for (int u = 0, x = xPix - size; u < fullSize; u++, x++) {
-                if (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) {
+    int numCols = image->numCols, numRows = image->numRows; // Size of image
+    int numPix = numCols * numRows;                         // Number of pixels
+    int num = PS_MAX(sample, numPix);                       // Number we care about
+    psVector *signoise = psVectorAllocEmpty(num, PS_TYPE_F32);   // Signal-to-noise values
+
+    if (num >= numPix) {
+        // We have an image smaller than Nsubset, so just loop over the image pixels
+        int index = 0;                  // Index for vector
+        for (int y = 0; y < numRows; y++) {
+            for (int x = 0; x < numCols; x++) {
+                if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) ||
+                    !isfinite(image->data.F32[y][x]) || !isfinite(variance->data.F32[y][x])) {
                     continue;
                 }
-                float value = image->data.F32[y][x] - bgMean; // Value of image
-                float xGauss = gauss->data.F32[u]; // Value of Gaussian in x
-                float xGauss2 = gauss2->data.F32[u]; // Value of Gaussian^2 in x
-                xSumNoise += value * xGauss;
-                xSumSource += (value + peakFlux * xGauss * yGauss) * xGauss;
-                xSumVariance += variance->data.F32[y][x] * xGauss2;
-                xSumGauss += xGauss;
-                xSumGauss2 += xGauss2;
-            }
-            float yGauss2 = gauss2->data.F32[v]; // Value of Gaussian^2 in y
-            sumNoise += xSumNoise * yGauss;
-            sumSource += xSumSource * yGauss;
-            sumVariance += xSumVariance * yGauss2;
-            sumGauss += xSumGauss * yGauss;
-            sumGauss2 += xSumGauss2 * yGauss2;
-        }
-
-        photMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = ((isfinite(sumNoise) && isfinite(sumSource) &&
-                                                isfinite(sumVariance) && sumGauss > 0 && sumGauss2 > 0) ?
-                                               0 : 0xFF);
-
-        float smoothImageNoise = sumNoise / sumGauss; // Value of smoothed image pixel for noise
-        float smoothImageSource = sumSource / sumGauss; // Value of smoothed image pixel for source
-        float smoothVariance = sumVariance / sumGauss2; // Value of smoothed variance pixel
-
-        noise->data.F32[i] = smoothImageNoise;
-        source->data.F32[i] = smoothImageSource;
-        guess->data.F32[i] = (sumSource > 0) ? sigFactor * PS_SQR(smoothImageSource) / smoothVariance : 0.0;
-        psTrace("psModules.camera", 10, "Flux %d (%d,%d): %f, %f, %f\n",
-                i, xPix, yPix, smoothImageNoise, smoothImageSource, smoothVariance);
-    }
-    psFree(gauss);
-    psFree(gauss2);
-    psFree(rng);
-
-    // Standard deviation of fluxes gives us the real significance
-    psStats *stdevStats = psStatsAlloc(stdevStat); // Statistics
-    if (!psVectorStats(stdevStats, noise, NULL, photMask, 0xFF)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to measure standard deviation of fluxes");
-        psFree(stdevStats);
-        psFree(noise);
-        psFree(source);
-        psFree(guess);
-        psFree(photMask);
+
+                signoise->data.F32[index] = image->data.F32[y][x] / sqrtf(variance->data.F32[y][x]);
+                index++;
+            }
+        }
+        signoise->n = index;
+    } else {
+        psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
+        int index = 0;                  // Index for vector
+        for (long i = 0; i < num; i++) {
+            // Pixel coordinates
+            int pixel = numPix * psRandomUniform(rng);
+            int x = pixel % numCols;
+            int y = pixel / numCols;
+
+            if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) ||
+                !isfinite(image->data.F32[y][x]) || !isfinite(variance->data.F32[y][x])) {
+                continue;
+            }
+
+            signoise->data.F32[index] = image->data.F32[y][x] / sqrtf(variance->data.F32[y][x]);
+            index++;
+        }
+        signoise->n = index;
+        psFree(rng);
+    }
+
+    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_STDEV); // Statistics
+
+    if (!psVectorStats(stats, signoise, NULL, NULL, 0)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to measure statistics on S/N image");
+        psFree(signoise);
         return false;
     }
-    float stdev = psStatsGetValue(stdevStats, stdevStat); // Standard deviation of fluxes
-    psFree(stdevStats);
-    psFree(noise);
-    psTrace("psModules.camera", 5, "Standard deviation of fluxes is %f\n", stdev);
-
-    // Ratio of measured significance to guessed significance
-    psVector *ratio = psVectorAlloc(num, PS_TYPE_F32); // Ratio of measured to guess
-    for (int i = 0; i < num; i++) {
-        float measuredSig = PS_SQR(source->data.F32[i] / stdev); // Measured significance
-        ratio->data.F32[i] = measuredSig / guess->data.F32[i];
-        if (guess->data.F32[i] <= 0.0 || source->data.F32[i] <= 0.0 || !isfinite(ratio->data.F32[i])) {
-            photMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xFF;
-        }
-        psTrace("psModules.camera", 9, "Ratio %d: %f, %f, %f\n",
-                i, guess->data.F32[i], measuredSig, ratio->data.F32[i]);
-    }
-    psFree(source);
-    psFree(guess);
-
-    psStats *meanStats = psStatsAlloc(meanStat | stdevStat); // Statistics
-    if (!psVectorStats(meanStats, ratio, NULL, photMask, 0xFF)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to measure mean ratio");
-        psFree(meanStats);
-        psFree(ratio);
-        psFree(photMask);
-        return false;
-    }
-    float meanRatio = psStatsGetValue(meanStats, meanStat); // Mean ratio
-    psTrace("psModules.camera", 5, "Mean significance ratio is %f +/- %f\n",
-            meanRatio, psStatsGetValue(meanStats, stdevStat));
-    psFree(meanStats);
-    psFree(ratio);
-    psFree(photMask);
-
-    psLogMsg("psModules.camera", PS_LOG_INFO, "Renormalising variance map by %f", meanRatio);
-    psBinaryOp(variance, variance, "*", psScalarAlloc(meanRatio, PS_TYPE_F32));
+    psFree(signoise);
+
+    float covar = sqrtf(psImageCovarianceFactor(readout->covariance)); // Covariance factor
+    float correction = stats->robustStdev / covar; // Correction factor
+    psFree(stats);
+    psLogMsg("psModules.camera", PS_LOG_DETAIL, "Variance renormalisation factor is %f", correction);
+
+    // Check valid range of correction factor
+    if ((isfinite(minValid) && correction < minValid) || (isfinite(maxValid) && correction > maxValid)) {
+        psWarning("Variance renormalisation is outside valid range: %f vs %f:%f --- no correction made",
+                  correction, minValid, maxValid);
+        return true;
+    }
+
+    psBinaryOp(variance, variance, "*", psScalarAlloc(PS_SQR(correction), PS_TYPE_F32));
+
+    pmHDU *hdu = pmHDUFromReadout(readout); // HDU for readout
+    if (hdu)  {
+        psString history = NULL;
+        psStringAppend(&history, "Rescaled variance by %6.4f (stdev by %6.4f)",
+                       PS_SQR(correction), correction);
+        psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, history);
+        psFree(history);
+    }
 
     return true;
 }
 
-
-bool pmReadoutVarianceRenorm(const pmReadout *readout, psImageMaskType maskVal, psStatsOptions meanStat,
-                           psStatsOptions stdevStat, int width, psRandom *rng)
-{
-    PM_ASSERT_READOUT_NON_NULL(readout, false);
-    PM_ASSERT_READOUT_IMAGE(readout, false);
-    PM_ASSERT_READOUT_VARIANCE(readout, false);
-    PS_ASSERT_INT_POSITIVE(width, false);
-
-    if (!psMemIncrRefCounter(rng)) {
-        rng = psRandomAlloc(PS_RANDOM_TAUS);
-    }
-
-    psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout images
-    int numCols = image->numCols, numRows = image->numRows; // Size of images
-    int xNum = numCols / width + 1, yNum = numRows / width + 1; // Number of renormalisation regions
-    float xSize = numCols / (float)xNum, ySize = numRows / (float)yNum; // Size of renormalisation regions
-
-    psStats *meanStats = psStatsAlloc(meanStat), *stdevStats = psStatsAlloc(stdevStat); // Statistics
-    psVector *buffer = NULL;
-
-    for (int j = 0; j < yNum; j++) {
-        // Bounds in y
-        int yMin = j * ySize;
-        int yMax = (j + 1) * ySize;
-        for (int i = 0; i < xNum; i++) {
-            // Bounds in x
-            int xMin = i * xSize;
-            int xMax = (i + 1) * xSize;
-
-            psRegion region = psRegionSet(xMin, xMax, yMin, yMax); // Region of interest
-            psImage *subImage = psImageSubset(image, region); // Sub-image of the image pixels
-            psImage *subVariance = psImageSubset(variance, region); // Sub image of the variance pixels
-            psImage *subMask = mask ? psImageSubset(mask, region) : NULL; // Sub-image of the mask pixels
-
-            if (!psImageBackground(stdevStats, &buffer, subImage, subMask, maskVal, rng) ||
-                !psImageBackground(meanStats, &buffer, subVariance, subMask, maskVal, rng)) {
-                // Nothing we can do about it, but don't want to keel over and die, so do our best to flag it.
-                psString regionStr = psRegionToString(region); // String with region
-                psWarning("Unable to measure statistics over %s", regionStr);
-                psFree(regionStr);
-                psErrorClear();
-                psImageInit(subVariance, NAN);
-                if (subMask) {
-                    psImageInit(subMask, maskVal);
-                }
-            } else {
-                double meanVar = psStatsGetValue(meanStats, meanStat); // Mean of variance map
-                double stdev = psStatsGetValue(stdevStats, stdevStat); // Standard deviation of image
-                psTrace("psModules.camera", 3,
-                        "Region [%d:%d,%d:%d] has variance %lf, but mean of variance map is %lf\n",
-                        xMin, xMax, yMin, yMax, PS_SQR(stdev), meanVar);
-                psBinaryOp(subVariance, subVariance, "*", psScalarAlloc(PS_SQR(stdev) / meanVar, PS_TYPE_F32));
-            }
-
-            psFree(subImage);
-            psFree(subVariance);
-            psFree(subMask);
-        }
-    }
-    psFree(meanStats);
-    psFree(stdevStats);
-    psFree(rng);
-    psFree(buffer);
-
-    return true;
-}
 
 
Index: branches/eam_branches/20090820/psModules/src/camera/pmFPAMaskWeight.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/camera/pmFPAMaskWeight.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/camera/pmFPAMaskWeight.h	(revision 25766)
@@ -80,36 +80,10 @@
 ///
 /// The variance map is adjusted so that the mean matches the actual pixel variance in the image
-bool pmReadoutVarianceRenormPixels(
-    const pmReadout *readout,           ///< Readout to normalise
-    psImageMaskType maskVal,                 ///< Value to mask
-    psStatsOptions meanStat,            ///< Statistic to measure the mean (of the variance map)
-    psStatsOptions stdevStat,           ///< Statistic to measure the stdev (of the image)
-    psRandom *rng                       ///< Random number generator
-    );
-
-/// Renormalise the variance map to match the actual photometry variance
-///
-/// The variance map is adjusted so that the actual significance of fake sources matches the
-/// guestimated significance
-bool pmReadoutVarianceRenormPhot(
+bool pmReadoutVarianceRenormalise(
     const pmReadout *readout,           ///< Readout to normalise
     psImageMaskType maskVal,            ///< Value to mask
-    int num,                            ///< Number of instances to measure over the image
-    float width,                        ///< Photometry width
-    psStatsOptions meanStat,            ///< Statistic to measure the mean
-    psStatsOptions stdevStat,           ///< Statistic to measure the stdev
-    psRandom *rng                       ///< Random number generator
-    );
-
-/// Renormalise the variance map to match the actual variance
-///
-/// The variance in the image is measured in patches, and the variance map is adjusted so that the mean for
-/// that patch corresponds.
-bool pmReadoutVarianceRenorm(const pmReadout *readout, // Readout to normalise
-                             psImageMaskType maskVal, // Value to mask
-                             psStatsOptions meanStat, // Statistic to measure the mean (of the variance map)
-                             psStatsOptions stdevStat, // Statistic to measure the stdev (of the image)
-                             int width,   // Width of patch (pixels)
-                             psRandom *rng // Random number generator (for sub-sampling images)
+    int sample,                         ///< Sample size
+    float minValid,                     ///< Minimum valid renormalisation, or NAN
+    float maxValid                      ///< Maximum valid renormalisation, or NAN
     );
 
Index: branches/eam_branches/20090820/psModules/src/camera/pmFPAMosaic.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/camera/pmFPAMosaic.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/camera/pmFPAMosaic.c	(revision 25766)
@@ -740,5 +740,5 @@
 static bool chipMosaic(psImage **mosaicImage, // The mosaic image, to be returned
                        psImage **mosaicMask, // The mosaic mask, to be returned
-                       psImage **mosaicVariances, // The mosaic variances, to be returned
+                       psImage **mosaicVariance, // The mosaic variance, to be returned
                        int *xBinChip, int *yBinChip, // The binning in x and y, to be returned
                        const pmChip *chip, // Chip to mosaic
@@ -749,5 +749,5 @@
     assert(mosaicImage);
     assert(mosaicMask);
-    assert(mosaicVariances);
+    assert(mosaicVariance);
     assert(xBinChip);
     assert(yBinChip);
@@ -826,5 +826,5 @@
     if (allGood) {
         *mosaicImage = imageMosaic(images, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0, BLANK_VALUE);
-        *mosaicVariances = imageMosaic(variances, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0, BLANK_VALUE);
+        *mosaicVariance = imageMosaic(variances, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0, BLANK_VALUE);
         *mosaicMask = imageMosaic(masks, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0, blank);
     }
@@ -847,5 +847,5 @@
 static bool fpaMosaic(psImage **mosaicImage, // The mosaic image, to be returned
                       psImage **mosaicMask, // The mosaic mask, to be returned
-                      psImage **mosaicVariances, // The mosaic variances, to be returned
+                      psImage **mosaicVariance, // The mosaic variance, to be returned
                       int *xBinFPA, int *yBinFPA, // The binning in x and y, to be returned
                       const pmFPA *fpa,  // FPA to mosaic
@@ -857,5 +857,5 @@
     assert(mosaicImage);
     assert(mosaicMask);
-    assert(mosaicVariances);
+    assert(mosaicVariance);
     assert(xBinFPA);
     assert(yBinFPA);
@@ -960,5 +960,5 @@
     if (allGood) {
         *mosaicImage = imageMosaic(images, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0, BLANK_VALUE);
-        *mosaicVariances = imageMosaic(variances, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0, BLANK_VALUE);
+        *mosaicVariance = imageMosaic(variances, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0, BLANK_VALUE);
         *mosaicMask = imageMosaic(masks, xFlip, yFlip, xBin, yBin, *xBinFPA, *yBinFPA, x0, y0, blank);
     }
@@ -1025,5 +1025,5 @@
     psImage *mosaicImage   = NULL;      // The mosaic image
     psImage *mosaicMask    = NULL;      // The mosaic mask
-    psImage *mosaicVariances = NULL;      // The mosaic variances
+    psImage *mosaicVariance = NULL;      // The mosaic variances
 
     // Find the HDU
@@ -1052,6 +1052,6 @@
         }
         if (hdu->variances) {
-            mosaicVariances = psImageSubset(hdu->variances->data[0], bounds);
-            if (!mosaicVariances) {
+            mosaicVariance = psImageSubset(hdu->variances->data[0], bounds);
+            if (!mosaicVariance) {
                 psError(PS_ERR_UNKNOWN, false, "Unable to select variance pixels.\n");
                 return false;
@@ -1061,5 +1061,5 @@
         // Case 2 --- we need to mosaic by cut and paste
         psTrace("psModules.camera", 1, "Case 2 mosaicking: cut and paste.\n");
-        if (!chipMosaic(&mosaicImage, &mosaicMask, &mosaicVariances, &xBin, &yBin, source, targetCell, blank)) {
+        if (!chipMosaic(&mosaicImage, &mosaicMask, &mosaicVariance, &xBin, &yBin, source, targetCell, blank)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to mosaic cells.\n");
             return false;
@@ -1069,4 +1069,5 @@
     }
     psTrace("psModules.camera", 1, "xBin,yBin: %d,%d\n", xBin, yBin);
+
 
     // Set the concepts for the target cell
@@ -1090,9 +1091,31 @@
     target->parent->concepts = psMetadataCopy(target->parent->concepts, source->parent->concepts); // FPA lvl
 
+    // Average the covariances
+    psList *covariances = psListAlloc(NULL); // Input covariance matrices
+    for (int i = 0; i < source->cells->n; i++) {
+        pmCell *cell = source->cells->data[i]; // Cell of interest
+        if (!cell || !cell->data_exists) {
+            continue;
+        }
+        pmReadout *ro = cell->readouts->data[0]; // Readout of interest
+        if (!ro || !ro->covariance) {
+            continue;
+        }
+        psListAdd(covariances, PS_LIST_TAIL, ro->covariance);
+    }
+    psKernel *mosaicCovariance = NULL;  // Covariance for mosaic
+    if (psListLength(covariances) > 0) {
+        psArray *covarArray = psListToArray(covariances); // Array with covariances
+        mosaicCovariance = psImageCovarianceAverage(covarArray);
+        psFree(covarArray);
+    }
+    psFree(covariances);
+
     // Now make a new readout to go in the target cell
     pmReadout *newReadout = pmReadoutAlloc(targetCell); // New readout
     newReadout->image  = mosaicImage;
     newReadout->mask   = mosaicMask;
-    newReadout->variance = mosaicVariances;
+    newReadout->variance = mosaicVariance;
+    newReadout->covariance = mosaicCovariance;
     psFree(newReadout);                 // Drop reference
 
@@ -1334,4 +1357,32 @@
     target->concepts = psMetadataCopy(target->concepts, source->concepts);
 
+    // Average the covariances
+    psList *covariances = psListAlloc(NULL); // Input covariance matrices
+    for (int i = 0; i < covariances->n; i++) {
+        pmChip *chip = chips->data[i];  // Chip of interest
+        if (!chip || !chip->data_exists) {
+            continue;
+        }
+        psArray *cells = chip->cells;   // Cells in chip
+        for (long j = 0; j < cells->n; j++) {
+            pmCell *cell = cells->data[i]; // Cell of interest
+            if (!cell || !cell->data_exists) {
+                continue;
+            }
+            pmReadout *ro = cell->readouts->data[0]; // Readout of interest
+            if (!ro || !ro->covariance) {
+                continue;
+            }
+            psListAdd(covariances, PS_LIST_TAIL, ro->covariance);
+        }
+    }
+    psKernel *mosaicCovariances = NULL; // Covariance for mosaic
+    if (psListLength(covariances) > 0) {
+        psArray *covarArray = psListToArray(covariances); // Array with covariances
+        mosaicCovariances = psImageCovarianceAverage(covarArray);
+        psFree(covarArray);
+    }
+    psFree(covariances);
+
     // Now make a new readout to go in the new cell
     pmReadout *newReadout = pmReadoutAlloc(targetCell); // New readout
@@ -1339,4 +1390,5 @@
     newReadout->mask   = mosaicMask;
     newReadout->variance = mosaicVariances;
+    newReadout->covariance = mosaicCovariances;
     psFree(newReadout);                 // Drop reference
 
Index: branches/eam_branches/20090820/psModules/src/camera/pmFPARead.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/camera/pmFPARead.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/camera/pmFPARead.c	(revision 25766)
@@ -387,4 +387,5 @@
                 psFree(regionString);
                 psFree(readout);
+		psFree(iter);
                 return false;
             }
Index: branches/eam_branches/20090820/psModules/src/camera/pmHDUGenerate.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/camera/pmHDUGenerate.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/camera/pmHDUGenerate.c	(revision 25766)
@@ -611,4 +611,5 @@
             if (cells->n == 0) {
                 // Nothing to do
+		psFree (cells);
                 return true;
             }
@@ -660,4 +661,5 @@
             if (cells->n == 0) {
                 // Nothing to do
+		psFree (cells);
                 return true;
             }
@@ -710,5 +712,4 @@
                 return true;
             }
-
             bool status = generateHDU(hdu, cells);
 	    psFree(cells);
Index: branches/eam_branches/20090820/psModules/src/camera/pmReadoutFake.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/camera/pmReadoutFake.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/camera/pmReadoutFake.c	(revision 25766)
@@ -28,5 +28,4 @@
 #define MODEL_TYPE "PS_MODEL_RGAUSS"    // Type of model to use
 #define MAX_AXIS_RATIO 20.0             // Maximum axis ratio for PSF model
-#define SOURCE_MASK (PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_CR_LIMIT) // Mask to apply to input sources
 #define MODEL_MASK (PM_MODEL_STATUS_NONCONVERGE | PM_MODEL_STATUS_OFFIMAGE | \
                     PM_MODEL_STATUS_BADARGS | PM_MODEL_STATUS_LIMITS) // Mask to apply to models
@@ -50,13 +49,23 @@
 }
 
-bool pmReadoutFakeFromSources(pmReadout *readout, int numCols, int numRows, const psArray *sources,
-                              const psVector *xOffset, const psVector *yOffset, const pmPSF *psf,
-                              float minFlux, int radius, bool circularise, bool normalisePeak)
+
+bool pmReadoutFakeFromVectors(pmReadout *readout, int numCols, int numRows,
+                              const psVector *x, const psVector *y, const psVector *mag,
+                              const psVector *xOffset, const psVector *yOffset,
+                              const pmPSF *psf, float minFlux, int radius,
+                              bool circularise, bool normalisePeak)
 {
     PS_ASSERT_PTR_NON_NULL(readout, false);
     PS_ASSERT_INT_LARGER_THAN(numCols, 0, false);
     PS_ASSERT_INT_LARGER_THAN(numRows, 0, false);
-    PS_ASSERT_ARRAY_NON_NULL(sources, false);
-
+    PS_ASSERT_VECTOR_NON_NULL(x, false);
+    PS_ASSERT_VECTOR_TYPE(x, PS_TYPE_F32, false);
+    PS_ASSERT_VECTOR_NON_NULL(y, false);
+    PS_ASSERT_VECTOR_TYPE(y, PS_TYPE_F32, false);
+    PS_ASSERT_VECTORS_SIZE_EQUAL(y, x, false);
+    PS_ASSERT_VECTOR_NON_NULL(mag, false);
+    PS_ASSERT_VECTOR_TYPE(mag, PS_TYPE_F32, false);
+    PS_ASSERT_VECTORS_SIZE_EQUAL(mag, x, false);
+    long numSources = x->n;              // Number of sources
     if (xOffset || yOffset) {
         PS_ASSERT_VECTOR_NON_NULL(xOffset, false);
@@ -64,51 +73,41 @@
         PS_ASSERT_VECTORS_SIZE_EQUAL(xOffset, yOffset, false);
         PS_ASSERT_VECTOR_TYPE(xOffset, PS_TYPE_S32, false);
-        PS_ASSERT_VECTOR_TYPE_EQUAL(xOffset, yOffset, false);
-        if (xOffset->n != sources->n) {
+        PS_ASSERT_VECTOR_TYPE(yOffset, PS_TYPE_S32, false);
+        if (xOffset->n != numSources) {
             psError(PS_ERR_BAD_PARAMETER_SIZE, true,
                     "Number of offset vectors (%ld) and sources (%ld) doesn't match",
-                    xOffset->n, sources->n);
+                    xOffset->n, numSources);
             return false;
         }
     }
     PS_ASSERT_PTR_NON_NULL(psf, false);
-    if (radius > 0 && isfinite(minFlux) && minFlux > 0.0) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Cannot define both minimum flux and fixed radius.");
-        return false;
-    }
 
     readout->image = psImageRecycle(readout->image, numCols, numRows, PS_TYPE_F32);
     psImageInit(readout->image, 0);
 
-    int numSources = sources->n;          // Number of stars
-    for (int i = 0; i < numSources; i++) {
-        pmSource *source = sources->data[i]; // Source of interest
-        if (!source) {
-            continue;
-        }
-        if (source->mode & SOURCE_MASK) {
-            continue;
-        }
-        if (!isfinite(source->psfMag)) {
-            continue;
-        }
-        float x, y;                     // Coordinates of source
-        if (source->modelPSF) {
-            x = source->modelPSF->params->data.F32[PM_PAR_XPOS];
-            y = source->modelPSF->params->data.F32[PM_PAR_YPOS];
-        } else {
-            x = source->peak->xf;
-            y = source->peak->yf;
-        }
-
-        float flux = powf(10.0, -0.4 * source->psfMag); // Flux of source
+    for (long i = 0; i < numSources; i++) {
+        float flux = powf(10.0, -0.4 * mag->data.F32[i]); // Flux of source
+        float xSrc = x->data.F32[i], ySrc = y->data.F32[i]; // Coordinates of source
 
         if (normalisePeak) {
             // Normalise flux
-            pmModel *normModel = pmModelFromPSFforXY(psf, x, y, 1.0); // Model for normalisation
+            pmModel *normModel = pmModelFromPSFforXY(psf, xSrc, ySrc, 1.0); // Model for normalisation
             if (!normModel || (normModel->flags & MODEL_MASK)) {
                 psFree(normModel);
                 continue;
             }
+	    // check that all params are valid:
+	    bool validParams = true;
+	    for (int n = 0; validParams && (n < normModel->params->n); n++) {
+		if (n == PM_PAR_SKY) continue;
+		if (n == PM_PAR_I0) continue;
+		if (n == PM_PAR_XPOS) continue;
+		if (n == PM_PAR_YPOS) continue;
+		if (!isfinite(normModel->params->data.F32[n])) validParams = false;
+	    }
+	    if (!validParams) {
+                psFree(normModel);
+		continue;
+	    }		
             if (circularise && !circulariseModel(normModel)) {
                 psError(PS_ERR_UNKNOWN, false, "Unable to circularise PSF model.");
@@ -121,9 +120,22 @@
         }
 
-        pmModel *fakeModel = pmModelFromPSFforXY(psf, x, y, flux);
+        pmModel *fakeModel = pmModelFromPSFforXY(psf, xSrc, ySrc, flux);
         if (!fakeModel || (fakeModel->flags & MODEL_MASK)) {
             psFree(fakeModel);
             continue;
         }
+	// check that all params are valid:
+	bool validParams = true;
+	for (int n = 0; validParams && (n < fakeModel->params->n); n++) {
+	    if (n == PM_PAR_SKY) continue;
+	    if (n == PM_PAR_I0) continue;
+	    if (n == PM_PAR_XPOS) continue;
+	    if (n == PM_PAR_YPOS) continue;
+	    if (!isfinite(fakeModel->params->data.F32[n])) validParams = false;
+	}
+	if (!validParams) {
+	    psFree(fakeModel);
+	    continue;
+	}		
         if (circularise && !circulariseModel(fakeModel)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to circularise PSF model.");
@@ -137,11 +149,16 @@
 
         pmSource *fakeSource = pmSourceAlloc(); // Fake source to generate
-        fakeSource->peak = pmPeakAlloc(x, y, fakeModel->params->data.F32[PM_PAR_I0], PM_PEAK_LONE);
-        float fakeRadius = radius > 0 ? radius :
-            PS_MAX(1.0, fakeModel->modelRadius(fakeModel->params, minFlux)); // Radius of fake source
+        fakeSource->peak = pmPeakAlloc(xSrc, ySrc, fakeModel->params->data.F32[PM_PAR_I0], PM_PEAK_LONE);
+        float fakeRadius = 1.0;         // Radius of fake source
+        if (isfinite(minFlux)) {
+            fakeRadius = PS_MAX(fakeRadius, fakeModel->modelRadius(fakeModel->params, minFlux));
+        }
+        if (radius > 0) {
+            fakeRadius = PS_MAX(fakeRadius, radius);
+        }
 
         if (xOffset) {
-            if (!pmSourceDefinePixels(fakeSource, readout, x + xOffset->data.S32[i],
-                                      y + yOffset->data.S32[i], fakeRadius)) {
+            if (!pmSourceDefinePixels(fakeSource, readout, xSrc + xOffset->data.S32[i],
+                                      ySrc + yOffset->data.S32[i], fakeRadius)) {
                 psErrorClear();
                 continue;
@@ -153,5 +170,5 @@
             }
         } else {
-            if (!pmSourceDefinePixels(fakeSource, readout, x, y, fakeRadius)) {
+            if (!pmSourceDefinePixels(fakeSource, readout, xSrc, ySrc, fakeRadius)) {
                 psErrorClear();
                 continue;
@@ -168,2 +185,54 @@
     return true;
 }
+
+
+bool pmReadoutFakeFromSources(pmReadout *readout, int numCols, int numRows, const psArray *sources,
+                              pmSourceMode sourceMask, const psVector *xOffset, const psVector *yOffset,
+                              const pmPSF *psf, float minFlux, int radius,
+                              bool circularise, bool normalisePeak)
+{
+    PS_ASSERT_ARRAY_NON_NULL(sources, false);
+
+    int numSources = sources->n;          // Number of stars
+    psVector *x = psVectorAllocEmpty(numSources, PS_TYPE_F32);
+    psVector *y = psVectorAllocEmpty(numSources, PS_TYPE_F32);
+    psVector *mag = psVectorAllocEmpty(numSources, PS_TYPE_F32);
+
+    int numGood = 0;                    // Number of good sources
+    for (int i = 0; i < numSources; i++) {
+        pmSource *source = sources->data[i]; // Source of interest
+        if (!source) {
+            continue;
+        }
+        if (source->mode & sourceMask) {
+            continue;
+        }
+        if (!isfinite(source->psfMag)) {
+            continue;
+        }
+        float xSrc, ySrc;                     // Coordinates of source
+        if (source->modelPSF) {
+            xSrc = source->modelPSF->params->data.F32[PM_PAR_XPOS];
+            ySrc = source->modelPSF->params->data.F32[PM_PAR_YPOS];
+        } else {
+            xSrc = source->peak->xf;
+            ySrc = source->peak->yf;
+        }
+
+        x->data.F32[numGood] = xSrc;
+        y->data.F32[numGood] = ySrc;
+        mag->data.F32[numGood] = source->psfMag;
+        numGood++;
+    }
+    x->n = numGood;
+    y->n = numGood;
+    mag->n = numGood;
+
+    bool status = pmReadoutFakeFromVectors(readout, numCols, numRows, x, y, mag, xOffset, yOffset, psf,
+                                           minFlux, radius, circularise, normalisePeak);
+    psFree(x);
+    psFree(y);
+    psFree(mag);
+
+    return status;
+}
Index: branches/eam_branches/20090820/psModules/src/camera/pmReadoutFake.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/camera/pmReadoutFake.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/camera/pmReadoutFake.h	(revision 25766)
@@ -11,9 +11,25 @@
 #include <pmTrend2D.h>
 #include <pmPSF.h>
+#include <pmSourceMasks.h>
+
+/// Generate a fake readout from vectors
+bool pmReadoutFakeFromVectors(pmReadout *readout, ///< Output readout
+                              int numCols, int numRows, ///< Dimension of image
+                              const psVector *x, const psVector *y, ///< Source coordinates
+                              const psVector *mag, ///< Source magnitudes
+                              const psVector *xOffset, ///< x offsets for sources (source -> img), or NULL
+                              const psVector *yOffset, ///< y offsets for sources (source -> img), or NULL
+                              const pmPSF *psf, ///< PSF for sources
+                              float minFlux, ///< Minimum flux to bother about; for setting source radius
+                              int radius, ///< Fixed radius for sources
+                              bool circularise, ///< Circularise PSF model?
+                              bool normalisePeak ///< Normalise the peak value?
+    );
 
 /// Generate a fake readout from an array of sources
-bool pmReadoutFakeFromSources(pmReadout *readout, ///< Output readout, or NULL
+bool pmReadoutFakeFromSources(pmReadout *readout, ///< Output readout
                               int numCols, int numRows, ///< Dimension of image
                               const psArray *sources, ///< Array of pmSource
+                              pmSourceMode sourceMask, ///< Mask for sources
                               const psVector *xOffset, ///< x offsets for sources (source -> img), or NULL
                               const psVector *yOffset, ///< y offsets for sources (source -> img), or NULL
Index: branches/eam_branches/20090820/psModules/src/concepts/pmConcepts.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/concepts/pmConcepts.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/concepts/pmConcepts.c	(revision 25766)
@@ -333,4 +333,5 @@
         conceptRegisterF32("FPA.TELTEMP.EXTRA", "Telescope Temperatures: extra", p_pmConceptParse_TELTEMPS, NULL, NULL, false, PM_FPA_LEVEL_FPA);
         conceptRegisterF32("FPA.PON.TIME", "Power On Time", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
+	conceptRegisterS32("FPA.BURNTOOL.APPLIED", "Status of burntool processing", p_pmConceptParse_BTOOLAPP,NULL,NULL,false,PM_FPA_LEVEL_FPA);
         conceptRegisterF32("FPA.EXPOSURE", "Exposure time (sec)", NULL, NULL, NULL, false, PM_FPA_LEVEL_FPA);
     }
@@ -348,4 +349,5 @@
         conceptRegisterF32("CHIP.TEMP", "Temperature of chip", NULL, NULL, NULL, false, PM_FPA_LEVEL_CHIP);
         conceptRegisterStr("CHIP.ID", "Chip identifier", NULL, NULL, NULL, false, PM_FPA_LEVEL_CHIP);
+
     }
 
Index: branches/eam_branches/20090820/psModules/src/concepts/pmConceptsRead.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/concepts/pmConceptsRead.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/concepts/pmConceptsRead.c	(revision 25766)
@@ -73,5 +73,4 @@
         return false;
     }
-
     psTrace ("psModules.concepts", 3, "parsing concept: %s\n", spec->blank->name);
     if (!strcmp (spec->blank->name, "CELL.XPARITY")) {
@@ -275,4 +274,5 @@
         psMetadataItem *headerItem = NULL; // The value of the concept from the header
 
+
         psTrace ("psModules.concepts", 3, "reading concept: %s\n", name);
         if (!strcmp (name, "CELL.XPARITY")) {
@@ -307,5 +307,4 @@
             }
         }
-
         if (!headerItem) {
             psMetadataItem *formatItem = psMetadataLookup(transSpec, name); // Item with keyword
@@ -328,5 +327,4 @@
             }
             psString keywords = formatItem->data.str; // The FITS keywords
-
             // In case there are multiple headers
             psList *keys = psStringSplit(keywords, " ,;", true); // List of keywords
Index: branches/eam_branches/20090820/psModules/src/concepts/pmConceptsStandard.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/concepts/pmConceptsStandard.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/concepts/pmConceptsStandard.c	(revision 25766)
@@ -161,5 +161,4 @@
     assert(concept);
     assert(pattern);
-
     double value = NAN;
     switch (concept->type) {
@@ -736,4 +735,34 @@
     return psMetadataItemAllocS32(pattern->name, pattern->comment, binning);
 }
+
+// BTOOLAPP
+psMetadataItem *p_pmConceptParse_BTOOLAPP(const psMetadataItem *concept,
+					  const psMetadataItem *pattern,
+					  pmConceptSource source,
+					  const psMetadata *cameraFormat,
+					  const pmFPA *fpa,
+					  const pmChip *chip,
+					  const pmCell *cell)
+{
+  assert(concept);
+  assert(pattern);
+
+  int bt_status = 0;
+
+  if (concept->type != PS_DATA_BOOL) {
+    psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Type for %s (%x) is not BOOL\n",
+	    concept->name, concept->type);
+    return NULL;
+  }
+
+  if (concept->data.B == true) {
+    bt_status = -2;
+  }
+  else if (concept->data.B == false) {
+    bt_status = 1 ;
+  }
+  
+  return psMetadataItemAllocS32(concept->name, concept->comment, bt_status);
+}  
 
 // Get the current value of a concept
Index: branches/eam_branches/20090820/psModules/src/concepts/pmConceptsStandard.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/concepts/pmConceptsStandard.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/concepts/pmConceptsStandard.h	(revision 25766)
@@ -136,4 +136,16 @@
     );
 
+/// Format for the BTOOLAPP conceptn
+psMetadataItem *p_pmConceptParse_BTOOLAPP(
+    const psMetadataItem *concept, ///< Concept to format
+    const psMetadataItem *pattern,
+    pmConceptSource source, ///< Source for concept
+    const psMetadata *cameraFormat, ///< Camera format definition
+    const pmFPA *fpa, ///< FPA for concept, or NULL
+    const pmChip *chip, ///< Chip for concept, or NULL
+    const pmCell *cell ///< Cell for concept, or NULL
+    );
+
+
 /// Parse the cell binning concepts: CELL.XBIN, CELL.YBIN
 psMetadataItem *p_pmConceptParse_CELL_Binning(
Index: branches/eam_branches/20090820/psModules/src/config/pmConfigMask.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/config/pmConfigMask.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/config/pmConfigMask.c	(revision 25766)
@@ -22,8 +22,8 @@
     // Non-astronomical structures
     { "CR",        NULL,       0x08, true  }, // Pixel contains a cosmic ray
-    { "SPIKE",     NULL,       0x08, true  }, // Pixel contains a diffraction spike
-    { "GHOST",     NULL,       0x08, true  }, // Pixel contains an optical ghost
-    { "STREAK",    NULL,       0x08, true  }, // Pixel contains streak data
-    { "STARCORE",  NULL,       0x08, true  }, // Pixel contains a bright star core
+    { "SPIKE",     NULL,       0x08, false  }, // Pixel contains a diffraction spike
+    { "GHOST",     NULL,       0x08, false  }, // Pixel contains an optical ghost
+    { "STREAK",    NULL,       0x08, false  }, // Pixel contains streak data
+    { "STARCORE",  NULL,       0x08, false  }, // Pixel contains a bright star core
     // Effects of convolution and interpolation
     { "CONV.BAD",  NULL,       0x02, true  }, // Pixel is bad after convolution with a bad pixel
Index: branches/eam_branches/20090820/psModules/src/extras/pmVisual.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/extras/pmVisual.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/extras/pmVisual.c	(revision 25766)
@@ -22,4 +22,7 @@
 #include "pmSubtractionStamps.h"
 #include "pmTrend2D.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmSource.h"
 #include "pmFPAExtent.h"
 
@@ -86,9 +89,13 @@
 {
     char key[10];
-    fprintf (stdout, "[c]ontinue? [s]kip the rest of these plots? [a]bort all visual plots?");
+    if (plotFlag) {
+	fprintf (stdout, "[c]ontinue? [s]kip the rest of these plots? [a]bort all visual plots? (c) ");
+    } else {
+	fprintf (stdout, "[c]ontinue? [a]bort all visual plots? (c) ");
+    }
     if (!fgets(key, 8, stdin)) {
         psWarning("Unable to read option");
     }
-    if (key[0] == 's') {
+    if (plotFlag && (key[0] == 's')) {
         *plotFlag = false;
     }
Index: branches/eam_branches/20090820/psModules/src/imcombine/pmPSFEnvelope.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/imcombine/pmPSFEnvelope.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/imcombine/pmPSFEnvelope.c	(revision 25766)
@@ -34,4 +34,5 @@
 
 // #define TESTING                         // Enable test output
+// #define PEAK_NORM                       // Normalise peaks?
 #define PEAK_FLUX 1.0e4                 // Peak flux for each source
 #define SKY_VALUE 0.0e0                 // Sky value for fake image
@@ -122,8 +123,53 @@
             continue;
         }
+
+        if (psTraceGetLevel("psModules.imcombine") >= 1) {
+            psString string = NULL;     // String with values
+            psStringAppend(&string, "PSF %d: ", i);
+            float x = numCols / 2.0, y = numRows / 2.0; // Coordinates of interest
+            for (int j = 4; j < psf->params->n; j++) {
+                pmTrend2D *trend = psf->params->data[j]; // Trend of interest
+                double val = pmTrend2DEval(trend, x, y);
+                double err;
+                switch (trend->mode) {
+                  case PM_TREND_POLY_ORD:
+                  case PM_TREND_POLY_CHEB:
+                    err = NAN;
+                    break;
+                  case PM_TREND_MAP:
+                    err = psImageUnbinPixel(x, y, trend->map->error, trend->map->binning);
+                    break;
+                  default:
+                    psAbort("Unsupported mode: %x", trend->mode);
+                }
+                psStringAppend(&string, "%lf %lf   ", val, err);
+            }
+            psTrace("psModules.imcombine", 1, "%s\n", string);
+            psFree(string);
+        }
+
+        // Test PSF
+        {
+            bool goodPSF = true;                                                                // Good PSF?
+            pmModelClassSetLimits(PM_MODEL_LIMITS_IGNORE);
+            pmModel *model = pmModelFromPSFforXY(psf, numCols / 2.0, numRows / 2.0, PEAK_FLUX); // Test model
+            model->modelSetLimits(PM_MODEL_LIMITS_STRICT);
+            for (int j = 0; j < model->params->n && goodPSF; j++) {
+                if (!model->modelLimits(PS_MINIMIZE_PARAM_MIN, j, model->params->data.F32, NULL) ||
+                    !model->modelLimits(PS_MINIMIZE_PARAM_MAX, j, model->params->data.F32, NULL)) {
+                    goodPSF = false;
+                }
+            }
+            psFree(model);
+            if (!goodPSF) {
+                psWarning("PSF %d is bad --- not including in envelope calculation.", i);
+                continue;
+            }
+        }
+
         pmResiduals *resid = psf->residuals;// PSF residuals
         psf->residuals = NULL;
-        if (!pmReadoutFakeFromSources(fakeRO, fakeSize, fakeSize, fakes, xOffset, yOffset, psf,
-                                      NAN, radius, true, true)) {
+        if (!pmReadoutFakeFromSources(fakeRO, fakeSize, fakeSize, fakes, 0, xOffset, yOffset, psf,
+                                      NAN, radius, true, false)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to generate fake readout.");
             psFree(envelope);
@@ -144,13 +190,28 @@
             float y = source->peak->yf + yOffset->data.S32[j]; // y coordinate of source
 
-            double flux = fakeRO->image->data.F32[(int)y][(int)x];
+#ifdef PEAK_NORM
+            // Perhaps I'm being paranoid, but specify a range to check
+            int uMax = PS_MIN(x + radius, numCols - 1), uMin = PS_MAX(x - radius, 0);
+            int vMax = PS_MIN(y + radius, numRows - 1), vMin = PS_MAX(y - radius, 0);
+
+            double flux = -INFINITY;    // Peak flux
+            for (int v = vMin; v <= vMax; v++) {
+                for (int u = uMin; u <= uMax; u++) {
+                    if (fakeRO->image->data.F32[v][u] > flux) {
+                        flux = fakeRO->image->data.F32[v][u];
+                    }
+                }
+            }
             if (!isfinite(flux) || flux < 0) {
                 continue;
             }
             float norm = PEAK_FLUX / flux; // Normalisation for source
+#endif
             psRegion region = psRegionSet(x - radius, x + radius, y - radius, y + radius); // PSF region
             psImage *subImage = psImageSubset(fakeRO->image, region); // Subimage of fake PSF
             psImage *subEnv = psImageSubset(envelope, region); // Subimage of envelope
+#ifdef PEAK_NORM
             psBinaryOp(subImage, subImage, "*", psScalarAlloc(norm, PS_TYPE_F32));
+#endif
             psBinaryOp(subEnv, subEnv, "MAX", subImage);
             psFree(subImage);
@@ -298,5 +359,5 @@
         }
 
-	// measure the source moments: tophat windowing, no pixel S/N cutoff
+        // measure the source moments: tophat windowing, no pixel S/N cutoff
         if (!pmSourceMoments(source, maxRadius, 0.0, 1.0)) {
             // Can't do anything about it; limp along as best we can
@@ -320,5 +381,6 @@
     options->poissonErrorsParams = true;
     options->stats = psStatsAlloc(PSF_STATS);
-    options->radius = maxRadius;
+    options->fitRadius = maxRadius;
+    options->apRadius = maxRadius; // XXX need to decide if aperture mags need a different radius
     options->psfTrendMode = PM_TREND_MAP;
     options->psfTrendNx = xOrder;
@@ -343,4 +405,29 @@
     pmPSF *psf = psMemIncrRefCounter(try->psf); // Output PSF
     psFree(try);
+
+    if (psTraceGetLevel("psModules.imcombine") >= 1) {
+        psString string = NULL;     // String with values
+        psStringAppend(&string, "Envelope PSF: ");
+        float x = numCols / 2.0, y = numRows / 2.0; // Coordinates of interest
+        for (int j = 4; j < psf->params->n; j++) {
+            pmTrend2D *trend = psf->params->data[j]; // Trend of interest
+            double val = pmTrend2DEval(trend, x, y);
+            double err;
+            switch (trend->mode) {
+              case PM_TREND_POLY_ORD:
+              case PM_TREND_POLY_CHEB:
+                err = NAN;
+                break;
+              case PM_TREND_MAP:
+                err = psImageUnbinPixel(x, y, trend->map->error, trend->map->binning);
+                break;
+              default:
+                psAbort("Unsupported mode: %x", trend->mode);
+            }
+            psStringAppend(&string, "%lf %lf   ", val, err);
+        }
+        psTrace("psModules.imcombine", 1, "%s\n", string);
+        psFree(string);
+    }
 
 #ifdef TESTING
@@ -357,5 +444,5 @@
 
         pmReadout *generated = pmReadoutAlloc(NULL); // Generated image
-        pmReadoutFakeFromSources(generated, numCols, numRows, fakes, NULL, NULL, psf, NAN, radius,
+        pmReadoutFakeFromSources(generated, numCols, numRows, fakes, 0, NULL, NULL, psf, NAN, radius,
                                  false, true);
         {
Index: branches/eam_branches/20090820/psModules/src/imcombine/pmStack.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/imcombine/pmStack.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/imcombine/pmStack.c	(revision 25766)
@@ -30,5 +30,5 @@
 #define PIXEL_LIST_BUFFER 100           // Number of entries to add to pixel list at a time
 #define PIXEL_MAP_BUFFER 2              // Number of entries to add to pixel map at a time
-#define ADD_VARIANCE                    // Allow additional variance (besides variance factor)?
+//#define ADD_VARIANCE                    // Allow additional variance (besides variance factor)?
 #define NUM_DIRECT_STDEV 5              // For less than this number of values, measure stdev directly
 
Index: branches/eam_branches/20090820/psModules/src/imcombine/pmStackReject.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/imcombine/pmStackReject.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/imcombine/pmStackReject.c	(revision 25766)
@@ -43,21 +43,9 @@
     if (box > 0) {
         // Convolve a subimage, then stick it in the target
-        // XXX if (threaded) {
-        // XXX     psMutexLock(source);
-        // XXX }
         psImage *mask = psImageSubset(source, psRegionSet(xMin - box, xMax + box,
                                                           yMin - box, yMax + box)); // Mask to convolve
-        // XXX if (threaded) {
-        // XXX     psMutexUnlock(source);
-        // XXX }
         psImage *convolved = psImageConvolveMask(NULL, mask, PM_STACK_MASK_BAD, PM_STACK_MASK_CONVOLVE,
                                                  -box, box, -box, box); // Convolved mask
-        // XXX if (threaded) {
-        // XXX     psMutexLock(source);
-        // XXX }
         psFree(mask);
-        // XXX if (threaded) {
-        // XXX     psMutexUnlock(source);
-        // XXX }
 
         int numBytes = (xMax - xMin) * PSELEMTYPE_SIZEOF(PS_TYPE_IMAGE_MASK); // Number of bytes to copy
@@ -162,11 +150,8 @@
     pmReadout *inRO = pmReadoutAlloc(NULL); // Readout with input image
     inRO->image = image;
-    // XXX if (threaded) {
-    // XXX     psMutexInit(image);
-    // XXX }
     for (int i = 0; i < numRegions; i++) {
         psRegion *region = subRegions->data[i]; // Region of interest
         pmSubtractionKernels *kernels = subKernels->data[i]; // Kernel of interest
-        if (!pmSubtractionConvolve(convRO, NULL, inRO, NULL, NULL, stride, 0, 0, 1.0, 0.0,
+        if (!pmSubtractionConvolve(NULL, convRO, NULL, inRO, NULL, stride, 0, 0, 1.0, 0.0,
                                    region, kernels, false, true)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask image in region %d.", i);
@@ -211,7 +196,4 @@
         }
     }
-    // XXX if (threaded) {
-    // XXX     psMutexDestroy(image);
-    // XXX }
     psFree(inRO);
     psImage *convolved = psMemIncrRefCounter(convRO->image);
@@ -264,7 +246,4 @@
     psImage *target = psImageRecycle(convolved, numCols, numRows, PS_TYPE_IMAGE_MASK); // Grown image
     psImageInit(target, 0);
-    // XXX if (threaded) {
-    // XXX     psMutexInit(source);
-    // XXX }
     for (int i = 0; i < subRegions->n; i++) {
         psRegion *region = subRegions->data[i]; // Subtraction region
@@ -287,7 +266,5 @@
                     psArray *args = job->args; // Job arguments
                     psArrayAdd(args, 1, target);
-                    // XXX psMutexLock(source);
                     psArrayAdd(args, 1, source);
-                    // XXX psMutexUnlock(source);
                     psArrayAdd(args, 1, kernels);
                     PS_ARRAY_ADD_SCALAR(args, numCols, PS_TYPE_S32);
@@ -332,5 +309,4 @@
         }
 
-        // XXX psMutexDestroy(source);
     }
 
Index: branches/eam_branches/20090820/psModules/src/imcombine/pmSubtraction.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/imcombine/pmSubtraction.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/imcombine/pmSubtraction.c	(revision 25766)
@@ -957,10 +957,10 @@
     PS_ASSERT_FLOAT_WITHIN_RANGE(y, -1.0, 1.0, NULL);
 
-    psArray *images = psArrayAlloc(solution->n - 1); // Images of each kernel to return
-    psVector *fakeSolution = psVectorAlloc(solution->n, PS_TYPE_F64); // Fake solution vector
+    psArray *images = psArrayAlloc(kernels->solution1->n - 1); // Images of each kernel to return
+    psVector *fakeSolution = psVectorAlloc(kernels->solution1->n, PS_TYPE_F64); // Fake solution vector
     psVectorInit(fakeSolution, 0.0);
 
-    for (int i = 0; i < solution->n - 1; i++) {
-        fakeSolution->data.F64[i] = solution->data.F64[i];
+    for (int i = 0; i < kernels->solution1->n - 1; i++) {
+        fakeSolution->data.F64[i] = kernels->solution1->data.F64[i];
         images->data[i] = pmSubtractionKernelImage(kernels, x, y, wantDual);
         fakeSolution->data.F64[i] = 0.0;
Index: branches/eam_branches/20090820/psModules/src/imcombine/pmSubtraction.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/imcombine/pmSubtraction.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/imcombine/pmSubtraction.h	(revision 25766)
@@ -93,8 +93,9 @@
 
 /// Generate images of the convolution kernel elements
-psArray *pmSubtractionKernelSolutions(const psVector *solution, ///< Solution vector
-                                      const pmSubtractionKernels *kernels, ///< Kernel parameters
-                                      float x, float y ///< Normalised position [-1,1] for images
+psArray *pmSubtractionKernelSolutions(const pmSubtractionKernels *kernels, ///< Kernel parameters
+                                      float x, float y, ///< Normalised position [-1,1] for images
+                                      bool wantDual ///< Calculate for the dual kernel?
     );
+
 
 /// Execute a thread job to convolve a patch of the image
Index: branches/eam_branches/20090820/psModules/src/imcombine/pmSubtractionAnalysis.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/imcombine/pmSubtractionAnalysis.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/imcombine/pmSubtractionAnalysis.c	(revision 25766)
@@ -121,11 +121,11 @@
     {
         psMetadata *header = psMetadataAlloc(); // Header
-        for (int i = 0; i < solution->n; i++) {
+        for (int i = 0; i < kernels->solution1->n; i++) {
             psString name = NULL;       // Header keyword
             psStringAppend(&name, "SOLN%04d", i);
-            psMetadataAddF64(header, PS_LIST_TAIL, name, 0, NULL, solution->data.F64[i]);
+            psMetadataAddF64(header, PS_LIST_TAIL, name, 0, NULL, kernels->solution1->data.F64[i]);
             psFree(name);
         }
-        psArray *kernelImages = pmSubtractionKernelSolutions(solution, kernels, 0.0, 0.0);
+        psArray *kernelImages = pmSubtractionKernelSolutions(kernels, 0.0, 0.0, false);
         psFits *kernelFile = psFitsOpen("kernels.fits", "w");
         (void)psFitsWriteImageCube(kernelFile, header, kernelImages, NULL);
Index: branches/eam_branches/20090820/psModules/src/imcombine/pmSubtractionMatch.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/imcombine/pmSubtractionMatch.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/imcombine/pmSubtractionMatch.c	(revision 25766)
@@ -628,5 +628,9 @@
     variance = NULL;
 
-    if (!pmSubtractionBorder(conv1->image, conv1->variance, conv1->mask, size, maskBad)) {
+    if (conv1 && !pmSubtractionBorder(conv1->image, conv1->variance, conv1->mask, size, maskBad)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to set border of convolved image.");
+        goto MATCH_ERROR;
+    }
+    if (conv2 && !pmSubtractionBorder(conv2->image, conv2->variance, conv2->mask, size, maskBad)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to set border of convolved image.");
         goto MATCH_ERROR;
@@ -953,6 +957,6 @@
     kernels1->mode = PM_SUBTRACTION_MODE_1;
 
-    if (!subtractionModeTest(stamps1, kernels1, "forward", subMask1, rej)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to test forward subtraction");
+    if (!subtractionModeTest(stamps1, kernels1, "convolve 1", subMask1, rej)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to test subtraction with convolution of image 1");
         psFree(stamps1);
         psFree(kernels1);
@@ -968,6 +972,6 @@
     kernels2->mode = PM_SUBTRACTION_MODE_2;
 
-    if (!subtractionModeTest(stamps2, kernels2, "backward", subMask2, rej)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to test backward subtraction");
+    if (!subtractionModeTest(stamps2, kernels2, "convolve 2", subMask2, rej)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to test subtraction with convolution of image 2");
         psFree(stamps2);
         psFree(kernels2);
@@ -983,5 +987,5 @@
     pmSubtractionKernels *bestKernels = NULL; // Best choice for kernels
     psLogMsg("psModules.imcombine", PS_LOG_INFO,
-             "Forward: %f +/- %f from %d stamps\nBackward: %f +/- %f from %d stamps\n",
+             "Image 1: %f +/- %f from %d stamps\nImage 2: %f +/- %f from %d stamps\n",
              kernels1->mean, kernels1->rms, kernels1->numStamps,
              kernels2->mean, kernels2->rms, kernels2->numStamps);
Index: branches/eam_branches/20090820/psModules/src/objects/Makefile.am
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/Makefile.am	(revision 25766)
@@ -50,14 +50,18 @@
 	pmPSF_IO.c \
 	pmPSFtry.c \
+	pmPSFtryModel.c \
+	pmPSFtryFitEXT.c \
+	pmPSFtryMakePSF.c \
+	pmPSFtryFitPSF.c \
+	pmPSFtryMetric.c \
 	pmTrend2D.c \
 	pmGrowthCurveGenerate.c \
 	pmGrowthCurve.c \
-	pmSourceMatch.c
-
-EXTRA_DIST = \
+	pmSourceMatch.c \
+	pmDetEff.c \
 	models/pmModel_GAUSS.c \
 	models/pmModel_PGAUSS.c \
+	models/pmModel_PS1_V1.c \
 	models/pmModel_QGAUSS.c \
-	models/pmModel_SGAUSS.c \
 	models/pmModel_RGAUSS.c \
 	models/pmModel_SERSIC.c
@@ -90,5 +94,12 @@
 	pmTrend2D.h \
 	pmGrowthCurve.h \
-	pmSourceMatch.h
+	pmSourceMatch.h \
+	pmDetEff.h \
+	models/pmModel_GAUSS.h \
+	models/pmModel_PGAUSS.h \
+	models/pmModel_PS1_V1.h \
+	models/pmModel_QGAUSS.h \
+	models/pmModel_RGAUSS.h \
+	models/pmModel_SERSIC.h
 
 CLEANFILES = *~
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_GAUSS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_GAUSS.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_GAUSS.c	(revision 25766)
@@ -1,8 +1,8 @@
 /******************************************************************************
  * this file defines the GAUSS source shape model.  Note that these model functions are loaded
- * by pmModelGroup.c using 'include', and thus need no 'include' statements of their own.  The
+ * by pmModelClass.c using 'include', and thus need no 'include' statements of their own.  The
  * models use a psVector to represent the set of parameters, with the sequence used to specify
  * the meaning of the parameter.  The meaning of the parameters may thus vary depending on the
- * specifics of the model.  All models which are used a PSF representations share a few
+ * specifics of the model.  All models which are used as a PSF representations share a few
  * parameters, for which # define names are listed in pmModel.h:
 
@@ -19,4 +19,13 @@
  *****************************************************************************/
 
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmMoments.h"
+#include "pmPeaks.h"
+#include "pmSource.h"
+#include "pmModel.h"
+#include "pmModel_GAUSS.h"
+
 # define PM_MODEL_FUNC            pmModelFunc_GAUSS
 # define PM_MODEL_FLUX            pmModelFlux_GAUSS
@@ -27,6 +36,24 @@
 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_GAUSS
 # define PM_MODEL_FIT_STATUS      pmModelFitStatus_GAUSS
+# define PM_MODEL_SET_LIMITS      pmModelSetLimits_GAUSS
+
+// Lax parameter limits
+static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0 };
+static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0 };
+
+// Strict parameter limits
+static float *paramsMinStrict = paramsMinLax;
+static float *paramsMaxStrict = paramsMaxLax;
+
+// Parameter limits to use
+static float *paramsMinUse = paramsMinLax;
+static float *paramsMaxUse = paramsMaxLax;
+static float betaUse[] = { 1000, 3e6, 5, 5, 2.0, 2.0, 0.5 };
+
+static bool limitsApply = true;         // Apply limits?
 
 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y)
+// 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords
+// values need to be pixel coords
 psF32 PM_MODEL_FUNC(psVector *deriv,
                     const psVector *params,
@@ -68,118 +95,66 @@
 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta)
 {
-    float beta_lim = 0, params_min = 0, params_max = 0;
-    float f1 = 0, f2 = 0, q1 = 0, q2 = 0;
+    if (!limitsApply) {
+        return true;
+    }
+    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
+    float q2 = NAN;
     if (nParam == PM_PAR_SXY) {
-        f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
-        q1 = PS_MAX (0.0, q1);
+        float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
+        q1 = (q1 < 0.0) ? 0.0 : q1;
         // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg..  Saturate at that
         // angle and let f2,f1 fight it out
-        q2  = 0.5*sqrt (q1);
+        q2 = 0.5*sqrtf(q1);
     }
 
     switch (mode) {
-    case PS_MINIMIZE_BETA_LIMIT:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            beta_lim = 1000;
-            break;
-        case PM_PAR_I0:
-            beta_lim = 3e6;
-            break;
-        case PM_PAR_XPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_YPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_SXX:
-            beta_lim = 2.0;
-            break;
-        case PM_PAR_SYY:
-            beta_lim = 2.0;
-            break;
-        case PM_PAR_SXY:
-            beta_lim =  0.5*q2;
-            break;
-        default:
-            psAbort("invalid parameter %d for beta test", nParam);
-        }
-        if (fabs(beta[nParam]) > fabs(beta_lim)) {
-            beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim);
-            psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
-                     nParam, beta[nParam], beta_lim);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MIN:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_min = -1000;
-            break;
-        case PM_PAR_I0:
-            params_min =   0.01;
-            break;
-        case PM_PAR_XPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_YPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_SXX:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SYY:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SXY:
-            params_min =   -q2;
-            break;
-        default:
-            psAbort("invalid parameter %d for param min test", nParam);
-        }
-        if (params[nParam] < params_min) {
-            params[nParam] = params_min;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
-                     nParam, params[nParam], params_min);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MAX:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_max =   1e5;
-            break;
-        case PM_PAR_I0:
-            params_max =   1e8;
-            break;
-        case PM_PAR_XPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_YPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_SXX:
-            params_max =   100;
-            break;
-        case PM_PAR_SYY:
-            params_max =   100;
-            break;
-        case PM_PAR_SXY:
-            params_max =   +q2;
-            break;
-        default:
-            psAbort("invalid parameter %d for param max test", nParam);
-        }
-        if (params[nParam] > params_max) {
-            params[nParam] = params_max;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
-                     nParam, params[nParam], params_max);
-            return false;
-        }
-        return true;
+      case PS_MINIMIZE_BETA_LIMIT: {
+          psAssert(beta, "Require beta to limit beta");
+          float limit = betaUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (fabs(beta[nParam]) > fabs(limit)) {
+              beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit);
+              psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
+                      nParam, beta[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MIN: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMinUse, "Require parameter limits to limit parameters");
+          float limit = paramsMinUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] < limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MAX: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMaxUse, "Require parameter limits to limit parameters");
+          float limit = paramsMaxUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] > limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
     default:
         psAbort("invalid choice for limits");
@@ -190,4 +165,5 @@
 
 // make an initial guess for parameters
+// 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters
 bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
 {
@@ -205,5 +181,5 @@
     psEllipseShape shape = psEllipseAxesToShape (axes);
 
-    PAR[PM_PAR_SKY]  = moments->Sky;
+    PAR[PM_PAR_SKY]  = 0.0;
     PAR[PM_PAR_I0]   = peak->flux;
     PAR[PM_PAR_XPOS] = peak->xf;
@@ -257,4 +233,6 @@
     psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
     psF64 radius = axes.major * sqrt (2.0 * log(PAR[PM_PAR_I0] / flux));
+    psAssert (isfinite(radius), "fix this code: radius should not be nan for %f", PAR[PM_PAR_I0]);
+
     return (radius);
 }
@@ -367,5 +345,4 @@
 bool PM_MODEL_FIT_STATUS (pmModel *model)
 {
-    psF32 dP;
     bool  status;
 
@@ -373,17 +350,38 @@
     psF32 *dPAR = model->dparams->data.F32;
 
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
     status = true;
-    status &= (dP < 0.5);
     status &= (PAR[PM_PAR_I0] > 0);
     status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
 
-    if (status)
-        return true;
-    return false;
+    return status;
+}
+
+void PM_MODEL_SET_LIMITS(pmModelLimitsType type)
+{
+    switch (type) {
+      case PM_MODEL_LIMITS_NONE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_IGNORE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = false;
+        break;
+      case PM_MODEL_LIMITS_LAX:
+        paramsMinUse = paramsMinLax;
+        paramsMaxUse = paramsMaxLax;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_STRICT:
+        paramsMinUse = paramsMinStrict;
+        paramsMaxUse = paramsMaxStrict;
+        limitsApply = true;
+        break;
+      default:
+        psAbort("Unrecognised model limits type: %x", type);
+    }
+    return;
 }
 
@@ -396,2 +394,3 @@
 # undef PM_MODEL_PARAMS_FROM_PSF
 # undef PM_MODEL_FIT_STATUS
+# undef PM_MODEL_SET_LIMITS
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_GAUSS.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_GAUSS.h	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_GAUSS.h	(revision 25766)
@@ -0,0 +1,15 @@
+#ifndef PM_MODEL_GAUSS_H
+
+#include "pmModel.h"
+
+psF32 pmModelFunc_GAUSS(psVector *deriv, const psVector *params, const psVector *pixcoord);
+bool pmModelLimits_GAUSS(psMinConstraintMode mode, int nParam, float *params, float *beta);
+bool pmModelGuess_GAUSS(pmModel *model, pmSource *source);
+psF64 pmModelFlux_GAUSS(const psVector *params);
+psF64 pmModelRadius_GAUSS(const psVector *params, psF64 flux);
+bool pmModelFromPSF_GAUSS(pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf);
+bool  pmModelParamsFromPSF_GAUSS(pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io);
+bool pmModelFitStatus_GAUSS(pmModel *model);
+void pmModelSetLimits_GAUSS(pmModelLimitsType type);
+
+#endif
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PGAUSS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PGAUSS.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PGAUSS.c	(revision 25766)
@@ -1,8 +1,8 @@
 /******************************************************************************
  * this file defines the PGAUSS source shape model.  Note that these model functions are loaded
- * by pmModelGroup.c using 'include', and thus need no 'include' statements of their own.  The
+ * by pmModelClass.c using 'include', and thus need no 'include' statements of their own.  The
  * models use a psVector to represent the set of parameters, with the sequence used to specify
  * the meaning of the parameter.  The meaning of the parameters may thus vary depending on the
- * specifics of the model.  All models which are used a PSF representations share a few
+ * specifics of the model.  All models which are used as a PSF representations share a few
  * parameters, for which # define names are listed in pmModel.h:
 
@@ -19,4 +19,13 @@
  *****************************************************************************/
 
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmMoments.h"
+#include "pmPeaks.h"
+#include "pmSource.h"
+#include "pmModel.h"
+#include "pmModel_PGAUSS.h"
+
 # define PM_MODEL_FUNC            pmModelFunc_PGAUSS
 # define PM_MODEL_FLUX            pmModelFlux_PGAUSS
@@ -27,6 +36,24 @@
 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_PGAUSS
 # define PM_MODEL_FIT_STATUS      pmModelFitStatus_PGAUSS
+# define PM_MODEL_SET_LIMITS      pmModelSetLimits_PGAUSS
+
+// Lax parameter limits
+static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0 };
+static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0 };
+
+// Strict parameter limits
+static float *paramsMinStrict = paramsMinLax;
+static float *paramsMaxStrict = paramsMaxLax;
+
+// Parameter limits to use
+static float *paramsMinUse = paramsMinLax;
+static float *paramsMaxUse = paramsMaxLax;
+static float betaUse[] = { 1000, 3e6, 5, 5, 2.0, 2.0, 0.5 };
+
+static bool limitsApply = true;         // Apply limits?
 
 // the model is a function of the pixel coordinate (pixcoord[0,1] = x,y)
+// 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords
+// values need to be pixel coords
 psF32 PM_MODEL_FUNC(psVector *deriv,
                     const psVector *params,
@@ -69,119 +96,67 @@
 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta)
 {
-    float beta_lim = 0, params_min = 0, params_max = 0;
-    float f1 = 0, f2 = 0, q1 = 0, q2 = 0;
+    if (!limitsApply) {
+        return true;
+    }
+    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
+    float q2 = NAN;
     if (nParam == PM_PAR_SXY) {
-        f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
-        q1 = PS_MAX (0.0, q1);
+        float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
+        q1 = (q1 < 0.0) ? 0.0 : q1;
         // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg..  Saturate at that
         // angle and let f2,f1 fight it out
-        q2  = 0.5*sqrt (q1);
+        q2 = 0.5*sqrtf(q1);
     }
 
     switch (mode) {
-    case PS_MINIMIZE_BETA_LIMIT:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            beta_lim = 1000;
-            break;
-        case PM_PAR_I0:
-            beta_lim = 3e6;
-            break;
-        case PM_PAR_XPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_YPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_SXX:
-            beta_lim = 2.0;
-            break;
-        case PM_PAR_SYY:
-            beta_lim = 2.0;
-            break;
-        case PM_PAR_SXY:
-            beta_lim =  0.5*q2;
-            break;
-        default:
-            psAbort("invalid parameter %d for beta test", nParam);
-        }
-        if (fabs(beta[nParam]) > fabs(beta_lim)) {
-            beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim);
-            psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
-                     nParam, beta[nParam], beta_lim);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MIN:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_min = -1000;
-            break;
-        case PM_PAR_I0:
-            params_min =  0.01;
-            break;
-        case PM_PAR_XPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_YPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_SXX:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SYY:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SXY:
-            params_min =   -q2;
-            break;
-        default:
-            psAbort("invalid parameter %d for param min test", nParam);
-        }
-        if (params[nParam] < params_min) {
-            params[nParam] = params_min;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
-                     nParam, params[nParam], params_min);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MAX:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_max =   1e5;
-            break;
-        case PM_PAR_I0:
-            params_max =   1e8;
-            break;
-        case PM_PAR_XPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_YPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_SXX:
-            params_max =   100;
-            break;
-        case PM_PAR_SYY:
-            params_max =   100;
-            break;
-        case PM_PAR_SXY:
-            params_max =   +q2;
-            break;
-        default:
-            psAbort("invalid parameter %d for param max test", nParam);
-        }
-        if (params[nParam] > params_max) {
-            params[nParam] = params_max;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
-                     nParam, params[nParam], params_max);
-            return false;
-        }
-        return true;
-    default:
+      case PS_MINIMIZE_BETA_LIMIT: {
+          psAssert(beta, "Require beta to limit beta");
+          float limit = betaUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (fabs(beta[nParam]) > fabs(limit)) {
+              beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit);
+              psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
+                      nParam, beta[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MIN: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMinUse, "Require parameter limits to limit parameters");
+          float limit = paramsMinUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] < limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MAX: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMaxUse, "Require parameter limits to limit parameters");
+          float limit = paramsMaxUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] > limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      default:
         psAbort("invalid choice for limits");
     }
@@ -190,5 +165,7 @@
 }
 
+
 // make an initial guess for parameters
+// 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters
 bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
 {
@@ -205,5 +182,5 @@
     psEllipseShape shape = psEllipseAxesToShape (axes);
 
-    PAR[PM_PAR_SKY]  = moments->Sky;
+    PAR[PM_PAR_SKY]  = 0.0;
     PAR[PM_PAR_I0]   = peak->flux;
     PAR[PM_PAR_XPOS] = peak->xf;
@@ -284,5 +261,7 @@
     // choose a z value guaranteed to be beyond our limit
     float z0 = pow((1.0 / limit), (1.0 / 3.0));
+    psAssert (isfinite(z0), "fix this code: z0 should not be nan for %f", PAR[PM_PAR_I0]);
     float z1 = (1.0 / limit);
+    psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_I0]);
     z1 = PS_MAX (z0, z1);
     z0 = 0.0;
@@ -415,5 +394,4 @@
 bool PM_MODEL_FIT_STATUS (pmModel *model)
 {
-    psF32 dP;
     bool  status;
 
@@ -421,15 +399,39 @@
     psF32 *dPAR = model->dparams->data.F32;
 
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
     status = true;
-    status &= (dP < 0.5);
     status &= (PAR[PM_PAR_I0] > 0);
     status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
 
     return status;
+}
+
+
+void PM_MODEL_SET_LIMITS(pmModelLimitsType type)
+{
+    switch (type) {
+      case PM_MODEL_LIMITS_NONE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_IGNORE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = false;
+        break;
+      case PM_MODEL_LIMITS_LAX:
+        paramsMinUse = paramsMinLax;
+        paramsMaxUse = paramsMaxLax;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_STRICT:
+        paramsMinUse = paramsMinStrict;
+        paramsMaxUse = paramsMaxStrict;
+        limitsApply = true;
+        break;
+      default:
+        psAbort("Unrecognised model limits type: %x", type);
+    }
+    return;
 }
 
@@ -442,2 +444,3 @@
 # undef PM_MODEL_PARAMS_FROM_PSF
 # undef PM_MODEL_FIT_STATUS
+# undef PM_MODEL_SET_LIMITS
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PGAUSS.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PGAUSS.h	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PGAUSS.h	(revision 25766)
@@ -0,0 +1,15 @@
+#ifndef PM_MODEL_PGAUSS_H
+
+#include "pmModel.h"
+
+psF32 pmModelFunc_PGAUSS(psVector *deriv, const psVector *params, const psVector *pixcoord);
+bool pmModelLimits_PGAUSS(psMinConstraintMode mode, int nParam, float *params, float *beta);
+bool pmModelGuess_PGAUSS(pmModel *model, pmSource *source);
+psF64 pmModelFlux_PGAUSS(const psVector *params);
+psF64 pmModelRadius_PGAUSS(const psVector *params, psF64 flux);
+bool pmModelFromPSF_PGAUSS(pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf);
+bool  pmModelParamsFromPSF_PGAUSS(pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io);
+bool pmModelFitStatus_PGAUSS(pmModel *model);
+void pmModelSetLimits_PGAUSS(pmModelLimitsType type);
+
+#endif
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PS1_V1.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PS1_V1.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PS1_V1.c	(revision 25766)
@@ -1,9 +1,9 @@
 /******************************************************************************
- * this file defines the PS1_V1 source shape model (XXX need a better name!).  Note that these
- * model functions are loaded by pmModelGroup.c using 'include', and thus need no 'include'
- * statements of their own.  The models use a psVector to represent the set of parameters, with
- * the sequence used to specify the meaning of the parameter.  The meaning of the parameters
- * may thus vary depending on the specifics of the model.  All models which are used a PSF
- * representations share a few parameters, for which # define names are listed in pmModel.h:
+ * this file defines the PS1_V1 source shape model.  Note that these model functions are loaded
+ * by pmModelClass.c using 'include', and thus need no 'include' statements of their own.  The
+ * models use a psVector to represent the set of parameters, with the sequence used to specify
+ * the meaning of the parameter.  The meaning of the parameters may thus vary depending on the
+ * specifics of the model.  All models which are used as a PSF representations share a few
+ * parameters, for which # define names are listed in pmModel.h:
 
    power-law with fitted linear term
@@ -20,4 +20,13 @@
    *****************************************************************************/
 
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmMoments.h"
+#include "pmPeaks.h"
+#include "pmSource.h"
+#include "pmModel.h"
+#include "pmModel_PS1_V1.h"
+
 # define PM_MODEL_FUNC            pmModelFunc_PS1_V1
 # define PM_MODEL_FLUX            pmModelFlux_PS1_V1
@@ -28,7 +37,28 @@
 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_PS1_V1
 # define PM_MODEL_FIT_STATUS      pmModelFitStatus_PS1_V1
+# define PM_MODEL_SET_LIMITS      pmModelSetLimits_PS1_V1
 
 # define ALPHA   1.666
 # define ALPHA_M 0.666
+
+// the model is a function of the pixel coordinate (pixcoord[0,1] = x,y)
+// 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords
+// values need to be pixel coords
+
+// Lax parameter limits
+static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, -1.0 };
+static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 };
+
+// Strict parameter limits
+// k = PAR_7 < 0 is very undesirable (big divot in the middle)
+static float paramsMinStrict[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, 0.0 };
+static float paramsMaxStrict[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 };
+
+// Parameter limits to use
+static float *paramsMinUse = paramsMinLax;
+static float *paramsMaxUse = paramsMaxLax;
+static float betaUse[] = { 1000, 3e6, 5, 5, 1.0, 1.0, 0.5, 2.0 };
+
+static bool limitsApply = true;         // Apply limits?
 
 psF32 PM_MODEL_FUNC (psVector *deriv,
@@ -84,128 +114,67 @@
 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta)
 {
-    float beta_lim = 0, params_min = 0, params_max = 0;
-    float f1 = 0, f2 = 0, q1 = 0, q2 = 0;
+    if (!limitsApply) {
+        return true;
+    }
+    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
+    float q2 = NAN;
     if (nParam == PM_PAR_SXY) {
-        f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
+        float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
         q1 = (q1 < 0.0) ? 0.0 : q1;
         // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg..  Saturate at that
         // angle and let f2,f1 fight it out
-        q2  = 0.5*sqrt (q1);
+        q2 = 0.5*sqrtf(q1);
     }
 
     switch (mode) {
-    case PS_MINIMIZE_BETA_LIMIT:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            beta_lim = 1000;
-            break;
-        case PM_PAR_I0:
-            beta_lim = 3e6;
-            break;
-        case PM_PAR_XPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_YPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_SXX:
-            beta_lim = 1.0;
-            break;
-        case PM_PAR_SYY:
-            beta_lim = 1.0;
-            break;
-        case PM_PAR_SXY:
-            beta_lim =  0.5*q2;
-            break;
-        case PM_PAR_7:
-            beta_lim = 2.0;
-            break;
-        default:
-            psAbort("invalid parameter %d for beta test", nParam);
-        }
-        if (fabs(beta[nParam]) > fabs(beta_lim)) {
-            beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim);
-            psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
-                     nParam, beta[nParam], beta_lim);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MIN:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_min = -1000;
-            break;
-        case PM_PAR_I0:
-            params_min =   0.01;
-            break;
-        case PM_PAR_XPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_YPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_SXX:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SYY:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SXY:
-            params_min =  -q2;
-            break;
-        case PM_PAR_7:
-            params_min =  -1.0;
-            break;
-        default:
-            psAbort("invalid parameter %d for param min test", nParam);
-        }
-        if (params[nParam] < params_min) {
-            params[nParam] = params_min;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
-                     nParam, params[nParam], params_min);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MAX:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_max =   1e5;
-            break;
-        case PM_PAR_I0:
-            params_max =   1e8;
-            break;
-        case PM_PAR_XPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_YPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_SXX:
-            params_max =   100;
-            break;
-        case PM_PAR_SYY:
-            params_max =   100;
-            break;
-        case PM_PAR_SXY:
-            params_max =  +q2;
-            break;
-        case PM_PAR_7:
-            params_max =  20.0;
-            break;
-        default:
-            psAbort("invalid parameter %d for param max test", nParam);
-        }
-        if (params[nParam] > params_max) {
-            params[nParam] = params_max;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
-                     nParam, params[nParam], params_max);
-            return false;
-        }
-        return true;
-    default:
+      case PS_MINIMIZE_BETA_LIMIT: {
+          psAssert(beta, "Require beta to limit beta");
+          float limit = betaUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (fabs(beta[nParam]) > fabs(limit)) {
+              beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit);
+              psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
+                      nParam, beta[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MIN: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMinUse, "Require parameter limits to limit parameters");
+          float limit = paramsMinUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] < limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MAX: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMaxUse, "Require parameter limits to limit parameters");
+          float limit = paramsMaxUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] > limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      default:
         psAbort("invalid choice for limits");
     }
@@ -216,4 +185,5 @@
 
 // make an initial guess for parameters
+// 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters
 bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
 {
@@ -240,5 +210,4 @@
     if (!isfinite(shape.sxy)) return false;
 
-    // XXX turn this off here for now PAR[PM_PAR_SKY]  = moments->Sky;
     PAR[PM_PAR_SKY]  = 0.0;
     PAR[PM_PAR_I0]   = peak->flux;
@@ -299,10 +268,16 @@
     psF32 *PAR = params->data.F32;
 
-    if (flux <= 0)
-        return (1.0);
-    if (PAR[PM_PAR_I0] <= 0)
-        return (1.0);
-    if (flux >= PAR[PM_PAR_I0])
-        return (1.0);
+    if (flux <= 0) {
+        return 1.0;
+    }
+    if (PAR[PM_PAR_I0] <= 0) {
+        return 1.0;
+    }
+    if (flux >= PAR[PM_PAR_I0]) {
+        return 1.0;
+    }
+    if (PAR[PM_PAR_7] == 0.0) {
+        return powf(PAR[PM_PAR_I0] / flux - 1.0, 1.0 / ALPHA);
+    }
 
     shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
@@ -320,8 +295,8 @@
 
     // choose a z value guaranteed to be beyond our limit
-    float z0 = pow((1.0 / limit), (1.0 / ALPHA));
-    float z1 = (1.0 / limit) / PAR[PM_PAR_7];
-    z1 = PS_MAX (z0, z1);
-    z0 = 0.0;
+    float z0 = 0.0;
+    float z1 = pow((1.0 / limit), (1.0 / ALPHA));
+    psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]);
+    if (PAR[PM_PAR_7] < 0.0) z1 *= 2.0;
 
     // perform a type of bisection to find the value
@@ -448,6 +423,4 @@
 bool PM_MODEL_FIT_STATUS (pmModel *model)
 {
-
-    psF32 dP;
     bool  status;
 
@@ -455,11 +428,5 @@
     psF32 *dPAR = model->dparams->data.F32;
 
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
     status = true;
-//    status &= (dP < 0.5);
     status &= (PAR[PM_PAR_I0] > 0);
     status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
@@ -467,4 +434,35 @@
     return status;
 }
+
+
+void PM_MODEL_SET_LIMITS(pmModelLimitsType type)
+{
+    switch (type) {
+      case PM_MODEL_LIMITS_NONE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_IGNORE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = false;
+        break;
+      case PM_MODEL_LIMITS_LAX:
+        paramsMinUse = paramsMinLax;
+        paramsMaxUse = paramsMaxLax;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_STRICT:
+        paramsMinUse = paramsMinStrict;
+        paramsMaxUse = paramsMaxStrict;
+        limitsApply = true;
+        break;
+      default:
+        psAbort("Unrecognised model limits type: %x", type);
+    }
+    return;
+}
+
 
 # undef PM_MODEL_FUNC
@@ -476,4 +474,5 @@
 # undef PM_MODEL_PARAMS_FROM_PSF
 # undef PM_MODEL_FIT_STATUS
+# undef PM_MODEL_SET_LIMITS
 # undef ALPHA
 # undef ALPHA_M
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PS1_V1.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PS1_V1.h	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_PS1_V1.h	(revision 25766)
@@ -0,0 +1,15 @@
+#ifndef PM_MODEL_PS1_V1_H
+
+#include "pmModel.h"
+
+psF32 pmModelFunc_PS1_V1(psVector *deriv, const psVector *params, const psVector *pixcoord);
+bool pmModelLimits_PS1_V1(psMinConstraintMode mode, int nParam, float *params, float *beta);
+bool pmModelGuess_PS1_V1(pmModel *model, pmSource *source);
+psF64 pmModelFlux_PS1_V1(const psVector *params);
+psF64 pmModelRadius_PS1_V1(const psVector *params, psF64 flux);
+bool pmModelFromPSF_PS1_V1(pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf);
+bool  pmModelParamsFromPSF_PS1_V1(pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io);
+bool pmModelFitStatus_PS1_V1(pmModel *model);
+void pmModelSetLimits_PS1_V1(pmModelLimitsType type);
+
+#endif
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_QGAUSS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_QGAUSS.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_QGAUSS.c	(revision 25766)
@@ -1,5 +1,5 @@
 /******************************************************************************
  * this file defines the QGAUSS source shape model (XXX need a better name!).  Note that these
- * model functions are loaded by pmModelGroup.c using 'include', and thus need no 'include'
+ * model functions are loaded by pmModelClass.c using 'include', and thus need no 'include'
  * statements of their own.  The models use a psVector to represent the set of parameters, with
  * the sequence used to specify the meaning of the parameter.  The meaning of the parameters
@@ -20,4 +20,13 @@
    *****************************************************************************/
 
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmMoments.h"
+#include "pmPeaks.h"
+#include "pmSource.h"
+#include "pmModel.h"
+#include "pmModel_QGAUSS.h"
+
 # define PM_MODEL_FUNC            pmModelFunc_QGAUSS
 # define PM_MODEL_FLUX            pmModelFlux_QGAUSS
@@ -28,4 +37,24 @@
 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_QGAUSS
 # define PM_MODEL_FIT_STATUS      pmModelFitStatus_QGAUSS
+# define PM_MODEL_SET_LIMITS      pmModelSetLimits_QGAUSS
+
+// the model is a function of the pixel coordinate (pixcoord[0,1] = x,y)
+// 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords
+// values need to be pixel coords
+
+// Lax parameter limits
+static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, 0.1 };
+static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 20.0 };
+
+// Strict parameter limits
+static float *paramsMinStrict = paramsMinLax;
+static float *paramsMaxStrict = paramsMaxLax;
+
+// Parameter limits to use
+static float *paramsMinUse = paramsMinLax;
+static float *paramsMaxUse = paramsMaxLax;
+static float betaUse[] = { 1000, 3e6, 5, 5, 1.0, 1.0, 0.5 };
+
+static bool limitsApply = true;         // Apply limits?
 
 psF32 PM_MODEL_FUNC (psVector *deriv,
@@ -79,129 +108,69 @@
 # define AR_MAX 20.0
 # define AR_RATIO 0.99
+
 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta)
 {
-    float beta_lim = 0, params_min = 0, params_max = 0;
-    float f1 = 0, f2 = 0, q1 = 0, q2 = 0;
+    if (!limitsApply) {
+        return true;
+    }
+    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
+    float q2 = NAN;
     if (nParam == PM_PAR_SXY) {
-        f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
+        float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
         q1 = (q1 < 0.0) ? 0.0 : q1;
         // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg..  Saturate at that
         // angle and let f2,f1 fight it out
-        q2  = 0.5*sqrt (q1);
+        q2 = 0.5*sqrtf(q1);
     }
 
     switch (mode) {
-    case PS_MINIMIZE_BETA_LIMIT:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            beta_lim = 1000;
-            break;
-        case PM_PAR_I0:
-            beta_lim = 3e6;
-            break;
-        case PM_PAR_XPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_YPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_SXX:
-            beta_lim = 1.0;
-            break;
-        case PM_PAR_SYY:
-            beta_lim = 1.0;
-            break;
-        case PM_PAR_SXY:
-            beta_lim =  0.5*q2;
-            break;
-        case PM_PAR_7:
-            beta_lim = 2.0;
-            break;
-        default:
-            psAbort("invalid parameter %d for beta test", nParam);
-        }
-        if (fabs(beta[nParam]) > fabs(beta_lim)) {
-            beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim);
-            psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
-                     nParam, beta[nParam], beta_lim);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MIN:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_min = -1000;
-            break;
-        case PM_PAR_I0:
-            params_min =   0.01;
-            break;
-        case PM_PAR_XPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_YPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_SXX:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SYY:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SXY:
-            params_min =  -q2;
-            break;
-        case PM_PAR_7:
-            params_min =   0.1;
-            break;
-        default:
-            psAbort("invalid parameter %d for param min test", nParam);
-        }
-        if (params[nParam] < params_min) {
-            params[nParam] = params_min;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
-                     nParam, params[nParam], params_min);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MAX:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_max =   1e5;
-            break;
-        case PM_PAR_I0:
-            params_max =   1e8;
-            break;
-        case PM_PAR_XPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_YPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_SXX:
-            params_max =   100;
-            break;
-        case PM_PAR_SYY:
-            params_max =   100;
-            break;
-        case PM_PAR_SXY:
-            params_max =  +q2;
-            break;
-        case PM_PAR_7:
-            params_max =  20.0;
-            break;
-        default:
-            psAbort("invalid parameter %d for param max test", nParam);
-        }
-        if (params[nParam] > params_max) {
-            params[nParam] = params_max;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
-                     nParam, params[nParam], params_max);
-            return false;
-        }
-        return true;
+      case PS_MINIMIZE_BETA_LIMIT: {
+          psAssert(beta, "Require beta to limit beta");
+          float limit = betaUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (fabs(beta[nParam]) > fabs(limit)) {
+              beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit);
+              psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
+                      nParam, beta[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MIN: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMinUse, "Require parameter limits to limit parameters");
+          float limit = paramsMinUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] < limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MAX: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMaxUse, "Require parameter limits to limit parameters");
+          float limit = paramsMaxUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] > limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
     default:
         psAbort("invalid choice for limits");
@@ -213,4 +182,5 @@
 
 // make an initial guess for parameters
+// 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters
 bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
 {
@@ -237,5 +207,4 @@
     if (!isfinite(shape.sxy)) return false;
 
-    // XXX turn this off here for now PAR[PM_PAR_SKY]  = moments->Sky;
     PAR[PM_PAR_SKY]  = 0.0;
     PAR[PM_PAR_I0]   = peak->flux;
@@ -318,5 +287,7 @@
     // choose a z value guaranteed to be beyond our limit
     float z0 = pow((1.0 / limit), (1.0 / 2.25));
+    psAssert (isfinite(z0), "fix this code: z0 should not be nan for %f", PAR[PM_PAR_7]);
     float z1 = (1.0 / limit) / PAR[PM_PAR_7];
+    psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]);
     z1 = PS_MAX (z0, z1);
     z0 = 0.0;
@@ -444,6 +415,4 @@
 bool PM_MODEL_FIT_STATUS (pmModel *model)
 {
-
-    psF32 dP;
     bool  status;
 
@@ -451,15 +420,39 @@
     psF32 *dPAR = model->dparams->data.F32;
 
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
     status = true;
-//    status &= (dP < 0.5);
     status &= (PAR[PM_PAR_I0] > 0);
     status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
 
     return status;
+}
+
+
+void PM_MODEL_SET_LIMITS(pmModelLimitsType type)
+{
+    switch (type) {
+      case PM_MODEL_LIMITS_NONE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_IGNORE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = false;
+        break;
+      case PM_MODEL_LIMITS_LAX:
+        paramsMinUse = paramsMinLax;
+        paramsMaxUse = paramsMaxLax;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_STRICT:
+        paramsMinUse = paramsMinStrict;
+        paramsMaxUse = paramsMaxStrict;
+        limitsApply = true;
+        break;
+      default:
+        psAbort("Unrecognised model limits type: %x", type);
+    }
+    return;
 }
 
@@ -472,2 +465,3 @@
 # undef PM_MODEL_PARAMS_FROM_PSF
 # undef PM_MODEL_FIT_STATUS
+# undef PM_MODEL_SET_LIMITS
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_QGAUSS.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_QGAUSS.h	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_QGAUSS.h	(revision 25766)
@@ -0,0 +1,15 @@
+#ifndef PM_MODEL_QGAUSS_H
+
+#include "pmModel.h"
+
+psF32 pmModelFunc_QGAUSS(psVector *deriv, const psVector *params, const psVector *pixcoord);
+bool pmModelLimits_QGAUSS(psMinConstraintMode mode, int nParam, float *params, float *beta);
+bool pmModelGuess_QGAUSS(pmModel *model, pmSource *source);
+psF64 pmModelFlux_QGAUSS(const psVector *params);
+psF64 pmModelRadius_QGAUSS(const psVector *params, psF64 flux);
+bool pmModelFromPSF_QGAUSS(pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf);
+bool  pmModelParamsFromPSF_QGAUSS(pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io);
+bool pmModelFitStatus_QGAUSS(pmModel *model);
+void pmModelSetLimits_QGAUSS(pmModelLimitsType type);
+
+#endif
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_RGAUSS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_RGAUSS.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_RGAUSS.c	(revision 25766)
@@ -1,8 +1,8 @@
 /******************************************************************************
  * this file defines the RGAUSS source shape model (XXX need a better name!).  Note that these
- * model functions are loaded by pmModelGroup.c using 'include', and thus need no 'include'
+ * model functions are loaded by pmModelClass.c using 'include', and thus need no 'include'
  * statements of their own.  The models use a psVector to represent the set of parameters, with
  * the sequence used to specify the meaning of the parameter.  The meaning of the parameters
- * may thus vary depending on the specifics of the model.  All models which are used a PSF
+ * may thus vary depending on the specifics of the model.  All models which are used as a PSF
  * representations share a few parameters, for which # define names are listed in pmModel.h:
 
@@ -20,4 +20,13 @@
  *****************************************************************************/
 
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmMoments.h"
+#include "pmPeaks.h"
+#include "pmSource.h"
+#include "pmModel.h"
+#include "pmModel_RGAUSS.h"
+
 # define PM_MODEL_FUNC            pmModelFunc_RGAUSS
 # define PM_MODEL_FLUX            pmModelFlux_RGAUSS
@@ -28,4 +37,24 @@
 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_RGAUSS
 # define PM_MODEL_FIT_STATUS      pmModelFitStatus_RGAUSS
+# define PM_MODEL_SET_LIMITS      pmModelSetLimits_RGAUSS
+
+// the model is a function of the pixel coordinate (pixcoord[0,1] = x,y)
+// 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords
+// values need to be pixel coords
+
+// Lax parameter limits
+static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.5, 0.5, -1.0, 1.25 };
+static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 4.0 };
+
+// Strict parameter limits
+static float *paramsMinStrict = paramsMinLax;
+static float *paramsMaxStrict = paramsMaxLax;
+
+// Parameter limits to use
+static float *paramsMinUse = paramsMinLax;
+static float *paramsMaxUse = paramsMaxLax;
+static float betaUse[] = { 1000, 3e6, 5, 5, 0.5, 0.5, 0.5, 0.5 };
+
+static bool limitsApply = true;         // Apply limits?
 
 psF32 PM_MODEL_FUNC (psVector *deriv,
@@ -62,5 +91,5 @@
         dPAR[PM_PAR_SXY] = -q*X*Y;
 
-        // this model derivative is undefined at z = 0.0, but is actually 0.0
+        // this model derivative is undefined at z = 0.0, but the limit is zero as z -> 0.0
         dPAR[PM_PAR_7] = (z == 0.0) ? 0.0 : -5.0*t*log(z)*p*z;
     }
@@ -73,130 +102,70 @@
 # define AR_MAX 20.0
 # define AR_RATIO 0.99
+
 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta)
 {
-    float beta_lim = 0, params_min = 0, params_max = 0;
-    float f1 = 0, f2 = 0, q1 = 0, q2 = 0;
+    if (!limitsApply) {
+        return true;
+    }
+    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
+    float q2 = NAN;
     if (nParam == PM_PAR_SXY) {
-        f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
+        float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
         q1 = (q1 < 0.0) ? 0.0 : q1;
         // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg..  Saturate at that
         // angle and let f2,f1 fight it out
-        q2  = 0.5*sqrt (q1);
+        q2 = 0.5*sqrtf(q1);
     }
 
     switch (mode) {
-    case PS_MINIMIZE_BETA_LIMIT:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            beta_lim = 1000;
-            break;
-        case PM_PAR_I0:
-            beta_lim = 3e6;
-            break;
-        case PM_PAR_XPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_YPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_SXX:
-            beta_lim = 0.5;
-            break;
-        case PM_PAR_SYY:
-            beta_lim = 0.5;
-            break;
-        case PM_PAR_SXY:
-            beta_lim =  0.5*q2;
-            break;
-        case PM_PAR_7:
-            beta_lim = 0.5;
-            break;
-        default:
-            psAbort("invalid parameter %d for beta test", nParam);
-        }
-        if (fabs(beta[nParam]) > fabs(beta_lim)) {
-            beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim);
-            psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
-                     nParam, beta[nParam], beta_lim);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MIN:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_min = -1000;
-            break;
-        case PM_PAR_I0:
-            params_min =   0.01;
-            break;
-        case PM_PAR_XPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_YPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_SXX:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SYY:
-            params_min =   0.5;
-            break;
-        case PM_PAR_SXY:
-            params_min =  -q2;
-            break;
-        case PM_PAR_7:
-            params_min =   1.25;
-            break;
-        default:
-            psAbort("invalid parameter %d for param min test", nParam);
-        }
-        if (params[nParam] < params_min) {
-            params[nParam] = params_min;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
-                     nParam, params[nParam], params_min);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MAX:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_max =   1e5;
-            break;
-        case PM_PAR_I0:
-            params_max =   1e8;
-            break;
-        case PM_PAR_XPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_YPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_SXX:
-            params_max =   100;
-            break;
-        case PM_PAR_SYY:
-            params_max =   100;
-            break;
-        case PM_PAR_SXY:
-            params_max =  +q2;
-            break;
-        case PM_PAR_7:
-            params_max =  4.0;
-            break;
-        default:
-            psAbort("invalid parameter %d for param max test", nParam);
-        }
-        if (params[nParam] > params_max) {
-            params[nParam] = params_max;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
-                     nParam, params[nParam], params_max);
-            return false;
-        }
-        return true;
-    default:
+      case PS_MINIMIZE_BETA_LIMIT: {
+          psAssert(beta, "Require beta to limit beta");
+          float limit = betaUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (fabs(beta[nParam]) > fabs(limit)) {
+              beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit);
+              psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
+                      nParam, beta[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MIN: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMinUse, "Require parameter limits to limit parameters");
+          float limit = paramsMinUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] < limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MAX: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMaxUse, "Require parameter limits to limit parameters");
+          float limit = paramsMaxUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] > limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      default:
         psAbort("invalid choice for limits");
     }
@@ -205,5 +174,7 @@
 }
 
+
 // make an initial guess for parameters
+// 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters
 bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
 {
@@ -230,5 +201,5 @@
     if (!isfinite(shape.sxy)) return false;
 
-    PAR[PM_PAR_SKY]  = moments->Sky;
+    PAR[PM_PAR_SKY]  = 0.0;
     PAR[PM_PAR_I0]   = peak->flux;
     PAR[PM_PAR_XPOS] = peak->xf;
@@ -310,5 +281,7 @@
     // choose a z value guaranteed to be beyond our limit
     float z0 = pow((1.0 / limit), (1.0 / PAR[PM_PAR_7]));
+    psAssert (isfinite(z0), "fix this code: z0 should not be nan for %f", PAR[PM_PAR_7]);
     float z1 = (1.0 / limit);
+    psAssert (isfinite(z1), "fix this code: z1 should not be nan for %f", PAR[PM_PAR_7]);
     z1 = PS_MAX (z0, z1);
     z0 = 0.0;
@@ -436,6 +409,4 @@
 bool PM_MODEL_FIT_STATUS (pmModel *model)
 {
-
-    psF32 dP;
     bool  status;
 
@@ -443,15 +414,39 @@
     psF32 *dPAR = model->dparams->data.F32;
 
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
     status = true;
-    status &= (dP < 0.5);
     status &= (PAR[PM_PAR_I0] > 0);
     status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
 
     return status;
+}
+
+
+void PM_MODEL_SET_LIMITS(pmModelLimitsType type)
+{
+    switch (type) {
+      case PM_MODEL_LIMITS_NONE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_IGNORE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = false;
+        break;
+      case PM_MODEL_LIMITS_LAX:
+        paramsMinUse = paramsMinLax;
+        paramsMaxUse = paramsMaxLax;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_STRICT:
+        paramsMinUse = paramsMinStrict;
+        paramsMaxUse = paramsMaxStrict;
+        limitsApply = true;
+        break;
+      default:
+        psAbort("Unrecognised model limits type: %x", type);
+    }
+    return;
 }
 
@@ -464,2 +459,3 @@
 # undef PM_MODEL_PARAMS_FROM_PSF
 # undef PM_MODEL_FIT_STATUS
+# undef PM_MODEL_SET_LIMITS
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_RGAUSS.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_RGAUSS.h	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_RGAUSS.h	(revision 25766)
@@ -0,0 +1,15 @@
+#ifndef PM_MODEL_RGAUSS_H
+
+#include "pmModel.h"
+
+psF32 pmModelFunc_RGAUSS(psVector *deriv, const psVector *params, const psVector *pixcoord);
+bool pmModelLimits_RGAUSS(psMinConstraintMode mode, int nParam, float *params, float *beta);
+bool pmModelGuess_RGAUSS(pmModel *model, pmSource *source);
+psF64 pmModelFlux_RGAUSS(const psVector *params);
+psF64 pmModelRadius_RGAUSS(const psVector *params, psF64 flux);
+bool pmModelFromPSF_RGAUSS(pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf);
+bool  pmModelParamsFromPSF_RGAUSS(pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io);
+bool pmModelFitStatus_RGAUSS(pmModel *model);
+void pmModelSetLimits_RGAUSS(pmModelLimitsType type);
+
+#endif
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_SERSIC.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_SERSIC.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_SERSIC.c	(revision 25766)
@@ -1,8 +1,8 @@
 /******************************************************************************
  * this file defines the SERSIC source shape model.  Note that these model functions are loaded
- * by pmModelGroup.c using 'include', and thus need no 'include' statements of their own.  The
+ * by pmModelClass.c using 'include', and thus need no 'include' statements of their own.  The
  * models use a psVector to represent the set of parameters, with the sequence used to specify
  * the meaning of the parameter.  The meaning of the parameters may thus vary depending on the
- * specifics of the model.  All models which are used a PSF representations share a few
+ * specifics of the model.  All models which are used as a PSF representations share a few
  * parameters, for which # define names are listed in pmModel.h:
 
@@ -23,4 +23,13 @@
    *****************************************************************************/
 
+#include <stdio.h>
+#include <pslib.h>
+
+#include "pmMoments.h"
+#include "pmPeaks.h"
+#include "pmSource.h"
+#include "pmModel.h"
+#include "pmModel_SERSIC.h"
+
 # define PM_MODEL_FUNC            pmModelFunc_SERSIC
 # define PM_MODEL_FLUX            pmModelFlux_SERSIC
@@ -31,4 +40,24 @@
 # define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_SERSIC
 # define PM_MODEL_FIT_STATUS      pmModelFitStatus_SERSIC
+# define PM_MODEL_SET_LIMITS      pmModelSetLimits_SERSIC
+
+// the model is a function of the pixel coordinate (pixcoord[0,1] = x,y)
+// 0.5 PIX: the parameters are defined in terms of pixel coords, so the incoming pixcoords
+// values need to be pixel coords
+
+// Lax parameter limits
+static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.05, 0.05, -1.0, 0.05 };
+static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 4.0 };
+
+// Strict parameter limits
+static float *paramsMinStrict = paramsMinLax;
+static float *paramsMaxStrict = paramsMaxLax;
+
+// Parameter limits to use
+static float *paramsMinUse = paramsMinLax;
+static float *paramsMaxUse = paramsMaxLax;
+static float betaUse[] = { 1000, 3e6, 5, 5, 1.0, 1.0, 0.5, 2.0 };
+
+static bool limitsApply = true;         // Apply limits?
 
 psF32 PM_MODEL_FUNC (psVector *deriv,
@@ -91,128 +120,67 @@
 bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta)
 {
-    float beta_lim = 0, params_min = 0, params_max = 0;
-    float f1 = 0, f2 = 0, q1 = 0, q2 = 0;
+    if (!limitsApply) {
+        return true;
+    }
+    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
+    float q2 = NAN;
     if (nParam == PM_PAR_SXY) {
-        f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
-        q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
+        float f1 = 1.0 / PS_SQR(params[PM_PAR_SYY]) + 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float f2 = 1.0 / PS_SQR(params[PM_PAR_SYY]) - 1.0 / PS_SQR(params[PM_PAR_SXX]);
+        float q1 = PS_SQR(f1)*AR_RATIO - PS_SQR(f2);
         q1 = (q1 < 0.0) ? 0.0 : q1;
         // if q1 < 0.0, f2 ~ f1, we have a very large axis ratio near 45deg..  Saturate at that
         // angle and let f2,f1 fight it out
-        q2  = 0.5*sqrt (q1);
+        q2 = 0.5*sqrtf(q1);
     }
 
     switch (mode) {
-    case PS_MINIMIZE_BETA_LIMIT:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            beta_lim = 1000;
-            break;
-        case PM_PAR_I0:
-            beta_lim = 3e6;
-            break;
-        case PM_PAR_XPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_YPOS:
-            beta_lim = 5;
-            break;
-        case PM_PAR_SXX:
-            beta_lim = 1.0;
-            break;
-        case PM_PAR_SYY:
-            beta_lim = 1.0;
-            break;
-        case PM_PAR_SXY:
-            beta_lim =  0.5*q2;
-            break;
-        case PM_PAR_7:
-            beta_lim = 2.0;
-            break;
-        default:
-            psAbort("invalid parameter %d for beta test", nParam);
-        }
-        if (fabs(beta[nParam]) > fabs(beta_lim)) {
-            beta[nParam] = (beta[nParam] > 0) ? fabs(beta_lim) : -fabs(beta_lim);
-            psTrace ("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
-                     nParam, beta[nParam], beta_lim);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MIN:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_min = -1000;
-            break;
-        case PM_PAR_I0:
-            params_min =     0.01;
-            break;
-        case PM_PAR_XPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_YPOS:
-            params_min =  -100;
-            break;
-        case PM_PAR_SXX:
-            params_min =   0.05;
-            break;
-        case PM_PAR_SYY:
-            params_min =   0.05;
-            break;
-        case PM_PAR_SXY:
-            params_min =  -q2;
-            break;
-        case PM_PAR_7:
-            params_min =   0.05;
-            break;
-        default:
-            psAbort("invalid parameter %d for param min test", nParam);
-        }
-        if (params[nParam] < params_min) {
-            params[nParam] = params_min;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
-                     nParam, params[nParam], params_min);
-            return false;
-        }
-        return true;
-    case PS_MINIMIZE_PARAM_MAX:
-        switch (nParam) {
-        case PM_PAR_SKY:
-            params_max =   1e5;
-            break;
-        case PM_PAR_I0:
-            params_max =   1e8;
-            break;
-        case PM_PAR_XPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_YPOS:
-            params_max =   1e4;
-            break;
-        case PM_PAR_SXX:
-            params_max =   100;
-            break;
-        case PM_PAR_SYY:
-            params_max =   100;
-            break;
-        case PM_PAR_SXY:
-            params_max =  +q2;
-            break;
-        case PM_PAR_7:
-            params_max =   4.0;
-            break;
-        default:
-            psAbort("invalid parameter %d for param max test", nParam);
-        }
-        if (params[nParam] > params_max) {
-            params[nParam] = params_max;
-            psTrace ("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
-                     nParam, params[nParam], params_max);
-            return false;
-        }
-        return true;
-    default:
+      case PS_MINIMIZE_BETA_LIMIT: {
+          psAssert(beta, "Require beta to limit beta");
+          float limit = betaUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (fabs(beta[nParam]) > fabs(limit)) {
+              beta[nParam] = (beta[nParam] > 0) ? fabs(limit) : -fabs(limit);
+              psTrace("psModules.objects", 5, "|beta[nParam==%d]| > |beta_lim|; %g v. %g",
+                      nParam, beta[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MIN: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMinUse, "Require parameter limits to limit parameters");
+          float limit = paramsMinUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] < limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] < params_min; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      case PS_MINIMIZE_PARAM_MAX: {
+          psAssert(params, "Require parameters to limit parameters");
+          psAssert(paramsMaxUse, "Require parameter limits to limit parameters");
+          float limit = paramsMaxUse[nParam];
+          if (nParam == PM_PAR_SXY) {
+              limit *= q2;
+          }
+          if (params[nParam] > limit) {
+              params[nParam] = limit;
+              psTrace("psModules.objects", 5, "params[nParam==%d] > params_max; %g v. %g",
+                      nParam, params[nParam], limit);
+              return false;
+          }
+          return true;
+      }
+      default:
         psAbort("invalid choice for limits");
     }
@@ -221,6 +189,6 @@
 }
 
-
 // make an initial guess for parameters
+// 0.5 PIX: moments and peaks are in pixel coords, thus so are model parameters
 bool PM_MODEL_GUESS (pmModel *model, pmSource *source)
 {
@@ -247,5 +215,4 @@
     if (!isfinite(shape.sxy)) return false;
 
-    // XXX PAR[PM_PAR_SKY]  = moments->Sky;
     PAR[PM_PAR_SKY]  = 0.0;
     PAR[PM_PAR_I0]   = peak->flux;
@@ -321,6 +288,8 @@
 
     psF64 z = pow (-log(limit), (1.0 / PAR[PM_PAR_7]));
+    psAssert (isfinite(z), "fix this code: z should not be nan for %f", PAR[PM_PAR_7]);
 
     psF64 radius = sigma * sqrt (2.0 * z);
+    psAssert (isfinite(radius), "fix this code: radius should not be nan for %f, %f", PAR[PM_PAR_7], sigma);
 
     if (isnan(radius))
@@ -429,6 +398,4 @@
 bool PM_MODEL_FIT_STATUS (pmModel *model)
 {
-
-    psF32 dP;
     bool  status;
 
@@ -436,18 +403,39 @@
     psF32 *dPAR = model->dparams->data.F32;
 
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
     status = true;
-//    status &= (dP < 0.5);
     status &= (PAR[PM_PAR_I0] > 0);
     status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
 
-    fprintf (stderr, "SERSIC status pars: dP: %f, I0: %f, S/N: %f\n",
-	     dP, PAR[PM_PAR_I0], (dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]));
-
     return status;
+}
+
+
+void PM_MODEL_SET_LIMITS(pmModelLimitsType type)
+{
+    switch (type) {
+      case PM_MODEL_LIMITS_NONE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_IGNORE:
+        paramsMinUse = NULL;
+        paramsMaxUse = NULL;
+        limitsApply = false;
+        break;
+      case PM_MODEL_LIMITS_LAX:
+        paramsMinUse = paramsMinLax;
+        paramsMaxUse = paramsMaxLax;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_STRICT:
+        paramsMinUse = paramsMinStrict;
+        paramsMaxUse = paramsMaxStrict;
+        limitsApply = true;
+        break;
+      default:
+        psAbort("Unrecognised model limits type: %x", type);
+    }
+    return;
 }
 
@@ -460,2 +448,3 @@
 # undef PM_MODEL_PARAMS_FROM_PSF
 # undef PM_MODEL_FIT_STATUS
+# undef PM_MODEL_SET_LIMITS
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_SERSIC.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_SERSIC.h	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/models/pmModel_SERSIC.h	(revision 25766)
@@ -0,0 +1,15 @@
+#ifndef PM_MODEL_SERSIC_H
+
+#include "pmModel.h"
+
+psF32 pmModelFunc_SERSIC(psVector *deriv, const psVector *params, const psVector *pixcoord);
+bool pmModelLimits_SERSIC(psMinConstraintMode mode, int nParam, float *params, float *beta);
+bool pmModelGuess_SERSIC(pmModel *model, pmSource *source);
+psF64 pmModelFlux_SERSIC(const psVector *params);
+psF64 pmModelRadius_SERSIC(const psVector *params, psF64 flux);
+bool pmModelFromPSF_SERSIC(pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf);
+bool  pmModelParamsFromPSF_SERSIC(pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io);
+bool pmModelFitStatus_SERSIC(pmModel *model);
+void pmModelSetLimits_SERSIC(pmModelLimitsType type);
+
+#endif
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_SGAUSS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_SGAUSS.c	(revision 25206)
+++ 	(revision )
@@ -1,389 +1,0 @@
-/******************************************************************************
- * this file defines the SGAUSS source shape model (XXX need a better name!).  Note that these
- * model functions are loaded by pmModelGroup.c using 'include', and thus need no 'include'
- * statements of their own.  The models use a psVector to represent the set of parameters, with
- * the sequence used to specify the meaning of the parameter.  The meaning of the parameters
- * may thus vary depending on the specifics of the model.  All models which are used a PSF
- * representations share a few parameters, for which # define names are listed in pmModel.h:
-
-   power-law with fitted slope and outer tidal radius
-   1 / (1 + z^N + kz^4)
-
-   * PM_PAR_SKY 0   - local sky : note that this is unused and may be dropped in the future
-   * PM_PAR_I0 1    - central intensity
-   * PM_PAR_XPOS 2  - X center of object
-   * PM_PAR_YPOS 3  - Y center of object
-   * PM_PAR_SXX 4   - X^2 term of elliptical contour (sqrt(2) / SigmaX)
-   * PM_PAR_SYY 5   - Y^2 term of elliptical contour (sqrt(2) / SigmaY)
-   * PM_PAR_SXY 6   - X*Y term of elliptical contour
-   * PM_PAR_7   7   - slope of power-law component (N)
-   * PM_PAR_8   8   - amplitude of the tidal cutoff (k)
-   *****************************************************************************/
-
-/***
-    XXXX the model in this file needs to be tested more carefully.
-    the code for guessing the power-law slope based on the radial profile
-    is either too slow or does not work well.
-    fix up the code to follow conventions in the other model function files.
-***/
-
-XXX broken code
-
-# define PM_MODEL_FUNC       pmModelFunc_SGAUSS
-# define PM_MODEL_FLUX       pmModelFlux_SGAUSS
-# define PM_MODEL_GUESS      pmModelGuess_SGAUSS
-# define PM_MODEL_LIMITS     pmModelLimits_SGAUSS
-# define PM_MODEL_RADIUS     pmModelRadius_SGAUSS
-# define PM_MODEL_FROM_PSF   pmModelFromPSF_SGAUSS
-# define PM_MODEL_FIT_STATUS pmModelFitStatus_SGAUSS
-
-psF64 psImageEllipseContour (psEllipseAxes axes, double xc, double yc, psImage *image);
-
-psF32 PM_MODEL_FUNC (psVector *deriv,
-                     const psVector *params,
-                     const psVector *x)
-{
-    psF32 *PAR = params->data.F32;
-
-    psF32 X  = x->data.F32[0] - PAR[2];
-    psF32 Y  = x->data.F32[1] - PAR[3];
-    psF32 px = PAR[4]*X;
-    psF32 py = PAR[5]*Y;
-    psF32 z  = PS_MAX((0.5*PS_SQR(px) + 0.5*PS_SQR(py) + PAR[6]*X*Y), 1e-8);
-    // note that if z -> 0, dPAR[7] -> -inf
-    // also z^(PAR[7]-1) -> Inf
-
-    psF32 pr = z*PAR[8];
-    psF32 pr3 = pr*pr*pr;
-    psF32 p  = pow(z, PAR[7] - 1.0);
-    psF32 r  = 1.0 / (1 + z*p + pr*pr3);
-    psF32 f  = PAR[1]*r + PAR[0];
-
-    if (deriv != NULL) {
-        // note difference from a pure gaussian: q = params->data.F32[1]*r
-        psF32 t = PAR[1]*r*r;
-        psF32 q = t*(PAR[7]*p + 4*PAR[8]*pr3);
-
-        deriv->data.F32[0] = +1.0;
-        deriv->data.F32[1] = +r;
-        deriv->data.F32[2] = q*(2.0*px*PAR[4] + PAR[6]*Y);
-        deriv->data.F32[3] = q*(2.0*py*PAR[5] + PAR[6]*X);
-        deriv->data.F32[4] = -2.0*q*px*X;
-        deriv->data.F32[5] = -2.0*q*py*Y;
-        deriv->data.F32[6] = -q*X*Y;
-        deriv->data.F32[7] = -2*t*log(z)*z*p;
-        deriv->data.F32[8] = -2*t*4*z*pr3;
-    }
-    return(f);
-}
-
-bool PM_MODEL_LIMITS  (psVector **beta_lim, psVector **params_min, psVector **params_max)
-{
-
-    *beta_lim   = psVectorAlloc (9, PS_TYPE_F32);
-    *params_min = psVectorAlloc (9, PS_TYPE_F32);
-    *params_max = psVectorAlloc (9, PS_TYPE_F32);
-
-    beta_lim[0][0].data.F32[0] = 1000;
-    beta_lim[0][0].data.F32[1] = 10000;
-    beta_lim[0][0].data.F32[2] = 5;
-    beta_lim[0][0].data.F32[3] = 5;
-    beta_lim[0][0].data.F32[4] = 0.5;
-    beta_lim[0][0].data.F32[5] = 0.5;
-    beta_lim[0][0].data.F32[6] = 0.5;
-    beta_lim[0][0].data.F32[7] = 0.5;
-    beta_lim[0][0].data.F32[8] = 0.05;
-
-    params_min[0][0].data.F32[0] = -1000;
-    params_min[0][0].data.F32[1] = 0;
-    params_min[0][0].data.F32[2] = -100;
-    params_min[0][0].data.F32[3] = -100;
-    params_min[0][0].data.F32[4] = 0.01;
-    params_min[0][0].data.F32[5] = 0.01;
-    params_min[0][0].data.F32[6] = -5.0;
-    params_min[0][0].data.F32[7] = 0.5;
-    params_min[0][0].data.F32[8] = 0.001;
-
-    params_max[0][0].data.F32[0] = 1e5;
-    params_max[0][0].data.F32[1] = 1e6;
-    params_max[0][0].data.F32[2] = 1e4;  // this should be set by image dimensions!
-    params_max[0][0].data.F32[3] = 1e4;  // this should be set by image dimensions!
-    params_max[0][0].data.F32[4] = 2.0;
-    params_max[0][0].data.F32[5] = 2.0;
-    params_max[0][0].data.F32[6] = +3.0;
-    params_max[0][0].data.F32[7] = 5.0;
-    params_max[0][0].data.F32[8] = 0.5;
-
-    return (TRUE);
-}
-
-bool PM_MODEL_GUESS  (pmModel *model, pmSource *source)
-{
-
-    pmMoments *sMoments = source->moments;
-    pmPeak    *peak     = source->peak;
-    psF32     *params   = model->params->data.F32;
-
-    psEllipseAxes axes;
-    psEllipseShape shape;
-    psEllipseMoments moments;
-
-    moments.x2 = PS_SQR(sMoments->Sx);
-    moments.y2 = PS_SQR(sMoments->Sy);
-    moments.xy = sMoments->Sxy;
-
-    // solve the math to go from Moments To Shape
-    axes = psEllipseMomentsToAxes(moments);
-    shape = psEllipseAxesToShape(axes);
-
-    params[0] = sMoments->Sky;
-    params[1] = sMoments->Peak - sMoments->Sky;
-    params[2] = peak->x;
-    params[3] = peak->y;
-    params[4] = 1.0 / shape.sx;
-    params[5] = 1.0 / shape.sy;
-    params[6] = shape.sxy;
-
-    # if (0)
-
-        f1 = psImageEllipseContour (axes, peak->x, peak->y, source->pixels);
-    axes.major *= 2.0;
-    axes.minor *= 2.0;
-    f2 = psImageEllipseContour (axes, peak->x, peak->y, source->pixels);
-
-    if (f1 > f2) {
-        params[7] = PS_MIN (3.0, PS_MAX (0.5, log(2.0*(f1/f2) - 1.0) / log(2.0)));
-    } else {
-        params[7] = 0.5;
-    }
-    # endif
-
-    params[7] = 1.8;
-    params[8] = 0.1;
-
-
-    return(true);
-}
-
-psF64 PM_MODEL_FLUX (const psVector *params)
-{
-    float f, norm, z;
-
-    psF32 *PAR = params->data.F32;
-
-    psF64 A1   = PS_SQR(PAR[4]);
-    psF64 A2   = PS_SQR(PAR[5]);
-    psF64 A3   = PS_SQR(PAR[6]);
-    psF64 Area = 2.0 * M_PI / sqrt(A1*A2 - A3);
-    // Area is equivalent to 2 pi sigma^2
-
-    // the area needs to be multiplied by the integral of f(z)
-    norm = 0.0;
-    for (z = 0.005; z < 50; z += 0.01) {
-        psF32 pr = PAR[8]*z;
-        f = 1.0 / (1 + pow(z, PAR[7]) + PS_SQR(PS_SQR(pr)));
-        norm += f;
-    }
-    norm *= 0.01;
-
-    psF64 Flux = PAR[1] * Area * norm;
-
-    return(Flux);
-}
-
-// XXX need to define the radius along the major axis
-// define this function so it never returns Inf or NaN
-// return the radius which yields the requested flux
-psF64 PM_MODEL_RADIUS   (const psVector *params, psF64 flux)
-{
-    psF64 r, z = 0.0, pr, f;
-    psF32 *PAR = params->data.F32;
-
-    psEllipseAxes axes;
-    psEllipseShape shape;
-
-    if (flux <= 0)
-        return (1.0);
-    if (PAR[1] <= 0)
-        return (1.0);
-    if (flux >= PAR[1])
-        return (1.0);
-
-    // convert Sx,Sy,Sxy to major/minor axes
-    shape.sx = 1.0 / PAR[4];
-    shape.sy = 1.0 / PAR[5];
-    shape.sxy = PAR[6];
-
-    axes = psEllipseShapeToAxes (shape);
-    psF64 dr = 1.0 / axes.major;
-    psF64 limit = flux / PAR[1];
-
-    // XXX : we can do this faster with an intelligent starting choice
-    for (r = 0.0; r < 20.0; r += dr) {
-        z = PS_SQR(r);
-        pr = PAR[8]*z;
-        f = 1.0 / (1 + pow(z, PAR[7]) + PS_SQR(PS_SQR(pr)));
-        if (f < limit)
-            break;
-    }
-    psF64 radius = 2.0 * axes.major * sqrt (z);
-    if (isnan(radius)) {
-        fprintf (stderr, "error in code\n");
-    }
-    return (radius);
-}
-
-bool PM_MODEL_FROM_PSF  (pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf)
-{
-
-    psF32 *out = modelPSF->params->data.F32;
-    psF32 *in  = modelFLT->params->data.F32;
-
-    out[0] = in[0];
-    out[1] = in[1];
-    out[2] = in[2];
-    out[3] = in[3];
-
-    for (int i = 4; i < 9; i++) {
-        psPolynomial2D *poly = psf->params->data[i-4];
-        // XXX: Verify this (from EAM change)
-        //out[i] = Polynomial2DEval_EAM(poly, out[2], out[3]);
-        out[i] = psPolynomial2DEval(poly, out[2], out[3]);
-    }
-    return(true);
-}
-
-bool PM_MODEL_FIT_STATUS  (pmModel *model)
-{
-
-    psF32 dP;
-    bool  status;
-    psEllipseAxes axes;
-    psEllipseShape shape;
-
-    psF32 *PAR  = model->params->data.F32;
-    psF32 *dPAR = model->dparams->data.F32;
-
-    shape.sx = 1.0 / PAR[4];
-    shape.sy = 1.0 / PAR[5];
-    shape.sxy = PAR[6];
-
-    axes = psEllipseShapeToAxes (shape);
-
-    dP = 0;
-    dP += PS_SQR(dPAR[4] / PAR[4]);
-    dP += PS_SQR(dPAR[5] / PAR[5]);
-    dP += PS_SQR(dPAR[7] / PAR[7]);
-    dP = sqrt (dP);
-
-    status = true;
-    status &= (dP < 0.5);
-    status &= (PAR[1] > 0);
-    status &= ((dPAR[1]/PAR[1]) < 0.5);
-    status &= (fabs(PAR[8]) < 0.5);
-    status &= (dPAR[8] < 0.1);
-    status &= (axes.major > 1.41);
-    status &= (axes.minor > 1.41);
-    status &= ((axes.major / axes.minor) < 5.0);
-    status &= (PAR[7] > 0.5);
-
-    if (status)
-        return true;
-    return false;
-}
-
-// measure the flux for the elliptical contour
-psF64 psImageEllipseContour (psEllipseAxes axes, double xc, double yc, psImage *image)
-{
-
-    double t, dt, ct, st, xo, yo, value;
-    int N, Nt, x, y;
-
-    // choose dt to uniformly divide contour, with ~1 pix spacing at most
-    dt = asin (1 / axes.minor);
-    Nt = (int)(2*M_PI / dt) + 1;
-    dt = 2*M_PI / Nt;
-
-    ct = cos(axes.theta);
-    st = sin(axes.theta);
-    xo = xc - image->col0;
-    yo = yc - image->row0;
-
-    psVector *contour = psVectorAlloc (Nt, PS_TYPE_F32);
-    contour->n = contour->nalloc;
-    for (t = 0, N = 0; (t < 2*M_PI) && (N < Nt); t += dt) {
-        x = ct*axes.major*cos(t) + st*axes.minor*sin(t) + xo;
-        y = ct*axes.minor*sin(t) + st*axes.major*cos(t) + yo;
-        value = p_psImageGetElementF64(image, x, y);
-        if (isfinite(value)) {
-            contour->data.F32[N] = value;
-            N++;
-        }
-    }
-    contour->n = N;
-    // accept every pixel: double counting is not so problematic here...
-
-    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
-    if (!psVectorStats (stats, contour, NULL, NULL, 0)) {
-	psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-	return false;
-    }
-    value = stats->sampleMedian;
-
-    psFree (stats);
-    psFree (contour);
-
-    return (value);
-}
-
-// XXX EAM : test version using flux contours to guess slope
-bool PM_MODEL_GUESS_HARD (pmModel *model, pmSource *source)
-{
-
-    pmMoments *sMoments = source->moments;
-    pmPeak    *peak     = source->peak;
-    psF32     *params   = model->params->data.F32;
-    float f1, f2;
-
-    psEllipseAxes axes;
-    psEllipseShape shape;
-    psEllipseMoments moments;
-
-    moments.x2 = PS_SQR(sMoments->Sx);
-    moments.y2 = PS_SQR(sMoments->Sy);
-    moments.xy = sMoments->Sxy;
-
-    // solve the math to go from Moments To Shape
-    axes = psEllipseMomentsToAxes(moments);
-    shape = psEllipseAxesToShape(axes);
-
-    params[0] = sMoments->Sky;
-    params[1] = sMoments->Peak - sMoments->Sky;
-    params[2] = peak->x;
-    params[3] = peak->y;
-    params[4] = 1.0 / shape.sx;
-    params[5] = 1.0 / shape.sy;
-    params[6] = shape.sxy;
-
-    f1 = psImageEllipseContour (axes, peak->x, peak->y, source->pixels);
-    axes.major *= 2.0;
-    axes.minor *= 2.0;
-    f2 = psImageEllipseContour (axes, peak->x, peak->y, source->pixels);
-
-    if (f1 > f2) {
-        params[7] = PS_MIN (3.0, PS_MAX (0.5, log(2.0*(f1/f2) - 1.0) / log(2.0)));
-    } else {
-        params[7] = 0.5;
-    }
-    params[8] = 0.1;
-
-    return(true);
-}
-
-# undef PM_MODEL_FUNC
-# undef PM_MODEL_FLUX
-# undef PM_MODEL_GUESS
-# undef PM_MODEL_LIMITS
-# undef PM_MODEL_RADIUS
-# undef PM_MODEL_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_TGAUSS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_TGAUSS.c	(revision 25206)
+++ 	(revision )
@@ -1,202 +1,0 @@
-/******************************************************************************
- * this file defines the TGAUSS source shape model (XXX need a better name!).  Note that these
- * model functions are loaded by pmModelGroup.c using 'include', and thus need no 'include'
- * statements of their own.  The models use a psVector to represent the set of parameters, with
- * the sequence used to specify the meaning of the parameter.  The meaning of the parameters
- * may thus vary depending on the specifics of the model.  All models which are used a PSF
- * representations share a few parameters, for which # define names are listed in pmModel.h:
-
-   power-law with fixed slope and fitted amplitude
-   1 / (1 + z + kz^2.2)
-
-   * PM_PAR_SKY 0   - local sky : note that this is unused and may be dropped in the future
-   * PM_PAR_I0 1    - central intensity
-   * PM_PAR_XPOS 2  - X center of object
-   * PM_PAR_YPOS 3  - Y center of object
-   * PM_PAR_SXX 4   - X^2 term of elliptical contour (sqrt(2) / SigmaX)
-   * PM_PAR_SYY 5   - Y^2 term of elliptical contour (sqrt(2) / SigmaY)
-   * PM_PAR_SXY 6   - X*Y term of elliptical contour
-   * PM_PAR_7   7   - amplitude of high-order component (k)
-   *****************************************************************************/
-
-/***
-    XXXX the model in this file needs to be tested more carefully.
-    fix up the code to follow conventions in the other model function files.
-***/
-
-XXX broken code
-
-# define PM_MODEL_FUNC       pmModelFunc_TGAUSS
-# define PM_MODEL_FLUX       pmModelFlux_TGAUSS
-# define PM_MODEL_GUESS      pmModelGuess_TGAUSS
-# define PM_MODEL_LIMITS     pmModelLimits_TGAUSS
-# define PM_MODEL_RADIUS     pmModelRadius_TGAUSS
-# define PM_MODEL_FROM_PSF   pmModelFromPSF_TGAUSS
-# define PM_MODEL_FIT_STATUS pmModelFitStatus_TGAUSS
-
-psF64 PS_MODEL_FUNC (psVector *deriv,
-                     const psVector *params,
-                     const psVector *x)
-{
-    psF32 *PAR = params->data.F32;
-
-    psF32 X  = x->data.F32[0] - PAR[2];
-    psF32 Y  = x->data.F32[1] - PAR[3];
-    psF32 px = PAR[4]*X;
-    psF32 py = PAR[5]*Y;
-    psF32 z  = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + PAR[6]*X*Y;
-
-    psF32 p  = pow(z, 1.2);
-    psF32 r  = 1.0 / (1 + z + PAR[7]*z*p);
-    psF32 f  = PAR[1]*r + PAR[0];
-
-    if (deriv != NULL) {
-        // note difference from a pure gaussian: q = params->data.F32[1]*r
-        psF32 t = PAR[1]*r*r;
-        psF32 q = t*(1 + PAR[7]*2.2*p);
-
-        deriv->data.F32[0] = +1.0;
-        deriv->data.F32[1] = +r;
-        deriv->data.F32[2] = q*(2.0*px*PAR[4] + PAR[6]*Y);
-        deriv->data.F32[3] = q*(2.0*py*PAR[5] + PAR[6]*X);
-        deriv->data.F32[4] = -2.0*q*px*X;
-        deriv->data.F32[5] = -2.0*q*py*Y;
-        deriv->data.F32[6] = -q*X*Y;
-        deriv->data.F32[7] = -t*z*p;
-    }
-    return(f);
-}
-
-bool PM_MODEL_LIMITS  (psVector **beta_lim, psVector **params_min, psVector **params_max)
-{
-
-    *beta_lim   = psVectorAlloc (8, PS_TYPE_F32);
-    *params_min = psVectorAlloc (8, PS_TYPE_F32);
-    *params_max = psVectorAlloc (8, PS_TYPE_F32);
-
-    beta_lim[0][0].data.F32[PM_PAR_SKY] = 1000;
-    beta_lim[0][0].data.F32[PM_PAR_I0] = 3e6;
-    beta_lim[0][0].data.F32[PM_PAR_XPOS] = 5;
-    beta_lim[0][0].data.F32[PM_PAR_YPOS] = 5;
-    beta_lim[0][0].data.F32[PM_PAR_SXX] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_SYY] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_SXY] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_7] = 0.5;
-
-    params_min[0][0].data.F32[PM_PAR_SKY] = -1000;
-    params_min[0][0].data.F32[PM_PAR_I0] = 0;
-    params_min[0][0].data.F32[PM_PAR_XPOS] = -100;
-    params_min[0][0].data.F32[PM_PAR_YPOS] = -100;
-    params_min[0][0].data.F32[PM_PAR_SXX] = 0.5;
-    params_min[0][0].data.F32[PM_PAR_SYY] = 0.5;
-    params_min[0][0].data.F32[PM_PAR_SXY] = -5.0;
-    params_min[0][0].data.F32[PM_PAR_7] = 0.1;
-
-    params_max[0][0].data.F32[PM_PAR_SKY] = 1e5;
-    params_max[0][0].data.F32[PM_PAR_I0] = 1e8;
-    params_max[0][0].data.F32[PM_PAR_XPOS] = 1e4;  // this should be set by image dimensions!
-    params_max[0][0].data.F32[PM_PAR_YPOS] = 1e4;  // this should be set by image dimensions!
-    params_max[0][0].data.F32[PM_PAR_SXX] = 100.0;
-    params_max[0][0].data.F32[PM_PAR_SYY] = 100.0;
-    params_max[0][0].data.F32[PM_PAR_SXY] = +5.0;
-    params_max[0][0].data.F32[PM_PAR_7] = 10.0;
-
-    return (TRUE);
-}
-
-bool PS_MODEL_GUESS  (psModel *model, psSource *source)
-{
-
-    psVector *params = model->params;
-
-    params->data.F32[0] = source->moments->Sky;
-    params->data.F32[1] = source->peak->counts - source->moments->Sky;
-    params->data.F32[2] = source->moments->x;
-    params->data.F32[3] = source->moments->y;
-    params->data.F32[4] = 1.0/source->moments->Sx;
-    params->data.F32[5] = 1.0/source->moments->Sy;
-    // params->data.F32[6] = source->moments->Sxy;
-    params->data.F32[6] = 0.0;
-    params->data.F32[7] = 5.0;
-    return(true);
-}
-
-psF64 PS_MODEL_FLUX (const psVector *params)
-{
-    psF64 A1   = 1 / PS_SQR(params->data.F32[4]);
-    psF64 A2   = 1 / PS_SQR(params->data.F32[5]);
-    psF64 A3   = params->data.F32[6];
-    psF64 Area = 2.0 * M_PI / sqrt(A1*A2 - PS_SQR(A3));
-    // Area is equivalent to 2 pi sigma^2
-
-    psF64 Flux = params->data.F32[1] * Area;
-
-    return(Flux);
-}
-
-// define this function so it never returns Inf or NaN
-// return the radius which yields the requested flux
-psF64 PS_MODEL_RADIUS   (const psVector *params, psF64 flux)
-{
-    if (flux <= 0)
-        return (1.0);
-    if (params->data.F32[1] <= 0)
-        return (1.0);
-    if (flux >= params->data.F32[1])
-        return (1.0);
-
-    psF64 sigma  = sqrt(2.0) * hypot (1.0 / params->data.F32[4], 1.0 / params->data.F32[5]);
-    psF64 radius = sigma * sqrt (2.0 * log(params->data.F32[1] / flux));
-    if (isnan(radius)) {
-        fprintf (stderr, "error in code\n");
-    }
-    return (radius);
-}
-
-bool PS_MODEL_FROM_PSF  (psModel *modelPSF, psModel *modelFLT, const pmPSF *psf)
-{
-
-    psF32 *out = modelPSF->params->data.F32;
-    psF32 *in  = modelFLT->params->data.F32;
-
-    out[0] = in[0];
-    out[1] = in[1];
-    out[2] = in[2];
-    out[3] = in[3];
-
-    for (int i = 4; i < 8; i++) {
-        psPolynomial2D *poly = psf->params->data[i-4];
-        out[i] = Polynomial2DEval (poly, out[2], out[3]);
-    }
-    return(true);
-}
-
-bool PM_MODEL_FIT_STATUS (pmModel *model)
-{
-
-    psF32 dP;
-    bool  status;
-
-    psF32 *PAR  = model->params->data.F32;
-    psF32 *dPAR = model->dparams->data.F32;
-
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
-    status = true;
-    status &= (dP < 0.5);
-    status &= (PAR[PM_PAR_I0] > 0);
-    status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
-
-    return status;
-}
-
-# undef PM_MODEL_FUNC
-# undef PM_MODEL_FLUX
-# undef PM_MODEL_GUESS
-# undef PM_MODEL_LIMITS
-# undef PM_MODEL_RADIUS
-# undef PM_MODEL_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_WAUSS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_WAUSS.c	(revision 25206)
+++ 	(revision )
@@ -1,198 +1,0 @@
-/******************************************************************************
- * this file defines the WAUSS source shape model (XXX need a better name!).  Note that these
- * model functions are loaded by pmModelGroup.c using 'include', and thus need no 'include'
- * statements of their own.  The models use a psVector to represent the set of parameters, with
- * the sequence used to specify the meaning of the parameter.  The meaning of the parameters
- * may thus vary depending on the specifics of the model.  All models which are used a PSF
- * representations share a few parameters, for which # define names are listed in pmModel.h:
-
-   power-law with fitted linear term
-   1 / (1 + Az + Bz^2 + z^3/6)
-
-   * PM_PAR_SKY 0   - local sky : note that this is unused and may be dropped in the future
-   * PM_PAR_I0 1    - central intensity
-   * PM_PAR_XPOS 2  - X center of object
-   * PM_PAR_YPOS 3  - Y center of object
-   * PM_PAR_SXX 4   - X^2 term of elliptical contour (SigmaX / sqrt(2))
-   * PM_PAR_SYY 5   - Y^2 term of elliptical contour (SigmaY / sqrt(2))
-   * PM_PAR_SXY 6   - X*Y term of elliptical contour
-   * PM_PAR_7   7   - amplitude of the linear component (A)
-   * PM_PAR_8   8   - amplitude of the quadratic component (B)
-   *****************************************************************************/
-
-/***
-    XXXX the model in this file needs to be tested more carefully.
-    fix up the code to follow conventions in the other model function files.
-***/
-
-XXX broken code
-
-# define PM_MODEL_FUNC       pmModelFunc_WAUSS
-# define PM_MODEL_FLUX       pmModelFlux_WAUSS
-# define PM_MODEL_GUESS      pmModelGuess_WAUSS
-# define PM_MODEL_LIMITS     pmModelLimits_WAUSS
-# define PM_MODEL_RADIUS     pmModelRadius_WAUSS
-# define PM_MODEL_FROM_PSF   pmModelFromPSF_WAUSS
-# define PM_MODEL_FIT_STATUS pmModelFitStatus_WAUSS
-
-psF64 PS_MODEL_FUNC (psVector *deriv,
-                     const psVector *params,
-                     const psVector *x)
-{
-    psF32 X = x->data.F32[0] - params->data.F32[2];
-    psF32 Y = x->data.F32[1] - params->data.F32[2];
-    psF32 px = params->data.F32[4]*X;
-    psF32 py = params->data.F32[5]*Y;
-    psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
-    psF32 t = 0.5*z*z*(1.0 + params->data.F32[8]*z/3.0);
-    psF32 r = 1.0 / (1.0 + z + params->data.F32[7]*t); /* exp (-Z) */
-    psF32 f = params->data.F32[1]*r + params->data.F32[0];
-
-    if (deriv != NULL) {
-        // note difference from gaussian: q = params->data.F32[1]*r
-        psF32 q = params->data.F32[1]*r*r*(1.0 + params->data.F32[7]*z*(1.0 + params->data.F32[8]*z/2.0));
-        deriv->data.F32[0] = +1.0;
-        deriv->data.F32[1] = +r;
-        deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y);
-        deriv->data.F32[3] = q*(2.0*py*params->data.F32[5] + params->data.F32[6]*X);
-        deriv->data.F32[4] = -2.0*q*px*X;
-        deriv->data.F32[5] = -2.0*q*py*Y;
-        deriv->data.F32[6] = -q*X*Y;
-        deriv->data.F32[7] = -100.0*params->data.F32[1]*r*r*t;
-        deriv->data.F32[8] = -100.0*params->data.F32[1]*r*r*params->data.F32[7]*(z*z*z)/6.0;
-        // The values of 100 dampen the swing of params->data.F32[7,8] */
-    }
-    return(f);
-}
-
-bool PM_MODEL_LIMITS  (psVector **beta_lim, psVector **params_min, psVector **params_max)
-{
-
-    *beta_lim   = psVectorAlloc (8, PS_TYPE_F32);
-    *params_min = psVectorAlloc (8, PS_TYPE_F32);
-    *params_max = psVectorAlloc (8, PS_TYPE_F32);
-
-    beta_lim[0][0].data.F32[PM_PAR_SKY] = 1000;
-    beta_lim[0][0].data.F32[PM_PAR_I0] = 3e6;
-    beta_lim[0][0].data.F32[PM_PAR_XPOS] = 5;
-    beta_lim[0][0].data.F32[PM_PAR_YPOS] = 5;
-    beta_lim[0][0].data.F32[PM_PAR_SXX] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_SYY] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_SXY] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_7] = 0.5;
-
-    params_min[0][0].data.F32[PM_PAR_SKY] = -1000;
-    params_min[0][0].data.F32[PM_PAR_I0] = 0;
-    params_min[0][0].data.F32[PM_PAR_XPOS] = -100;
-    params_min[0][0].data.F32[PM_PAR_YPOS] = -100;
-    params_min[0][0].data.F32[PM_PAR_SXX] = 0.5;
-    params_min[0][0].data.F32[PM_PAR_SYY] = 0.5;
-    params_min[0][0].data.F32[PM_PAR_SXY] = -5.0;
-    params_min[0][0].data.F32[PM_PAR_7] = 0.1;
-
-    params_max[0][0].data.F32[PM_PAR_SKY] = 1e5;
-    params_max[0][0].data.F32[PM_PAR_I0] = 1e8;
-    params_max[0][0].data.F32[PM_PAR_XPOS] = 1e4;  // this should be set by image dimensions!
-    params_max[0][0].data.F32[PM_PAR_YPOS] = 1e4;  // this should be set by image dimensions!
-    params_max[0][0].data.F32[PM_PAR_SXX] = 100.0;
-    params_max[0][0].data.F32[PM_PAR_SYY] = 100.0;
-    params_max[0][0].data.F32[PM_PAR_SXY] = +5.0;
-    params_max[0][0].data.F32[PM_PAR_7] = 10.0;
-
-    return (TRUE);
-}
-
-bool PS_MODEL_GUESS  (psModel *model, psSource *source)
-{
-
-    psVector *params = model->params;
-
-    params->data.F32[0] = source->moments->Sky;
-    params->data.F32[1] = source->peak->counts - source->moments->Sky;
-    params->data.F32[2] = source->moments->x;
-    params->data.F32[3] = source->moments->y;
-    params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
-    params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
-    params->data.F32[6] = source->moments->Sxy;
-    // XXX: What are these?
-    // params->data.F32[7] = B2;
-    // params->data.F32[8] = B3;
-    return(true);
-}
-
-// this is probably wrong since it uses the gauss integral 2 pi sigma^2
-psF64 PS_MODEL_FLUX (const psVector *params)
-{
-    psF64 A1   = 1 / PS_SQR(params->data.F32[4]);
-    psF64 A2   = 1 / PS_SQR(params->data.F32[5]);
-    psF64 A3   = params->data.F32[6];
-    psF64 Area = 2.0 * M_PI / sqrt(A1*A2 - PS_SQR(A3));
-    // Area is equivalent to 2 pi sigma^2
-
-    psF64 Flux = params->data.F32[1] * Area;
-
-    return(Flux);
-}
-
-// return the radius which yields the requested flux
-psF64 PS_MODEL_RADIUS   (const psVector *params, psF64 flux)
-{
-    if (flux <= 0)
-        return (1.0);
-    if (params->data.F32[1] <= 0)
-        return (1.0);
-    if (flux >= params->data.F32[1] <= 0)
-        return (1.0);
-
-    psF64 sigma  = sqrt(2.0) * hypot (1.0 / params->data.F32[4], 1.0 / params->data.F32[5]);
-    psF64 radius = sigma * sqrt (2.0 * log(params->data.F32[1] / flux));
-    return (radius);
-}
-
-bool PS_MODEL_FROM_PSF  (psModel *modelPSF, psModel *modelFLT, const pmPSF *psf)
-{
-
-    psF32 *out = modelPSF->params->data.F32;
-    psF32 *in  = modelFLT->params->data.F32;
-
-    out[0] = in[0];
-    out[1] = in[1];
-    out[2] = in[2];
-    out[3] = in[3];
-
-    for (int i = 4; i < 9; i++) {
-        psPolynomial2D *poly = psf->params->data[i-4];
-        out[i] = Polynomial2DEval (poly, out[2], out[3]);
-    }
-    return(true);
-}
-
-bool PM_MODEL_FIT_STATUS (pmModel *model)
-{
-
-    psF32 dP;
-    bool  status;
-
-    psF32 *PAR  = model->params->data.F32;
-    psF32 *dPAR = model->dparams->data.F32;
-
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
-    status = true;
-    status &= (dP < 0.5);
-    status &= (PAR[PM_PAR_I0] > 0);
-    status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
-
-    return status;
-}
-
-# undef PM_MODEL_FUNC
-# undef PM_MODEL_FLUX
-# undef PM_MODEL_GUESS
-# undef PM_MODEL_LIMITS
-# undef PM_MODEL_RADIUS
-# undef PM_MODEL_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
Index: branches/eam_branches/20090820/psModules/src/objects/models/pmModel_ZGAUSS.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/models/pmModel_ZGAUSS.c	(revision 25206)
+++ 	(revision )
@@ -1,251 +1,0 @@
-/******************************************************************************
- * this file defines the ZGAUSS source shape model (XXX need a better name!).  Note that these
- * model functions are loaded by pmModelGroup.c using 'include', and thus need no 'include'
- * statements of their own.  The models use a psVector to represent the set of parameters, with
- * the sequence used to specify the meaning of the parameter.  The meaning of the parameters
- * may thus vary depending on the specifics of the model.  All models which are used a PSF
- * representations share a few parameters, for which # define names are listed in pmModel.h:
-
-   power-law with fitted slope and tidal cutoff
-   1 / (1 + z^N + (Az)^4)
-
-   * PM_PAR_SKY 0   - local sky : note that this is unused and may be dropped in the future
-   * PM_PAR_I0 1    - central intensity
-   * PM_PAR_XPOS 2  - X center of object
-   * PM_PAR_YPOS 3  - Y center of object
-   * PM_PAR_SXX 4   - X^2 term of elliptical contour (sqrt(2) / SigmaX)
-   * PM_PAR_SYY 5   - Y^2 term of elliptical contour (sqrt(2) / SigmaY)
-   * PM_PAR_SXY 6   - X*Y term of elliptical contour
-   * PM_PAR_7   7   - slope of power-law component (N)
-   *****************************************************************************/
-
-/***
-    XXXX the model in this file needs to be tested more carefully.
-    fix up the code to follow conventions in the other model function files.
-***/
-
-XXX broken code
-
-# define PM_MODEL_FUNC       pmModelFunc_ZGAUSS
-# define PM_MODEL_FLUX       pmModelFlux_ZGAUSS
-# define PM_MODEL_GUESS      pmModelGuess_ZGAUSS
-# define PM_MODEL_LIMITS     pmModelLimits_ZGAUSS
-# define PM_MODEL_RADIUS     pmModelRadius_ZGAUSS
-# define PM_MODEL_FROM_PSF   pmModelFromPSF_ZGAUSS
-# define PM_MODEL_FIT_STATUS pmModelFitStatus_ZGAUSS
-
-# define PAR8 0.1
-
-psF64 PS_MODEL_FUNC (psVector *deriv,
-                     const psVector *params,
-                     const psVector *x)
-{
-    psF32 *PAR = params->data.F32;
-
-    psF32 X  = x->data.F32[0] - PAR[2];
-    psF32 Y  = x->data.F32[1] - PAR[3];
-    psF32 px = PAR[4]*X;
-    psF32 py = PAR[5]*Y;
-    psF32 z  = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + PAR[6]*X*Y;
-
-    psF32 pr = PAR8*z;
-    psF32 p  = pow(z, PAR[7] - 1.0);
-    psF32 r  = 1.0 / (1 + z*p + SQ(SQ(pr)));
-    psF32 f  = PAR[1]*r + PAR[0];
-
-    if (deriv != NULL) {
-        // note difference from a pure gaussian: q = params->data.F32[1]*r
-        psF32 t = PAR[1]*r*r;
-        psF32 q = t*(PAR[7]*p + 4*PAR8*pr*pr*pr);
-
-        deriv->data.F32[0] = +1.0;
-        deriv->data.F32[1] = +r;
-        deriv->data.F32[2] = q*(2.0*px*PAR[4] + PAR[6]*Y);
-        deriv->data.F32[3] = q*(2.0*py*PAR[5] + PAR[6]*X);
-        deriv->data.F32[4] = -q*px*X;
-        deriv->data.F32[5] = -q*py*Y;
-        deriv->data.F32[6] = -q*X*Y;
-        deriv->data.F32[7] = -t*log(z)*z*p;
-    }
-    return(f);
-}
-
-bool PM_MODEL_LIMITS  (psVector **beta_lim, psVector **params_min, psVector **params_max)
-{
-
-    *beta_lim   = psVectorAlloc (8, PS_TYPE_F32);
-    *params_min = psVectorAlloc (8, PS_TYPE_F32);
-    *params_max = psVectorAlloc (8, PS_TYPE_F32);
-
-    beta_lim[0][0].data.F32[PM_PAR_SKY] = 1000;
-    beta_lim[0][0].data.F32[PM_PAR_I0] = 3e6;
-    beta_lim[0][0].data.F32[PM_PAR_XPOS] = 5;
-    beta_lim[0][0].data.F32[PM_PAR_YPOS] = 5;
-    beta_lim[0][0].data.F32[PM_PAR_SXX] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_SYY] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_SXY] = 0.5;
-    beta_lim[0][0].data.F32[PM_PAR_7] = 0.5;
-
-    params_min[0][0].data.F32[PM_PAR_SKY] = -1000;
-    params_min[0][0].data.F32[PM_PAR_I0] = 0;
-    params_min[0][0].data.F32[PM_PAR_XPOS] = -100;
-    params_min[0][0].data.F32[PM_PAR_YPOS] = -100;
-    params_min[0][0].data.F32[PM_PAR_SXX] = 0.5;
-    params_min[0][0].data.F32[PM_PAR_SYY] = 0.5;
-    params_min[0][0].data.F32[PM_PAR_SXY] = -5.0;
-    params_min[0][0].data.F32[PM_PAR_7] = 0.1;
-
-    params_max[0][0].data.F32[PM_PAR_SKY] = 1e5;
-    params_max[0][0].data.F32[PM_PAR_I0] = 1e8;
-    params_max[0][0].data.F32[PM_PAR_XPOS] = 1e4;  // this should be set by image dimensions!
-    params_max[0][0].data.F32[PM_PAR_YPOS] = 1e4;  // this should be set by image dimensions!
-    params_max[0][0].data.F32[PM_PAR_SXX] = 100.0;
-    params_max[0][0].data.F32[PM_PAR_SYY] = 100.0;
-    params_max[0][0].data.F32[PM_PAR_SXY] = +5.0;
-    params_max[0][0].data.F32[PM_PAR_7] = 10.0;
-
-    return (TRUE);
-}
-
-bool PS_MODEL_GUESS  (psModel *model, psSource *source)
-{
-
-    psVector *params = model->params;
-
-    psEllipseAxes axes;
-    psEllipseShape shape;
-    psEllipseMoments moments;
-
-    moments.x2 = PS_SQR(source->moments->Sx);
-    moments.y2 = PS_SQR(source->moments->Sy);
-    moments.xy = source->moments->Sxy;
-
-    axes = psEllipseMomentsToAxes(moments);
-    shape = psEllipseAxesToShape(axes);
-
-    params->data.F32[0] = source->moments->Sky;
-    params->data.F32[1] = source->peak->counts - source->moments->Sky;
-    params->data.F32[2] = source->moments->x;
-    params->data.F32[3] = source->moments->y;
-    params->data.F32[4] = 1.0 / shape.sx;
-    params->data.F32[5] = 1.0 / shape.sy;
-    params->data.F32[6] = shape.sxy;
-    params->data.F32[7] = 1.9;
-    return(true);
-}
-
-psF64 PS_MODEL_FLUX (const psVector *params)
-{
-    float f, norm, z;
-
-    psF32 *PAR = params->data.F32;
-
-    psF64 A1   = PS_SQR(PAR[4]);
-    psF64 A2   = PS_SQR(PAR[5]);
-    psF64 A3   = PS_SQR(PAR[6]);
-    psF64 Area = 2.0 * M_PI / sqrt(A1*A2 - A3);
-    // Area is equivalent to 2 pi sigma^2
-
-    // the area needs to be multiplied by the integral of f(z)
-    norm = 0.0;
-    psF32 pr = PAR8*z;
-    for (z = 0.005; z < 50; z += 0.01) {
-        f = 1.0 / (1 + pow(z, PAR[7]) + SQ(SQ(pr)));
-        norm += f;
-    }
-    norm *= 0.01;
-
-    psF64 Flux = PAR[1] * Area * norm;
-
-    return(Flux);
-}
-
-// XXX need to define the radius along the major axis
-// define this function so it never returns Inf or NaN
-// return the radius which yields the requested flux
-psF64 PS_MODEL_RADIUS   (const psVector *params, psF64 flux)
-{
-    psF64 r, z, pr, f;
-    psF32 *PAR = params->data.F32;
-
-    psEllipseAxes axes;
-    psEllipseShape shape;
-
-    if (flux <= 0)
-        return (1.0);
-    if (PAR[1] <= 0)
-        return (1.0);
-    if (flux >= PAR[1])
-        return (1.0);
-
-    // convert Sx,Sy,Sxy to major/minor axes
-    shape.sx = 1.0 / PAR[4];
-    shape.sy = 1.0 / PAR[5];
-    shape.sxy = PAR[6];
-
-    axes = psEllipseShapeToAxes (shape);
-    psF64 dr = 1.0 / axes.major;
-    psF64 limit = flux / PAR[1];
-
-    // XXX : we can do this faster with an intelligent starting choice
-    for (r = 0.0; r < 20.0; r += dr) {
-        z = SQ(r);
-        pr = PAR8*z;
-        f = 1.0 / (1 + pow(z, PAR[7]) + SQ(SQ(pr)));
-        if (f < limit)
-            break;
-    }
-    psF64 radius = 2.0 * axes.major * sqrt (z);
-    if (isnan(radius)) {
-        fprintf (stderr, "error in code\n");
-    }
-    return (radius);
-}
-
-bool PS_MODEL_FROM_PSF  (psModel *modelPSF, psModel *modelFLT, const pmPSF *psf)
-{
-
-    psF32 *out = modelPSF->params->data.F32;
-    psF32 *in  = modelFLT->params->data.F32;
-
-    out[0] = in[0];
-    out[1] = in[1];
-    out[2] = in[2];
-    out[3] = in[3];
-
-    for (int i = 4; i < 8; i++) {
-        psPolynomial2D *poly = psf->params->data[i-4];
-        out[i] = Polynomial2DEval (poly, out[2], out[3]);
-    }
-    return(true);
-}
-
-bool PM_MODEL_FIT_STATUS (pmModel *model)
-{
-
-    psF32 dP;
-    bool  status;
-
-    psF32 *PAR  = model->params->data.F32;
-    psF32 *dPAR = model->dparams->data.F32;
-
-    dP = 0;
-    dP += PS_SQR(dPAR[PM_PAR_SXX] / PAR[PM_PAR_SXX]);
-    dP += PS_SQR(dPAR[PM_PAR_SYY] / PAR[PM_PAR_SYY]);
-    dP = sqrt (dP);
-
-    status = true;
-    status &= (dP < 0.5);
-    status &= (PAR[PM_PAR_I0] > 0);
-    status &= ((dPAR[PM_PAR_I0]/PAR[PM_PAR_I0]) < 0.5);
-
-    return status;
-}
-
-# undef PM_MODEL_FUNC
-# undef PM_MODEL_FLUX
-# undef PM_MODEL_GUESS
-# undef PM_MODEL_LIMITS
-# undef PM_MODEL_RADIUS
-# undef PM_MODEL_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
Index: branches/eam_branches/20090820/psModules/src/objects/pmDetEff.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmDetEff.c	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmDetEff.c	(revision 25766)
@@ -0,0 +1,169 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pslib.h>
+
+#include "pmDetEff.h"
+
+
+static void detEffFree(pmDetEff *de)
+{
+    psFree(de->magOffsets);
+    psFree(de->counts);
+    psFree(de->magDiffMean);
+    psFree(de->magDiffStdev);
+    psFree(de->magErrMean);
+}
+
+
+pmDetEff *pmDetEffAlloc(float magRef, int numSources, int numBins)
+{
+    pmDetEff *de = psAlloc(sizeof(pmDetEff)); // Detection efficiency, to return
+    psMemSetDeallocator(de, (psFreeFunc)detEffFree);
+
+    de->magRef = magRef;
+    de->numSources = numSources;
+    de->numBins = numBins;
+
+    de->magOffsets = NULL;
+    de->counts = NULL;
+    de->magDiffMean = NULL;
+    de->magDiffStdev = NULL;
+    de->magErrMean = NULL;
+
+    return de;
+}
+
+
+bool pmDetEffWrite(psFits *fits, pmDetEff *de, const psMetadata *header, const char *extname)
+{
+    PS_ASSERT_FITS_NON_NULL(fits, false);
+    PS_ASSERT_FITS_WRITABLE(fits, false);
+    PM_ASSERT_DETEFF_RESULTS(de, false);
+
+    psArray *table = psArrayAlloc(de->numBins); // Table to write
+    for (int i = 0; i < de->numBins; i++) {
+        psMetadata *row = psMetadataAlloc(); // Table row
+        psMetadataAddF32(row, PS_LIST_TAIL, "OFFSET", 0, "Magnitude offset from reference",
+                         de->magOffsets->data.F32[i]);
+        psMetadataAddS32(row, PS_LIST_TAIL, "COUNTS", 0, "Number of sources recovered",
+                         de->counts->data.S32[i]);
+        psMetadataAddF32(row, PS_LIST_TAIL, "DIFF.MEAN", 0, "Mean magnitude difference",
+                         de->magDiffMean->data.F32[i]);
+        psMetadataAddF32(row, PS_LIST_TAIL, "DIFF.STDEV", 0, "Stdev magnitude difference",
+                         de->magDiffStdev->data.F32[i]);
+        psMetadataAddF32(row, PS_LIST_TAIL, "ERR.MEAN", 0, "Mean magnitude error",
+                         de->magErrMean->data.F32[i]);
+        table->data[i] = row;
+    }
+
+    psMetadata *deHeader = psMetadataCopy(NULL, header); // Header for detection efficiency
+    psMetadataAddF32(deHeader, PS_LIST_TAIL, "DETEFF.MAGREF", PS_META_REPLACE, "Magnitude reference",
+                     de->magRef);
+    psMetadataAddS32(deHeader, PS_LIST_TAIL, "DETEFF.NUM", PS_META_REPLACE, "Number of fake sources injected",
+                     de->numSources);
+
+    if (!psFitsWriteTable(fits, deHeader, table, extname)) {
+        psError(PS_ERR_IO, false, "Unable to write detection efficiency table.");
+        psFree(table);
+        psFree(deHeader);
+        return false;
+    }
+
+    psFree(table);
+    psFree(deHeader);
+
+    return true;
+}
+
+bool pmReadoutWriteDetEff(psFits *fits, const pmReadout *readout,
+                          const psMetadata *header, const char *extname)
+{
+    PM_ASSERT_READOUT_NON_NULL(readout, false);
+
+    bool mdok;                          // Status of MD lookup
+    pmDetEff *de = psMetadataLookupPtr(&mdok, readout->analysis, PM_DETEFF_ANALYSIS); // Detection efficiency
+    if (!mdok || !de) {
+        // Wrote everything there was to write
+        return true;
+    }
+    return pmDetEffWrite(fits, de, header, extname);
+}
+
+
+pmDetEff *pmDetEffRead(psFits *fits, const char *extname)
+{
+    PS_ASSERT_FITS_NON_NULL(fits, false);
+    PS_ASSERT_STRING_NON_EMPTY(extname, false);
+
+    if (!psFitsMoveExtNameClean(fits, extname)) {
+        // Nothing to read
+        return NULL;
+    }
+
+    psMetadata *header = psFitsReadHeader(NULL, fits); // Header for table
+    if (!header) {
+        psError(PS_ERR_IO, false, "Unable to read FITS header");
+        return NULL;
+    }
+
+    int numBins = psFitsTableSize(fits);// Size of table
+    bool mdok;                          // Status of MD lookup
+    int numSources = psMetadataLookupS32(&mdok, header, "DETEFF.NUM"); // Number of fake sources injected
+    if (!mdok) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to find number of sources");
+        psFree(header);
+        return NULL;
+    }
+    float magRef = psMetadataLookupF32(&mdok, header, "DETEFF.MAGREF"); // Magnitude reference
+    if (!mdok) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to find magnitude reference");
+        psFree(header);
+        return NULL;
+    }
+    psFree(header);
+
+    pmDetEff *de = pmDetEffAlloc(magRef, numSources, numBins); // Detection efficiency
+    de->magOffsets = psVectorAlloc(numBins, PS_TYPE_F32);
+    de->counts = psVectorAlloc(numBins, PS_TYPE_S32);
+    de->magDiffMean = psVectorAlloc(numBins, PS_TYPE_F32);
+    de->magDiffStdev = psVectorAlloc(numBins, PS_TYPE_F32);
+    de->magErrMean = psVectorAlloc(numBins, PS_TYPE_F32);
+
+    psArray *table = psFitsReadTable(fits); // FITS table
+    if (!table) {
+        psError(PS_ERR_IO, false, "Unable to read detection efficiency table.");
+        psFree(de);
+        return false;
+    }
+
+    for (int i = 0; i < numBins; i++) {
+        psMetadata *row = table->data[i]; // Table row
+        de->magOffsets->data.F32[i] = psMetadataLookupF32(NULL, row, "OFFSET");
+        de->counts->data.S32[i] = psMetadataLookupS32(NULL, row, "COUNTS");
+        de->magDiffMean->data.F32[i] = psMetadataLookupF32(NULL, row, "DIFF.MEAN");
+        de->magDiffStdev->data.F32[i] = psMetadataLookupF32(NULL, row, "DIFF.STDEV");
+        de->magErrMean->data.F32[i] = psMetadataLookupF32(NULL, row, "ERR.MEAN");
+    }
+
+    psFree(table);
+    return de;
+}
+
+bool pmReadoutReadDetEff(psFits *fits, const pmReadout *readout, const char *extname)
+{
+    PM_ASSERT_READOUT_NON_NULL(readout, false);
+
+    pmDetEff *de = pmDetEffRead(fits, extname);
+    if (!de) {
+        if (psErrorCodeLast() != PS_ERR_NONE) {
+            return false;
+        }
+        return true;
+    }
+
+    bool status = psMetadataAddPtr(readout->analysis, PS_LIST_TAIL, PM_DETEFF_ANALYSIS, PS_META_REPLACE | PS_DATA_UNKNOWN, "Detection efficiency", de);
+    psFree (de);
+    return status;
+}
Index: branches/eam_branches/20090820/psModules/src/objects/pmDetEff.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmDetEff.h	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmDetEff.h	(revision 25766)
@@ -0,0 +1,81 @@
+#ifndef PM_DET_EFF_H
+#define PM_DET_EFF_H
+
+#include <pslib.h>
+#include <string.h>
+
+#include "pmFPA.h"
+
+#define PM_DETEFF_ANALYSIS "DETEFF"     // Location of detection efficiency on pmReadout.analysis
+
+// Detection efficiency characterisation
+typedef struct {
+    float magRef;                       // Reference magnitude
+    int numSources;                     // Number of sources
+    int numBins;                        // Number of bins
+    psVector *magOffsets;               // Magnitude offsets for each bin
+    psVector *counts;                   // Counts of sources recovered for each bin
+    psVector *magDiffMean;              // Mean magnitude difference for each bin
+    psVector *magDiffStdev;             // Stdev of magnitude difference for each bin
+    psVector *magErrMean;               // Mean magnitude error for each bin
+} pmDetEff;
+
+
+/// Allocator
+pmDetEff *pmDetEffAlloc(float magRef,   // Reference magnitude
+                        int numSources, // Number of sources
+                        int numBins     // Number of bins
+                        );
+
+/// Write detection efficiency to FITS file
+bool pmDetEffWrite(psFits *fits,        // FITS file to which to write
+                   pmDetEff *deteff,    // Detection efficiency to write
+                   const psMetadata *header, // Header to write
+                   const char *extname  // Extension name
+                   );
+
+/// Write detection efficiency from a readout to a FITS file
+bool pmReadoutWriteDetEff(psFits *fits,// FITS file to which to write
+                          const pmReadout *readout, // Readout with detection efficiency
+                          const psMetadata *header, // Header to write
+                          const char *extname // Extension name
+    );
+
+/// Read detection efficiency
+pmDetEff *pmDetEffRead(psFits *fits,    // FITS file from which to read
+                       const char *extname // Extension name
+                       );
+
+/// Read detection efficiency into a readout
+bool pmReadoutReadDetEff(psFits *fits,// FITS file to which to write
+                         const pmReadout *readout, // Readout with detection efficiency
+                         const char *extname // Extension name
+    );
+
+#define PM_ASSERT_DETEFF_NON_NULL(DE, RETURN) { \
+    if (!(DE)) { \
+        psError(PS_ERR_UNEXPECTED_NULL, true, "Detection efficiency %s is NULL", #DE); \
+        return RETURN; \
+    } \
+}
+
+#define PM_ASSERT_DETEFF_RESULTS(DE, RETURN) { \
+    PM_ASSERT_DETEFF_NON_NULL(DE, RETURN); \
+    PS_ASSERT_VECTOR_NON_NULL((DE)->magOffsets, RETURN); \
+    PS_ASSERT_VECTOR_SIZE((DE)->magOffsets, (long)(DE)->numBins, RETURN); \
+    PS_ASSERT_VECTOR_TYPE((DE)->magOffsets, PS_TYPE_F32, RETURN); \
+    PS_ASSERT_VECTOR_NON_NULL((DE)->counts, RETURN); \
+    PS_ASSERT_VECTOR_SIZE((DE)->counts, (long)(DE)->numBins, RETURN); \
+    PS_ASSERT_VECTOR_TYPE((DE)->counts, PS_TYPE_S32, RETURN); \
+    PS_ASSERT_VECTOR_NON_NULL((DE)->magDiffMean, RETURN); \
+    PS_ASSERT_VECTOR_SIZE((DE)->magDiffMean, (long)(DE)->numBins, RETURN); \
+    PS_ASSERT_VECTOR_TYPE((DE)->magDiffMean, PS_TYPE_F32, RETURN); \
+    PS_ASSERT_VECTOR_NON_NULL((DE)->magDiffStdev, RETURN); \
+    PS_ASSERT_VECTOR_SIZE((DE)->magDiffStdev, (long)(DE)->numBins, RETURN); \
+    PS_ASSERT_VECTOR_TYPE((DE)->magDiffStdev, PS_TYPE_F32, RETURN); \
+    PS_ASSERT_VECTOR_NON_NULL((DE)->magErrMean, RETURN); \
+    PS_ASSERT_VECTOR_SIZE((DE)->magErrMean, (long)(DE)->numBins, RETURN); \
+    PS_ASSERT_VECTOR_TYPE((DE)->magErrMean, PS_TYPE_F32, RETURN); \
+}
+
+#endif
Index: branches/eam_branches/20090820/psModules/src/objects/pmGrowthCurveGenerate.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmGrowthCurveGenerate.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmGrowthCurveGenerate.c	(revision 25766)
@@ -65,4 +65,5 @@
 
 	    // use the center of the center pixel of the image
+	    // 0.5 PIX: is this offset needed? probably -- the psf model uses 0.5,0.5 as the center, double check
 	    float xc = (int)(ix*readout->image->numCols + 0.5*readout->image->numCols) + readout->image->col0 + 0.5;
 	    float yc = (int)(iy*readout->image->numRows + 0.5*readout->image->numRows) + readout->image->row0 + 0.5;
@@ -195,5 +196,5 @@
 	    return NULL;
         }
-        psImageKeepCircle (mask, xc, yc, radius, "AND", PS_NOT_IMAGE_MASK(markVal));
+	psImageMaskPixels (mask, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
 
         // the 'ignore' mode is for testing
Index: branches/eam_branches/20090820/psModules/src/objects/pmModel.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmModel.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmModel.c	(revision 25766)
@@ -56,10 +56,11 @@
 
     tmp->type = type;
-    tmp->chisq = 0.0;
-    tmp->chisqNorm = 0.0;
+    tmp->mag = NAN;
+    tmp->chisq = NAN;
+    tmp->chisqNorm = NAN;
     tmp->nDOF  = 0;
     tmp->nPix  = 0;
     tmp->nIter = 0;
-    tmp->radiusFit = 0;
+    tmp->fitRadius = 0;
     tmp->flags = PM_MODEL_STATUS_NONE;
     tmp->residuals = NULL;              // XXX should the model own this memory?
@@ -86,4 +87,5 @@
     tmp->modelParamsFromPSF = class->modelParamsFromPSF;
     tmp->modelFitStatus     = class->modelFitStatus;
+    tmp->modelSetLimits     = class->modelSetLimits;
 
     psTrace("psModules.objects", 10, "---- %s() end ----\n", __func__);
@@ -108,5 +110,5 @@
     new->nIter     = model->nIter;
     new->flags     = model->flags;
-    new->radiusFit = model->radiusFit;
+    new->fitRadius = model->fitRadius;
 
     for (int i = 0; i < new->params->n; i++) {
@@ -189,7 +191,7 @@
     psVector *params = model->params;
 
-    psS32 imageCol;
-    psS32 imageRow;
-    psF32 pixelValue;
+    float imageCol;
+    float imageRow;
+    float pixelValue;
 
     // save original values; restore before returning
@@ -232,5 +234,5 @@
     psF32 **Rx = NULL;
     psF32 **Ry = NULL;
-    psImageMaskType **Rm = NULL;
+    pmResidMaskType **Rm = NULL;
 
     if (model->residuals) {
@@ -240,5 +242,5 @@
 	Rx = (model->residuals->Rx)   ? model->residuals->Rx->data.F32 : NULL;
 	Ry = (model->residuals->Ry)   ? model->residuals->Ry->data.F32 : NULL;
-	Rm = (model->residuals->mask) ? model->residuals->mask->data.PS_TYPE_IMAGE_MASK_DATA : NULL;
+	Rm = (model->residuals->mask) ? model->residuals->mask->data.PM_TYPE_RESID_MASK_DATA : NULL;
 	if (Ro) {
 	    NX = model->residuals->Ro->numCols;
@@ -255,11 +257,11 @@
                 continue;
 
-            // XXX should we use using 0.5 pixel offset?
-	    // Convert to coordinate in parent image, with offset (dx,dy)
-            imageCol = ix + image->col0 - dx;
-            imageRow = iy + image->row0 - dy;
-
-            x->data.F32[0] = (float) imageCol;
-            x->data.F32[1] = (float) imageRow;
+            // Convert to coordinate in parent image, with offset (dx,dy)
+	    // 0.5 PIX: the model take pixel coordinates so convert the pixel index here
+            imageCol = ix + 0.5 + image->col0 - dx;
+            imageRow = iy + 0.5 + image->row0 - dy;
+
+            x->data.F32[0] = imageCol;
+            x->data.F32[1] = imageRow;
 
             pixelValue = 0.0;
@@ -276,56 +278,56 @@
                 float rx = xBin*ix + DX;
 
-		int rx0 = rx - 0.5;
-		int rx1 = rx + 0.5;
-		int ry0 = ry - 0.5;
-		int ry1 = ry + 0.5;
-
-		if (rx0 < 0) goto skip;
-		if (ry0 < 0) goto skip;
-		if (rx1 >= NX) goto skip;
-		if (ry1 >= NY) goto skip;
-
-		// these go from 0.0 to 1.0 between the centers of the pixels 
-		float fx = rx - 0.5 - rx0;
-		float Fx = 1.0 - fx;
-		float fy = ry - 0.5 - ry0;
-		float Fy = 1.0 - fy;
-
-		// check the residual image mask (if set). give up if any of the 4 pixels are masked.
-		if (Rm) {
-		    if (Rm[ry0][rx0]) goto skip;
-		    if (Rm[ry0][rx1]) goto skip;
-		    if (Rm[ry1][rx0]) goto skip;
-		    if (Rm[ry1][rx1]) goto skip;
-		}
-
-		// a possible further optimization if we re-use these values
-		// XXX allow for masked pixels, and add pixel weights
-		float V0 = (Ro[ry0][rx0]*Fx + Ro[ry0][rx1]*fx);
-		float V1 = (Ro[ry1][rx0]*Fx + Ro[ry1][rx1]*fx);
-		float Vo = V0*Fy + V1*fy;
-		if (!isfinite(Vo)) goto skip;
-
-		float Vx = 0.0;
-		float Vy = 0.0;
-
-		// skip Rx,Ry if Ro is masked
-		if (Rx && Ry && (mode & PM_MODEL_OP_RES1)) {
-		    V0 = (Rx[ry0][rx0]*Fx + Rx[ry0][rx1]*fx);
-		    V1 = (Rx[ry1][rx0]*Fx + Rx[ry1][rx1]*fx);
-		    Vx = V0*Fy + V1*fy;
-
-		    V0 = (Ry[ry0][rx0]*Fx + Ry[ry0][rx1]*fx);
-		    V1 = (Ry[ry1][rx0]*Fx + Ry[ry1][rx1]*fx);
-		    Vy = V0*Fy + V1*fy;
-		}
-		if (!isfinite(Vx)) goto skip;
-		if (!isfinite(Vy)) goto skip;
-
-		// 2D residual variations are set for the true source position
-		pixelValue += Io*(Vo + XoSave*Vx + XoSave*Vy);
+                int rx0 = rx - 0.5;
+                int rx1 = rx + 0.5;
+                int ry0 = ry - 0.5;
+                int ry1 = ry + 0.5;
+
+                if (rx0 < 0) goto skip;
+                if (ry0 < 0) goto skip;
+                if (rx1 >= NX) goto skip;
+                if (ry1 >= NY) goto skip;
+
+                // these go from 0.0 to 1.0 between the centers of the pixels
+                float fx = rx - 0.5 - rx0;
+                float Fx = 1.0 - fx;
+                float fy = ry - 0.5 - ry0;
+                float Fy = 1.0 - fy;
+
+                // check the residual image mask (if set). give up if any of the 4 pixels are masked.
+                if (Rm) {
+                    if (Rm[ry0][rx0]) goto skip;
+                    if (Rm[ry0][rx1]) goto skip;
+                    if (Rm[ry1][rx0]) goto skip;
+                    if (Rm[ry1][rx1]) goto skip;
+                }
+
+                // a possible further optimization if we re-use these values
+                // XXX allow for masked pixels, and add pixel weights
+                float V0 = (Ro[ry0][rx0]*Fx + Ro[ry0][rx1]*fx);
+                float V1 = (Ro[ry1][rx0]*Fx + Ro[ry1][rx1]*fx);
+                float Vo = V0*Fy + V1*fy;
+                if (!isfinite(Vo)) goto skip;
+
+                float Vx = 0.0;
+                float Vy = 0.0;
+
+                // skip Rx,Ry if Ro is masked
+                if (Rx && Ry && (mode & PM_MODEL_OP_RES1)) {
+                    V0 = (Rx[ry0][rx0]*Fx + Rx[ry0][rx1]*fx);
+                    V1 = (Rx[ry1][rx0]*Fx + Rx[ry1][rx1]*fx);
+                    Vx = V0*Fy + V1*fy;
+
+                    V0 = (Ry[ry0][rx0]*Fx + Ry[ry0][rx1]*fx);
+                    V1 = (Ry[ry1][rx0]*Fx + Ry[ry1][rx1]*fx);
+                    Vy = V0*Fy + V1*fy;
+                }
+                if (!isfinite(Vx)) goto skip;
+                if (!isfinite(Vy)) goto skip;
+
+                // 2D residual variations are set for the true source position
+                pixelValue += Io*(Vo + XoSave*Vx + XoSave*Vy);
             }
 
-	skip:
+        skip:
             // add or subtract the value
             if (add) {
Index: branches/eam_branches/20090820/psModules/src/objects/pmModel.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmModel.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmModel.h	(revision 25766)
@@ -44,4 +44,12 @@
 } pmModelOpMode;
 
+/// Parameter limit types
+typedef enum {
+    PM_MODEL_LIMITS_NONE,               ///< Apply no limits: suitable for debugging
+    PM_MODEL_LIMITS_IGNORE,             ///< Ignore all limits: fit can go to town
+    PM_MODEL_LIMITS_LAX,                ///< Lax limits: attempting to reproduce mildly bad data
+    PM_MODEL_LIMITS_STRICT,             ///< Strict limits: good quality data
+} pmModelLimitsType;
+
 typedef struct pmModel pmModel;
 typedef struct pmSource pmSource;
@@ -74,4 +82,7 @@
 //  This function returns the success / failure status of the given model fit
 typedef bool (*pmModelFitStatusFunc)(pmModel *model);
+
+//  This function sets the parameter limits for the given model
+typedef bool (*pmModelSetLimitsFunc)(pmModelLimitsType type);
 
 /** pmModel data structure
@@ -96,5 +107,5 @@
     int nIter;                          ///< number of iterations to reach min
     pmModelStatus flags;                ///< model status flags
-    float radiusFit;                    ///< fit radius actually used
+    float fitRadius;                    ///< fit radius actually used
     pmResiduals *residuals;             ///< normalized PSF residuals
 
@@ -108,4 +119,5 @@
     pmModelParamsFromPSF modelParamsFromPSF;
     pmModelFitStatusFunc modelFitStatus;
+    pmModelSetLimitsFunc modelSetLimits;
 };
 
@@ -151,5 +163,5 @@
     pmModel *model,                     ///< The input pmModel
     pmModelOpMode mode,                 ///< mode to control how the model is added into the image
-    psImageMaskType maskVal		///< Value to mask
+    psImageMaskType maskVal             ///< Value to mask
 );
 
@@ -169,5 +181,5 @@
     pmModel *model,                     ///< The input pmModel
     pmModelOpMode mode,                 ///< mode to control how the model is added into the image
-    psImageMaskType maskVal		///< Value to mask
+    psImageMaskType maskVal             ///< Value to mask
 );
 
@@ -202,4 +214,14 @@
 );
 
+
+/// Set the model parameter limits for the given model
+///
+/// Wraps the model-specific pmModelSetLimitsFunc function.
+bool pmModelSetLimits(
+    const pmModel *model,               ///< Model of interest
+    pmModelLimits type                  ///< Type of limits
+    );
+
+
 /// @}
 # endif /* PM_MODEL_H */
Index: branches/eam_branches/20090820/psModules/src/objects/pmModelClass.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmModelClass.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmModelClass.c	(revision 25766)
@@ -36,22 +36,22 @@
 #include "pmErrorCodes.h"
 
-// XXX shouldn't these be defined for us in pslib.h ???
+// XXX shouldn't these be defined for us in math.h ???
 double hypot(double x, double y);
 double sqrt (double x);
 
-# include "models/pmModel_GAUSS.c"
-# include "models/pmModel_PGAUSS.c"
-# include "models/pmModel_QGAUSS.c"
-# include "models/pmModel_PS1_V1.c"
-# include "models/pmModel_RGAUSS.c"
-# include "models/pmModel_SERSIC.c"
+# include "models/pmModel_GAUSS.h"
+# include "models/pmModel_PGAUSS.h"
+# include "models/pmModel_QGAUSS.h"
+# include "models/pmModel_PS1_V1.h"
+# include "models/pmModel_RGAUSS.h"
+# include "models/pmModel_SERSIC.h"
 
 static pmModelClass defaultModels[] = {
-    {"PS_MODEL_GAUSS",        7, pmModelFunc_GAUSS,   pmModelFlux_GAUSS,   pmModelRadius_GAUSS,   pmModelLimits_GAUSS,   pmModelGuess_GAUSS,  pmModelFromPSF_GAUSS,  pmModelParamsFromPSF_GAUSS,  pmModelFitStatus_GAUSS},
-    {"PS_MODEL_PGAUSS",       7, pmModelFunc_PGAUSS,  pmModelFlux_PGAUSS,  pmModelRadius_PGAUSS,  pmModelLimits_PGAUSS,  pmModelGuess_PGAUSS, pmModelFromPSF_PGAUSS, pmModelParamsFromPSF_PGAUSS, pmModelFitStatus_PGAUSS},
-    {"PS_MODEL_QGAUSS",       8, pmModelFunc_QGAUSS,  pmModelFlux_QGAUSS,  pmModelRadius_QGAUSS,  pmModelLimits_QGAUSS,  pmModelGuess_QGAUSS, pmModelFromPSF_QGAUSS, pmModelParamsFromPSF_QGAUSS, pmModelFitStatus_QGAUSS},
-    {"PS_MODEL_PS1_V1",       8, pmModelFunc_PS1_V1,  pmModelFlux_PS1_V1,  pmModelRadius_PS1_V1,  pmModelLimits_PS1_V1,  pmModelGuess_PS1_V1, pmModelFromPSF_PS1_V1, pmModelParamsFromPSF_PS1_V1, pmModelFitStatus_PS1_V1},
-    {"PS_MODEL_RGAUSS",       8, pmModelFunc_RGAUSS,  pmModelFlux_RGAUSS,  pmModelRadius_RGAUSS,  pmModelLimits_RGAUSS,  pmModelGuess_RGAUSS, pmModelFromPSF_RGAUSS, pmModelParamsFromPSF_RGAUSS, pmModelFitStatus_RGAUSS},
-    {"PS_MODEL_SERSIC",       8, pmModelFunc_SERSIC,  pmModelFlux_SERSIC,  pmModelRadius_SERSIC,  pmModelLimits_SERSIC,  pmModelGuess_SERSIC, pmModelFromPSF_SERSIC, pmModelParamsFromPSF_SERSIC, pmModelFitStatus_SERSIC}
+    {"PS_MODEL_GAUSS",        7, (pmModelFunc)pmModelFunc_GAUSS,   (pmModelFlux)pmModelFlux_GAUSS,   (pmModelRadius)pmModelRadius_GAUSS,   (pmModelLimits)pmModelLimits_GAUSS,   (pmModelGuessFunc)pmModelGuess_GAUSS,  (pmModelFromPSFFunc)pmModelFromPSF_GAUSS,  (pmModelParamsFromPSF)pmModelParamsFromPSF_GAUSS,  (pmModelFitStatusFunc)pmModelFitStatus_GAUSS,  (pmModelSetLimitsFunc)pmModelSetLimits_GAUSS  },
+    {"PS_MODEL_PGAUSS",       7, (pmModelFunc)pmModelFunc_PGAUSS,  (pmModelFlux)pmModelFlux_PGAUSS,  (pmModelRadius)pmModelRadius_PGAUSS,  (pmModelLimits)pmModelLimits_PGAUSS,  (pmModelGuessFunc)pmModelGuess_PGAUSS, (pmModelFromPSFFunc)pmModelFromPSF_PGAUSS, (pmModelParamsFromPSF)pmModelParamsFromPSF_PGAUSS, (pmModelFitStatusFunc)pmModelFitStatus_PGAUSS, (pmModelSetLimitsFunc)pmModelSetLimits_PGAUSS },
+    {"PS_MODEL_QGAUSS",       8, (pmModelFunc)pmModelFunc_QGAUSS,  (pmModelFlux)pmModelFlux_QGAUSS,  (pmModelRadius)pmModelRadius_QGAUSS,  (pmModelLimits)pmModelLimits_QGAUSS,  (pmModelGuessFunc)pmModelGuess_QGAUSS, (pmModelFromPSFFunc)pmModelFromPSF_QGAUSS, (pmModelParamsFromPSF)pmModelParamsFromPSF_QGAUSS, (pmModelFitStatusFunc)pmModelFitStatus_QGAUSS, (pmModelSetLimitsFunc)pmModelSetLimits_QGAUSS },
+    {"PS_MODEL_PS1_V1",       8, (pmModelFunc)pmModelFunc_PS1_V1,  (pmModelFlux)pmModelFlux_PS1_V1,  (pmModelRadius)pmModelRadius_PS1_V1,  (pmModelLimits)pmModelLimits_PS1_V1,  (pmModelGuessFunc)pmModelGuess_PS1_V1, (pmModelFromPSFFunc)pmModelFromPSF_PS1_V1, (pmModelParamsFromPSF)pmModelParamsFromPSF_PS1_V1, (pmModelFitStatusFunc)pmModelFitStatus_PS1_V1, (pmModelSetLimitsFunc)pmModelSetLimits_PS1_V1 },
+    {"PS_MODEL_RGAUSS",       8, (pmModelFunc)pmModelFunc_RGAUSS,  (pmModelFlux)pmModelFlux_RGAUSS,  (pmModelRadius)pmModelRadius_RGAUSS,  (pmModelLimits)pmModelLimits_RGAUSS,  (pmModelGuessFunc)pmModelGuess_RGAUSS, (pmModelFromPSFFunc)pmModelFromPSF_RGAUSS, (pmModelParamsFromPSF)pmModelParamsFromPSF_RGAUSS, (pmModelFitStatusFunc)pmModelFitStatus_RGAUSS, (pmModelSetLimitsFunc)pmModelSetLimits_RGAUSS },
+    {"PS_MODEL_SERSIC",       8, (pmModelFunc)pmModelFunc_SERSIC,  (pmModelFlux)pmModelFlux_SERSIC,  (pmModelRadius)pmModelRadius_SERSIC,  (pmModelLimits)pmModelLimits_SERSIC,  (pmModelGuessFunc)pmModelGuess_SERSIC, (pmModelFromPSFFunc)pmModelFromPSF_SERSIC, (pmModelParamsFromPSF)pmModelParamsFromPSF_SERSIC, (pmModelFitStatusFunc)pmModelFitStatus_SERSIC, (pmModelSetLimitsFunc)pmModelSetLimits_SERSIC }
 };
 
@@ -168,2 +168,18 @@
     return (models[type].name);
 }
+
+
+void pmModelClassSetLimits(pmModelLimitsType type)
+{
+    if (!models) {
+        pmModelClassInit();
+    }
+
+    for (int i = 0; i < Nmodels; i++) {
+        if (models[i].modelSetLimits) {
+            models[i].modelSetLimits(type);
+        }
+    }
+
+}
+
Index: branches/eam_branches/20090820/psModules/src/objects/pmModelClass.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmModelClass.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmModelClass.h	(revision 25766)
@@ -29,9 +29,10 @@
 # define PM_MODEL_CLASS_H
 
+#include <pmModel.h>
+
 /// @addtogroup Objects Object Detection / Analysis Functions
 /// @{
 
-typedef struct
-{
+typedef struct {
     char *name;
     int nParams;
@@ -44,4 +45,5 @@
     pmModelParamsFromPSF modelParamsFromPSF;
     pmModelFitStatusFunc modelFitStatus;
+    pmModelSetLimitsFunc modelSetLimits;
 } pmModelClass;
 
@@ -73,4 +75,8 @@
 pmModelType pmModelClassGetType (const char *name);
 
+/// Set parameter limits for all models
+void pmModelClassSetLimits(pmModelLimitsType type);
+
+
 /// @}
 # endif /* PM_MODEL_CLASS_H */
Index: branches/eam_branches/20090820/psModules/src/objects/pmModelGroup.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmModelGroup.c	(revision 25206)
+++ 	(revision )
@@ -1,204 +1,0 @@
-/** @file  pmModelGroup.c
- *
- *  Functions to define and manipulate object model attributes
- *
- *  @author GLG, MHPCC
- *  @author EAM, IfA
- *
- *  @version $Revision: 1.20 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-12-08 02:51:14 $
- *
- *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <pslib.h>
-#include "pmHDU.h"
-#include "pmFPA.h"
-#include "pmSpan.h"
-#include "pmFootprint.h"
-#include "pmPeaks.h"
-#include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmModel.h"
-#include "pmModelGroup.h"
-#include "pmErrorCodes.h"
-
-// XXX shouldn't these be defined for us in pslib.h ???
-double hypot(double x, double y);
-double sqrt (double x);
-
-# include "models/pmModel_GAUSS.c"
-# include "models/pmModel_PGAUSS.c"
-# include "models/pmModel_QGAUSS.c"
-# include "models/pmModel_RGAUSS.c"
-# include "models/pmModel_SERSIC.c"
-
-static pmModelGroup defaultModels[] = {
-                                          {"PS_MODEL_GAUSS",        7, pmModelFunc_GAUSS,   pmModelFlux_GAUSS,   pmModelRadius_GAUSS,   pmModelLimits_GAUSS,   pmModelGuess_GAUSS,  pmModelFromPSF_GAUSS,  pmModelFitStatus_GAUSS},
-                                          {"PS_MODEL_PGAUSS",       7, pmModelFunc_PGAUSS,  pmModelFlux_PGAUSS,  pmModelRadius_PGAUSS,  pmModelLimits_PGAUSS,  pmModelGuess_PGAUSS, pmModelFromPSF_PGAUSS, pmModelFitStatus_PGAUSS},
-                                          {"PS_MODEL_QGAUSS",       8, pmModelFunc_QGAUSS,  pmModelFlux_QGAUSS,  pmModelRadius_QGAUSS,  pmModelLimits_QGAUSS,  pmModelGuess_QGAUSS, pmModelFromPSF_QGAUSS, pmModelFitStatus_QGAUSS},
-                                          {"PS_MODEL_RGAUSS",       8, pmModelFunc_RGAUSS,  pmModelFlux_RGAUSS,  pmModelRadius_RGAUSS,  pmModelLimits_RGAUSS,  pmModelGuess_RGAUSS, pmModelFromPSF_RGAUSS, pmModelFitStatus_RGAUSS},
-                                          {"PS_MODEL_SERSIC",       8, pmModelFunc_SERSIC,  pmModelFlux_SERSIC,  pmModelRadius_SERSIC,  pmModelLimits_SERSIC,  pmModelGuess_SERSIC, pmModelFromPSF_SERSIC, pmModelFitStatus_SERSIC}
-                                      };
-
-static pmModelGroup *models = NULL;
-static int Nmodels = 0;
-
-static void ModelGroupFree (pmModelGroup *modelGroup)
-{
-
-    if (modelGroup == NULL)
-        return;
-    return;
-}
-
-pmModelGroup *pmModelGroupAlloc (int nModels)
-{
-
-    pmModelGroup *modelGroup = (pmModelGroup *) psAlloc (nModels * sizeof(pmModelGroup));
-    psMemSetDeallocator(modelGroup, (psFreeFunc) ModelGroupFree);
-    return (modelGroup);
-}
-
-bool psMemCheckModelGroup(psPtr ptr)
-{
-    PS_ASSERT_PTR(ptr, false);
-    return ( psMemGetDeallocator(ptr) == (psFreeFunc) ModelGroupFree);
-}
-
-void pmModelGroupAdd (pmModelGroup *model)
-{
-
-    if (models == NULL) {
-        pmModelGroupInit ();
-    }
-
-    Nmodels ++;
-    models = (pmModelGroup *) psRealloc (models, Nmodels*sizeof(pmModelGroup));
-    models[Nmodels-1] = model[0];
-    return;
-}
-
-bool pmModelGroupInit (void)
-{
-
-    // if we do not need to init, return false;
-    if (models != NULL)
-        return false;
-
-    int Nnew = sizeof (defaultModels) / sizeof (pmModelGroup);
-
-    models = pmModelGroupAlloc (Nnew);
-    for (int i = 0; i < Nnew; i++) {
-        models[i] = defaultModels[i];
-    }
-    Nmodels = Nnew;
-    return true;
-}
-
-void pmModelGroupCleanup (void)
-{
-    psFree (models);
-    models = NULL;
-    return;
-}
-
-pmModelFunc pmModelFunc_GetFunction (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (NULL);
-    }
-    return (models[type].modelFunc);
-}
-
-pmModelFlux pmModelFlux_GetFunction (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (NULL);
-    }
-    return (models[type].modelFlux);
-}
-
-pmModelRadius pmModelRadius_GetFunction (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (NULL);
-    }
-    return (models[type].modelRadius);
-}
-
-pmModelLimits pmModelLimits_GetFunction (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (NULL);
-    }
-    return (models[type].modelLimits);
-}
-
-pmModelGuessFunc pmModelGuessFunc_GetFunction (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (NULL);
-    }
-    return (models[type].modelGuessFunc);
-}
-
-pmModelFitStatusFunc pmModelFitStatusFunc_GetFunction (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (NULL);
-    }
-    return (models[type].modelFitStatusFunc);
-}
-
-pmModelFromPSFFunc pmModelFromPSFFunc_GetFunction (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (NULL);
-    }
-    return (models[type].modelFromPSFFunc);
-}
-
-psS32 pmModelParameterCount (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (0);
-    }
-    return (models[type].nParams);
-}
-
-psS32 pmModelSetType (char *name)
-{
-    for (int i = 0; i < Nmodels; i++) {
-        if (!strcmp(models[i].name, name)) {
-            return (i);
-        }
-    }
-    return (-1);
-}
-
-char *pmModelGetType (pmModelType type)
-{
-    if ((type < 0) || (type >= Nmodels)) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined pmModelType");
-        return (NULL);
-    }
-    return (models[type].name);
-}
Index: branches/eam_branches/20090820/psModules/src/objects/pmModelGroup.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmModelGroup.h	(revision 25206)
+++ 	(revision )
@@ -1,201 +1,0 @@
-/* @file  pmModelGroup.h
- *
- * The object model function types are desined to allow for the flexible addition of new object
- * models. Every object model, with parameters represented by pmModel, has an associated set of
- * functions which provide necessary support operations. A set of abstract functions allow the
- * programmer to select the approriate function or property for a specific named object model.
- *
- * Every model instance belongs to a class of models, defined by the value of
- * the pmModelType type entry. Various functions need access to information about
- * each of the models. Some of this information varies from model to model, and
- * may depend on the current parameter values or other data quantities. In order
- * to keep the code from requiring the information about each model to be coded
- * into the low-level fitting routines, we define a collection of functions which
- * allow us to abstract this type of model-dependent information. These generic
- * functions take the model type and return the corresponding function pointer
- * for the specified model. Each model is defined by creating this collection of
- * specific functions, and placing them in a single file for each model. We
- * define the following structure to carry the collection of information about
- * the models.
- *
- * @author EAM, IfA
- *
- * @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-11-10 01:09:20 $
- * Copyright 2004 Maui High Performance Computing Center, University of Hawaii
- */
-
-# ifndef PM_MODEL_GROUP_H
-# define PM_MODEL_GROUP_H
-
-/// @addtogroup Objects Object Detection / Analysis Functions
-/// @{
-
-//  This function is the model chi-square minimization function for this model.
-typedef psMinimizeLMChi2Func pmModelFunc;
-
-//  This function sets the parameter limits for this model.
-typedef psMinimizeLMLimitFunc pmModelLimits;
-
-// This function returns the integrated flux for the given model parameters.
-typedef psF64 (*pmModelFlux)(const psVector *params);
-
-// This function returns the radius at which the given model and parameters
-// achieves the given flux.
-typedef psF64 (*pmModelRadius)(const psVector *params, double flux);
-
-//  This function provides the model guess parameters based on the details of
-//  the given source.
-typedef bool (*pmModelGuessFunc)(pmModel *model, pmSource *source);
-
-//  This function constructs the PSF model for the given source based on the
-//  supplied psf and the EXT model for the object.
-typedef bool (*pmModelFromPSFFunc)(pmModel *modelPSF, pmModel *modelEXT, pmPSF *psf);
-
-//  This function sets the model parameters based on the PSF for a given coordinate and central
-//  intensity
-typedef bool (*pmModelParamsFromPSF)(pmModel *model, pmPSF *psf, float Xo, float Yo, float Io);
-
-//  This function returns the success / failure status of the given model fit
-typedef bool (*pmModelFitStatusFunc)(pmModel *model);
-
-typedef struct
-{
-    char *name;
-    int nParams;
-    pmModelFunc          modelFunc;
-    pmModelFlux          modelFlux;
-    pmModelRadius        modelRadius;
-    pmModelLimits        modelLimits;
-    pmModelGuessFunc     modelGuessFunc;
-    pmModelFromPSFFunc   modelFromPSFFunc;
-    pmModelParamsFromPSF modelParamsFromPSF;
-    pmModelFitStatusFunc modelFitStatusFunc;
-}
-pmModelGroup;
-
-// allocate a pmModelGroup to hold nModels entries
-pmModelGroup *pmModelGroupAlloc (int nModels);
-
-bool psMemCheckModelGroup(psPtr ptr);
-
-// initialize the internal (static) model group with the default models
-bool pmModelGroupInit (void);
-
-// free the internal (static) model group
-void pmModelGroupCleanup (void);
-
-// add a new model to the internal (static) model group
-void pmModelGroupAdd (pmModelGroup *model);
-
-/* This function returns the number of parameters used by the listed function.
- */
-int pmModelParameterCount(
-    pmModelType type                    ///< Add comment.
-);
-
-
-/* This function returns the user-space model names for the specified model type.
- */
-char *pmModelGetType(
-    pmModelType type                    ///< Add comment.
-);
-
-
-/**
- * 
- * This function returns the internal model type code for the user-space model names.
- * 
- */
-pmModelType pmModelSetType(
-    char *name                          ///< Add comment.
-);
-
-/**
- * 
- *  Each of the function types above has a corresponding function which returns
- *  the function given the model type:
- * 
- */
-
-/**
- * 
- * pmModelFunc is the function used to determine the value of the model at a
- * specific coordinate, and is the one used by psMinimizeLMChi2.
- * 
- */
-pmModelFunc          pmModelFunc_GetFunction (pmModelType type);
-
-
-/**
- * 
- * pmModelFlux returns the total integrated flux for the given input parameters.
- * 
- */
-pmModelFlux          pmModelFlux_GetFunction (pmModelType type);
-
-
-/**
- * 
- * pmModelRadius returns the scaling radius at which the flux of the model
- * matches the specified flux. This presumes that the model is a function of an
- * elliptical contour.
- * 
- */
-pmModelRadius        pmModelRadius_GetFunction (pmModelType type);
-
-
-/**
- * 
- * pmModelLimits sets the parameter limit vectors for the function.
- * 
- */
-pmModelLimits        pmModelLimits_GetFunction (pmModelType type);
-
-
-/**
- * 
- * pmModelGuessFunc generates an initial guess for the model based on the
- * provided source statistics (moments and pixel values as needed).
- * 
- */
-pmModelGuessFunc     pmModelGuessFunc_GetFunction (pmModelType type);
-
-
-/**
- * 
- * pmModelFromPSFFunc takes as input a representation of the psf and a value
- * for the model and fills in the PSF parameters of the model. The input
- * primarily relies upon the centroid coordinates of the input model, though the
- * normalization may potentially be used.
- * 
- */
-pmModelFromPSFFunc   pmModelFromPSFFunc_GetFunction (pmModelType type);
-
-
-/**
- * 
- * pmModelFitStatusFunc returns a true or false values based on the success or
- * failure of a model fit.  The success is determined by quantities such as the
- * chisq or the signal-to-noise.
- * 
- */
-pmModelFitStatusFunc pmModelFitStatusFunc_GetFunction (pmModelType type);
-
-
-/** pmSourceModelGuess()
- *
- * Convert available data to an initial guess for the given model. This
- * function allocates a pmModel entry for the pmSource structure based on the
- * provided model selection. The method of defining the model parameter guesses
- * are specified for each model below. The guess values are placed in the model
- * parameters. The function returns TRUE on success or FALSE on failure.
- *
- */
-pmModel *pmSourceModelGuess(
-    pmSource *source,   ///< The input pmSource
-    pmModelType model   ///< The type of model to be created.
-);
-
-/// @}
-# endif /* PM_MODEL_GROUP_H */
Index: branches/eam_branches/20090820/psModules/src/objects/pmModelUtils.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmModelUtils.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmModelUtils.c	(revision 25766)
@@ -48,5 +48,5 @@
         return NULL;
     }
-    // XXX note that model->residuals is just a reference
+    // note that model->residuals is just a reference
     modelPSF->residuals = psf->residuals;
 
@@ -65,11 +65,9 @@
     // set model parameters for this source based on PSF information
     if (!modelPSF->modelParamsFromPSF (modelPSF, psf, Xo, Yo, Io)) {
-        // XXX we do not want to raise an error here, just note that we failed
-	// psError(PM_ERR_PSF, false, "Failed to set model params from PSF");
         psFree(modelPSF);
         return NULL;
     }
 
-    // XXX note that model->residuals is just a reference
+    // note that model->residuals is just a reference
     modelPSF->residuals = psf->residuals;
 
Index: branches/eam_branches/20090820/psModules/src/objects/pmPSF.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPSF.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPSF.h	(revision 25766)
@@ -38,6 +38,5 @@
  *
  */
-typedef struct
-{
+typedef struct {
     pmModelType type;                   ///< PSF Model in use
     psArray *params;                    ///< Model parameters (psPolynomial2D)
@@ -65,6 +64,5 @@
     pmGrowthCurve *growth;              ///< apMag vs Radius
     pmResiduals *residuals;             ///< normalized residual image (no spatial variation)
-}
-pmPSF;
+} pmPSF;
 
 typedef struct {
@@ -81,5 +79,6 @@
     bool          poissonErrorsPhotLin; ///< use poission errors for linear model fitting
     bool          poissonErrorsParams; ///< use poission errors for model parameter fitting
-    float         radius;
+    float         fitRadius;
+    float         apRadius;
     bool          chiFluxTrend;         // Fit a trend in Chi2 as a function of flux?
 } pmPSFOptions;
Index: branches/eam_branches/20090820/psModules/src/objects/pmPSFtry.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPSFtry.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPSFtry.c	(revision 25766)
@@ -37,51 +37,4 @@
 #include "pmSourceVisual.h"
 
-bool printTrendMap (pmTrend2D *trend) {
-
-    if (!trend->map) return false;
-    if (!trend->map->map) return false;
-
-    for (int j = 0; j < trend->map->map->numRows; j++) {
-        for (int i = 0; i < trend->map->map->numCols; i++) {
-            fprintf (stderr, "%5.2f  ", trend->map->map->data.F32[j][i]);
-        }
-        fprintf (stderr, "\t\t\t");
-        for (int i = 0; i < trend->map->map->numCols; i++) {
-            fprintf (stderr, "%5.2f  ", trend->map->error->data.F32[j][i]);
-        }
-        fprintf (stderr, "\n");
-    }
-    return true;
-}
-
-bool psImageMapCleanup (psImageMap *map) {
-
-    if ((map->map->numRows == 1) && (map->map->numCols == 1)) return true;
-
-    // find the weighted average of all pixels
-    float Sum = 0.0;
-    float Wt = 0.0;
-    for (int j = 0; j < map->map->numRows; j++) {
-        for (int i = 0; i < map->map->numCols; i++) {
-            if (!isfinite(map->map->data.F32[j][i])) continue;
-            Sum += map->map->data.F32[j][i] * map->error->data.F32[j][i];
-            Wt += map->error->data.F32[j][i];
-        }
-    }
-
-    float Mean = Sum / Wt;
-
-    // do any of the pixels in the map need to be repaired?
-    // XXX for now, we are just replacing bad pixels with the Mean
-    for (int j = 0; j < map->map->numRows; j++) {
-        for (int i = 0; i < map->map->numCols; i++) {
-            if (isfinite(map->map->data.F32[j][i]) &&
-                (map->error->data.F32[j][i] > 0.0)) continue;
-            map->map->data.F32[j][i] = Mean;
-        }
-    }
-    return true;
-}
-
 // ********  pmPSFtry functions  **************************************************
 // * pmPSFtry holds a single pmPSF model test, with the input sources, the freely
@@ -110,5 +63,5 @@
     psMemSetDeallocator(test, (psFreeFunc) pmPSFtryFree);
 
-    test->psf       = pmPSFAlloc (options);
+    test->psf       = NULL; 
     test->metric    = psVectorAlloc (sources->n, PS_TYPE_F32);
     test->metricErr = psVectorAlloc (sources->n, PS_TYPE_F32);
@@ -136,934 +89,98 @@
 }
 
+float psVectorSystematicError (psVector *residuals, psVector *errors, float clipFraction) {
 
-// build a pmPSFtry for the given model:
-// - fit each source with the free-floating model
-// - construct the pmPSF from the collection of models
-// - fit each source with the PSF-parameter models
-// - measure the pmPSF quality metric (dApResid)
+    psAssert(residuals, "residuals cannot be NULL");
+    psAssert(errors, "errors cannot be NULL");
+    psAssert(residuals->n == errors->n, "residuals and errors must be the same length");
 
-// sources used in for pmPSFtry may be masked by the analysis
-// mask values indicate the reason the source was rejected:
+    // given a vector of residuals and their formal errors, calculated the necessary systematic
+    // error needed to yield a reduced chisq of 1.0, after first tossing out the clipFraction
+    // highest chi-square contributors (allowed outliers)
 
-// generate a pmPSFtry with a copy of the test PSF sources
-pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal)
-{
-    bool status;
-    int Next = 0;
-    int Npsf = 0;
+    psVector *mask  = psVectorAlloc(residuals->n, PS_TYPE_VECTOR_MASK);
+    psVector *chisq = psVectorAlloc(residuals->n, PS_TYPE_F32);
 
-    // validate the requested model name
-    options->type = pmModelClassGetType (modelName);
-    if (options->type == -1) {
-        psError (PS_ERR_UNKNOWN, true, "invalid model name %s", modelName);
-        return NULL;
+    // calculate the chisq vector:
+    int Ngood = 0;
+    for (int i = 0; i < residuals->n; i++) {
+	chisq->data.F32[i] = PS_MAX_F32;
+	if (!isfinite(residuals->data.F32[i])) continue;
+	if (!isfinite(errors->data.F32[i])) continue;
+	if (errors->data.F32[i] <= 0.0) continue;
+	chisq->data.F32[i] = PS_SQR(residuals->data.F32[i] / errors->data.F32[i]);
+	Ngood ++;
     }
 
-    pmPSFtry *psfTry = pmPSFtryAlloc (sources, options);
-    if (psfTry == NULL) {
-        psError (PS_ERR_UNKNOWN, false, "failed to allocate psf model");
-        return NULL;
+    psVector *index = psVectorSortIndex(NULL, chisq);
+
+    // toss out the clipFraction highest chisq values
+    for (int i = 0; i < residuals->n; i++) {
+	int n = index->data.S32[i];
+	if (i < (1.0 - clipFraction)*Ngood) {
+	    mask->data.PS_TYPE_VECTOR_MASK_DATA[n] = 0;
+	} else {
+	    mask->data.PS_TYPE_VECTOR_MASK_DATA[n] = 1;
+	}
     }
 
-    // maskVal is used to test for rejected pixels, and must include markVal
-    maskVal |= markVal;
+    // Ndof ~= Ngood
+    // Chisq_Ndof = sum(residuals_i^2 / error_i^2) / Ndof
+    // choose S2 such than Chisq^sys_Ndof = sum(residuals_i^2 / (error_i^2 + S2)) / Ndof = 1.0
+    
+    // use Newton-Raphson to solve for S2:
 
-    // stage 1:  fit an EXT model to all candidates PSF sources -- this is independent of the modeled 2D variations in the PSF
-    psTimerStart ("psf.fit");
-    for (int i = 0; i < psfTry->sources->n; i++) {
+    // use median sigma to calculate the initial guess for S2:
+    psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
+    psVectorStats (stats, errors, NULL, mask, 1);
+    float errorMedian = stats->sampleMedian;
+    
+    float nPts = 0.0;
+    float res2mean = 0.0;
+    float ChiSq = 0.0;
+    for (int i = 0; i < residuals->n; i++) {
+	int n = index->data.S32[i];
+	if (mask->data.PS_TYPE_VECTOR_MASK_DATA[n]) continue;
+	res2mean += PS_SQR(residuals->data.F32[n]);
+	ChiSq += PS_SQR(residuals->data.F32[n]) / PS_SQR(errors->data.F32[n]);
+	nPts += 1.0;
+    }
+    res2mean /= nPts;
+    ChiSq /= nPts;
+    
+    float S2guess = res2mean - PS_SQR(errorMedian);
 
-        pmSource *source = psfTry->sources->data[i];
-        if (!source->moments) {
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            continue;
-        }
-        if (!source->moments->nPixels) {
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            continue;
-        }
+    psLogMsg ("psModules", 10, "ChiSquare: %f, Ntotal: %ld, Ngood: %d, Nkeep: %.0f, S2 guess: %f\n", 
+	      ChiSq, residuals->n, Ngood, nPts, S2guess);
 
-        source->modelEXT = pmSourceModelGuess (source, psfTry->psf->type);
-        if (source->modelEXT == NULL) {
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y);
-            continue;
-        }
+    for (int iter = 0; iter < 10; iter++) {
 
-        // set object mask to define valid pixels
-        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "OR", markVal);
+	ChiSq = 0.0;
+	float dRdS = 0.0;
+	for (int i = 0; i < residuals->n; i++) {
+	    int n = index->data.S32[i];
+	    if (mask->data.PS_TYPE_VECTOR_MASK_DATA[n]) continue;
+	    float error2 = PS_SQR(errors->data.F32[n]) + S2guess;
+	    ChiSq += PS_SQR(residuals->data.F32[n]) / error2;
+	    dRdS += PS_SQR(residuals->data.F32[n]) / PS_SQR(error2);
+	}
+	ChiSq /= nPts;
+	dRdS /= nPts;
 
-        // fit model as EXT, not PSF
-        status = pmSourceFitModel (source, source->modelEXT, PM_SOURCE_FIT_EXT, maskVal);
+	// Note the sign on dS: dRdS above is -1 * dR/dS formally
+	float dS = (ChiSq - 1.0) / dRdS;
+	S2guess += dS;
+	S2guess = PS_MAX(0.0, S2guess);
 
-        // clear object mask to define valid pixels
-        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_IMAGE_MASK(markVal));
-
-        // exclude the poor fits
-        if (!status) {
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y);
-            continue;
-        }
-        Next ++;
-    }
-    psLogMsg ("psphot.psftry", PS_LOG_MINUTIA, "fit ext:   %f sec for %d of %ld sources\n", psTimerMark ("psf.fit"), Next, sources->n);
-    psTrace ("psModules.object", 3, "keeping %d of %ld PSF candidates (EXT)\n", Next, sources->n);
-
-    if (Next == 0) {
-        psError(PS_ERR_UNKNOWN, false, "No sources with good extended fits from which to determine PSF.");
-        psFree(psfTry);
-        return NULL;
+	psLogMsg ("psModules", 10, "ChiSquare: %f, dS: %f, S2 guess: %f\n", ChiSq, dS, S2guess);
     }
 
-    // stage 2: construct a psf (pmPSF) from this collection of model fits, including the 2D variation
-    if (!pmPSFFromPSFtry (psfTry)) {
-        psError(PS_ERR_UNKNOWN, false, "failed to construct a psf model from collection of sources");
-        psFree(psfTry);
-        return NULL;
-    }
+    // free local allocations
+    psFree (mask);
+    psFree (chisq);
+    psFree (stats);
+    psFree (index);
 
-    // stage 3: refit with fixed shape parameters
-    psTimerStart ("psf.fit");
-    for (int i = 0; i < psfTry->sources->n; i++) {
-
-        pmSource *source = psfTry->sources->data[i];
-
-        // masked for: bad model fit, outlier in parameters
-        if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL) {
-            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : source is masked\n", i, source->peak->x, source->peak->y);
-            continue;
-        }
-
-        // set shape for this model based on PSF
-        source->modelPSF = pmModelFromPSF (source->modelEXT, psfTry->psf);
-        if (source->modelPSF == NULL) {
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_BAD_MODEL;
-            abort();
-            continue;
-        }
-        source->modelPSF->radiusFit = options->radius;
-
-        // set object mask to define valid pixels
-        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "OR", markVal);
-
-        // fit the PSF model to the source
-        status = pmSourceFitModel (source, source->modelPSF, PM_SOURCE_FIT_PSF, maskVal);
-
-        // skip poor fits
-        if (!status) {
-            psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_IMAGE_MASK(markVal));
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_PSF_FAIL;
-            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : failed PSF fit\n", i, source->peak->x, source->peak->y);
-            continue;
-        }
-
-        status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal);
-        if (!status || isnan(source->apMag)) {
-            psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_IMAGE_MASK(markVal));
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_BAD_PHOT;
-            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : poor photometry\n", i, source->peak->x, source->peak->y);
-            continue;
-        }
-
-        // clear object mask to define valid pixels
-        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_IMAGE_MASK(markVal));
-
-        psfTry->fitMag->data.F32[i] = source->psfMag;
-        psfTry->metric->data.F32[i] = source->apMag - source->psfMag;
-        psfTry->metricErr->data.F32[i] = source->errMag;
-
-        psTrace ("psModules.object", 6, "keeping source %d (%d) of %ld\n", i, Npsf, psfTry->sources->n);
-        Npsf ++;
-    }
-    psfTry->psf->nPSFstars = Npsf;
-
-    psLogMsg ("psphot.psftry", PS_LOG_MINUTIA, "fit psf:   %f sec for %d of %ld sources\n", psTimerMark ("psf.fit"), Npsf, sources->n);
-    psTrace ("psModules.object", 3, "keeping %d of %ld PSF candidates (PSF)\n", Npsf, sources->n);
-
-    if (Npsf == 0) {
-        psError(PS_ERR_UNKNOWN, false, "No sources with good PSF fits after model is built.");
-        psFree(psfTry);
-        return NULL;
-    }
-
-    // measure the chi-square trend as a function of flux (PAR[PM_PAR_I0])
-    // this should be linear for Poisson errors and quadratic for constant sky errors
-    psVector *flux  = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
-    psVector *chisq = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
-    psVector *mask  = psVectorAlloc (psfTry->sources->n, PS_TYPE_VECTOR_MASK);
-
-    // generate the x and y vectors, and mask missing models
-    for (int i = 0; i < psfTry->sources->n; i++) {
-        pmSource *source = psfTry->sources->data[i];
-        if (source->modelPSF == NULL) {
-            flux->data.F32[i] = 0.0;
-            chisq->data.F32[i] = 0.0;
-            mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff;
-        } else {
-            flux->data.F32[i] = source->modelPSF->params->data.F32[PM_PAR_I0];
-            chisq->data.F32[i] = source->modelPSF->chisq / source->modelPSF->nDOF;
-            mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0;
-        }
-    }
-
-    // use 3hi/3lo sigma clipping on the chisq fit
-    psStats *stats = options->stats;
-
-    // linear clipped fit of chisq trend vs flux
-    if (options->chiFluxTrend) {
-        bool result = psVectorClipFitPolynomial1D(psfTry->psf->ChiTrend, options->stats,
-                                                  mask, 0xff, chisq, NULL, flux);
-        psStatsOptions meanStat = psStatsMeanOption(options->stats->options); // Statistic for mean
-        psStatsOptions stdevStat = psStatsStdevOption(options->stats->options); // Statistic for stdev
-
-        psLogMsg ("pmPSFtry", 4, "chisq vs flux fit: %f +/- %f\n",
-                  psStatsGetValue(stats, meanStat), psStatsGetValue(stats, stdevStat));
-
-        psFree(flux);
-        psFree(mask);
-        psFree(chisq);
-
-        if (!result) {
-            psError(PS_ERR_UNKNOWN, false, "Failed to fit psf->ChiTrend");
-            psFree(psfTry);
-            return NULL;
-        }
-    }
-
-    for (int i = 0; i < psfTry->psf->ChiTrend->nX + 1; i++) {
-        psLogMsg ("pmPSFtry", 4, "chisq vs flux fit term %d: %f +/- %f\n", i,
-                  psfTry->psf->ChiTrend->coeff[i]*pow(10000, i),
-                  psfTry->psf->ChiTrend->coeffErr[i]*pow(10000,i));
-    }
-
-    // XXX this function wants aperture radius for pmSourcePhotometry
-    if (!pmPSFtryMetric (psfTry, options)) {
-        psError(PS_ERR_UNKNOWN, false, "Attempt to fit PSF with model %s failed.", modelName);
-        psFree (psfTry);
-        return NULL;
-    }
-
-    psLogMsg ("psphot.pspsf", 3, "try model %s, ap-fit: %f +/- %f : sky bias: %f\n",
-              modelName, psfTry->psf->ApResid, psfTry->psf->dApResid, psfTry->psf->skyBias);
-
-    return (psfTry);
+    return (sqrt(S2guess));
 }
 
-bool pmPSFtryMetric (pmPSFtry *psfTry, pmPSFOptions *options)
-{
-    PS_ASSERT_PTR_NON_NULL(psfTry, false);
-    PS_ASSERT_PTR_NON_NULL(options, false);
-    PS_ASSERT_PTR_NON_NULL(psfTry->sources, false);
-
-    float RADIUS = options->radius;
-
-    // the measured (aperture - fit) magnitudes (dA == psfTry->metric)
-    //   depend on both the true ap-fit (dAo) and the bias in the sky measurement:
-    //     dA = dAo + dsky/flux
-    //   where flux is the flux of the star
-    // we fit this trend to find the infinite flux aperture correction (dAo),
-    //   the nominal sky bias (dsky), and the error on dAo
-    // the values of dA are contaminated by stars with close neighbors in the aperture
-    //   we use an outlier rejection to avoid this bias
-
-    // r2rflux = radius^2 * ten(0.4*fitMag);
-    psVector *r2rflux = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
-
-    for (int i = 0; i < psfTry->sources->n; i++) {
-        if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL)
-            continue;
-        r2rflux->data.F32[i] = PS_SQR(RADIUS) * pow(10.0, 0.4*psfTry->fitMag->data.F32[i]);
-    }
-
-    // XXX test dump of aperture residual data
-    if (psTraceGetLevel("psModules.objects") >= 5) {
-        FILE *f = fopen ("apresid.dat", "w");
-        for (int i = 0; i < psfTry->sources->n; i++) {
-            int keep = (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL);
-
-            pmSource *source = psfTry->sources->data[i];
-            float x = source->peak->x;
-            float y = source->peak->y;
-
-            fprintf (f, "%d  %d, %f %f %f  %f %f %f \n",
-                     i, keep, x, y,
-                     psfTry->fitMag->data.F32[i],
-                     r2rflux->data.F32[i],
-                     psfTry->metric->data.F32[i],
-                     psfTry->metricErr->data.F32[i]);
-        }
-        fclose (f);
-    }
-
-    // This analysis of the apResid statistics is only approximate.  The fitted magnitudes
-    // measured at this point (in the PSF fit) use Poisson errors, and are thus biased as a
-    // function of magnitude.  We re-measure the apResid statistics later in psphot using the
-    // linear, constant-error fitting.  Do not reject outliers with excessive vigor here.
-
-    // fit ApTrend only to r2rflux, ignore x,y,flux variations for now
-    // linear clipped fit of ApResid to r2rflux
-    psPolynomial1D *poly = psPolynomial1DAlloc (PS_POLYNOMIAL_ORD, 1);
-    poly->coeffMask[1] = PS_POLY_MASK_SET; // fit only a constant offset (no SKYBIAS)
-
-    // XXX replace this with a psVectorStats call?  since we are not fitting the trend
-    bool result = psVectorClipFitPolynomial1D(poly, options->stats, psfTry->mask, PSFTRY_MASK_ALL,
-                                              psfTry->metric, psfTry->metricErr, r2rflux);
-    if (!result) {
-        psError(PS_ERR_UNKNOWN, false, "Failed to fit clipped poly");
-
-        psFree(poly);
-        psFree(r2rflux);
-
-        return false;
-    }
-    psStatsOptions stdevStat = psStatsStdevOption(options->stats->options); // Statistic for stdev
-    psLogMsg ("pmPSFtryMetric", 4, "apresid: %f +/- %f; from statistics of %ld psf stars\n", poly->coeff[0],
-              psStatsGetValue(options->stats, stdevStat), psfTry->sources->n);
-
-
-
-    // XXX test dump of fitted model (dump when tracing?)
-    if (psTraceGetLevel("psModules.objects") >= 4) {
-        FILE *f = fopen ("resid.dat", "w");
-        psVector *apfit = psPolynomial1DEvalVector (poly, r2rflux);
-        for (int i = 0; i < psfTry->sources->n; i++) {
-            int keep = (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL);
-
-            pmSource *source = psfTry->sources->data[i];
-            float x = source->peak->x;
-            float y = source->peak->y;
-
-            fprintf (f, "%d  %d, %f %f %f  %f %f %f  %f\n",
-                     i, keep, x, y,
-                     psfTry->fitMag->data.F32[i],
-                     r2rflux->data.F32[i],
-                     psfTry->metric->data.F32[i],
-                     psfTry->metricErr->data.F32[i],
-                     apfit->data.F32[i]);
-        }
-        fclose (f);
-        psFree (apfit);
-    }
-
-    // XXX drop the skyBias value, or include above??
-    psfTry->psf->skyBias  = poly->coeff[1];
-    psfTry->psf->ApResid  = poly->coeff[0];
-    psfTry->psf->dApResid = psStatsGetValue(options->stats, stdevStat);
-
-    psFree (r2rflux);
-    psFree (poly);
-
-    return true;
-}
-
-/*
-  (aprMag' - fitMag) = rflux*skyBias + ApTrend(x,y)
-  (aprMag - rflux*skyBias) - fitMag = ApTrend(x,y)
-  (aprMag - rflux*skyBias) = fitMag + ApTrend(x,y)
-*/
-
-/*****************************************************************************
-pmPSFFromPSFtry (psfTry): build a PSF model from a collection of
-source->modelEXT entries.  The PSF ignores the first 4 (independent) model
-parameters and constructs a polynomial fit to the remaining as a function of
-image coordinate.
-    input: psfTry with fitted source->modelEXT collection, pre-allocated psf
-Note: some of the array entries may be NULL (failed fits); ignore them.
- *****************************************************************************/
-bool pmPSFFromPSFtry (pmPSFtry *psfTry)
-{
-    PS_ASSERT_PTR_NON_NULL(psfTry, false);
-    PS_ASSERT_PTR_NON_NULL(psfTry->sources, false);
-
-    pmPSF *psf = psfTry->psf;
-
-    // construct the fit vectors from the collection of objects
-    psVector *x  = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
-    psVector *y  = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
-    psVector *z  = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
-
-    // construct the x,y terms
-    for (int i = 0; i < psfTry->sources->n; i++) {
-        pmSource *source = psfTry->sources->data[i];
-        if (source->modelEXT == NULL)
-            continue;
-
-        x->data.F32[i] = source->modelEXT->params->data.F32[PM_PAR_XPOS];
-        y->data.F32[i] = source->modelEXT->params->data.F32[PM_PAR_YPOS];
-    }
-
-    if (!pmPSFFitShapeParams (psf, psfTry->sources, x, y, psfTry->mask)) {
-        psFree(x);
-        psFree(y);
-        psFree(z);
-        return false;
-    }
-
-    // skip the unfitted parameters (X, Y, Io, Sky) and the shape parameters (SXX, SYY, SXY)
-    // apply the values of Nx, Ny determined above for E0,E1,E2 to the remaining parameters
-    for (int i = 0; i < psf->params->n; i++) {
-        switch (i) {
-          case PM_PAR_SKY:
-          case PM_PAR_I0:
-          case PM_PAR_XPOS:
-          case PM_PAR_YPOS:
-          case PM_PAR_SXX:
-          case PM_PAR_SYY:
-          case PM_PAR_SXY:
-            continue;
-          default:
-            break;
-        }
-
-        // select the per-object fitted data for this parameter
-        for (int j = 0; j < psfTry->sources->n; j++) {
-            pmSource *source = psfTry->sources->data[j];
-            if (source->modelEXT == NULL) continue;
-            z->data.F32[j] = source->modelEXT->params->data.F32[i];
-        }
-
-        psImageBinning *binning = psImageBinningAlloc();
-        binning->nXruff = psf->trendNx;
-        binning->nYruff = psf->trendNy;
-        binning->nXfine = psf->fieldNx;
-        binning->nYfine = psf->fieldNy;
-
-        if (psf->psfTrendMode == PM_TREND_MAP) {
-            psImageBinningSetScale (binning, PS_IMAGE_BINNING_CENTER);
-            psImageBinningSetSkipByOffset (binning, psf->fieldXo, psf->fieldYo);
-        }
-
-        // free existing trend, re-alloc
-        psFree (psf->params->data[i]);
-        psf->params->data[i] = pmTrend2DNoImageAlloc (psf->psfTrendMode, binning, psf->psfTrendStats);
-        psFree (binning);
-
-        // fit the collection of measured parameters to the PSF 2D model
-        // the mask is carried from previous steps and updated with this operation
-        // the weight is either the flux error or NULL, depending on 'psf->poissonErrorParams'
-        if (!pmTrend2DFit (psf->params->data[i], psfTry->mask, 0xff, x, y, z, NULL)) {
-            psError(PS_ERR_UNKNOWN, false, "failed to build psf model for parameter %d", i);
-            psFree(x);
-            psFree(y);
-            psFree(z);
-            return false;
-        }
-    }
-
-    // test dump of star parameters vs position (compare with fitted values)
-    if (psTraceGetLevel("psModules.objects") >= 4) {
-        FILE *f = fopen ("params.dat", "w");
-
-        for (int j = 0; j < psfTry->sources->n; j++) {
-            pmSource *source = psfTry->sources->data[j];
-            if (source == NULL) continue;
-            if (source->modelEXT == NULL) continue;
-
-            pmModel *modelPSF = pmModelFromPSF (source->modelEXT, psf);
-
-            fprintf (f, "%f %f : ", source->modelEXT->params->data.F32[PM_PAR_XPOS], source->modelEXT->params->data.F32[PM_PAR_YPOS]);
-
-            for (int i = 0; i < psf->params->n; i++) {
-                if (psf->params->data[i] == NULL) continue;
-                fprintf (f, "%f %f : ", source->modelEXT->params->data.F32[i], modelPSF->params->data.F32[i]);
-            }
-            fprintf (f, "%f %d\n", source->modelEXT->chisq, source->modelEXT->nIter);
-
-            psFree(modelPSF);
-        }
-        fclose (f);
-    }
-
-    psFree (x);
-    psFree (y);
-    psFree (z);
-    return true;
-}
-
-
-bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask) {
-
-    // we are doing a robust fit.  after each pass, we drop points which are more deviant than
-    // three sigma.  mask is currently updated for each pass.
-
-    // The shape parameters (SXX, SXY, SYY) are strongly coupled.  We have to handle them very
-    // carefully.  First, we convert them to the Ellipse Polarization terms (E0, E1, E2) for
-    // each source and fit this set of parameters.  These values are less tightly coupled, but
-    // are still inter-related.  The fitted values do a good job of constraining the major axis
-    // and the position angle, but the minor axis is weakly measured.  When we apply the PSF
-    // model to construct a source model, we convert the fitted values of E0,E1,E2 to the shape
-    // parameters, with the constraint that the minor axis must be greater than a minimum
-    // threshold.
-
-    // convert the measured source shape paramters to polarization terms
-    psVector *e0   = psVectorAlloc (sources->n, PS_TYPE_F32);
-    psVector *e1   = psVectorAlloc (sources->n, PS_TYPE_F32);
-    psVector *e2   = psVectorAlloc (sources->n, PS_TYPE_F32);
-    psVector *mag  = psVectorAlloc (sources->n, PS_TYPE_F32);
-
-    for (int i = 0; i < sources->n; i++) {
-        // skip any masked sources (failed to fit one of the model steps or get a magnitude)
-        if (srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue;
-
-        pmSource *source = sources->data[i];
-        assert (source->modelEXT); // all unmasked sources should have modelEXT
-
-        psEllipsePol pol = pmPSF_ModelToFit (source->modelEXT->params->data.F32);
-
-        e0->data.F32[i] = pol.e0;
-        e1->data.F32[i] = pol.e1;
-        e2->data.F32[i] = pol.e2;
-
-        float flux = source->modelEXT->params->data.F32[PM_PAR_I0];
-        mag->data.F32[i] = (flux > 0.0) ? -2.5*log(flux) : -100.0;
-    }
-
-    if (psf->psfTrendMode == PM_TREND_MAP) {
-        float scatterTotal = 0.0;
-        float scatterTotalMin = FLT_MAX;
-        int entryMin = -1;
-
-        psVector *dz = NULL;
-        psVector *mask = psVectorAlloc (sources->n, PS_TYPE_VECTOR_MASK);
-
-        // check the fit residuals and increase Nx,Ny until the error is minimized
-        // pmPSFParamTrend increases the number along the longer of x or y
-        for (int i = 1; i <= PS_MAX (psf->trendNx, psf->trendNy); i++) {
-
-            // copy srcMask to mask (we do not want the mask values set in pmPSFFitShapeParamsMap to be sticky)
-            for (int i = 0; i < mask->n; i++) {
-                mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i];
-            }
-            if (!pmPSFFitShapeParamsMap (psf, i, &scatterTotal, mask, x, y, mag, e0, e1, e2, dz)) {
-                break;
-            }
-
-            // store the resulting scatterTotal values and the scales, redo the best
-            if (scatterTotal < scatterTotalMin) {
-                scatterTotalMin = scatterTotal;
-                entryMin = i;
-            }
-        }
-        if (entryMin == -1) {
-            psError (PS_ERR_UNKNOWN, false, "failed to find image map for shape params");
-            return false;
-        }
-
-        // copy srcMask to mask (we do not want the mask values set in pmPSFFitShapeParamsMap to be sticky)
-        for (int i = 0; i < mask->n; i++) {
-            mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i];
-        }
-        if (!pmPSFFitShapeParamsMap (psf, entryMin, &scatterTotal, mask, x, y, mag, e0, e1, e2, dz)) {
-            psAbort ("failed pmPSFFitShapeParamsMap on second pass?");
-        }
-
-        pmTrend2D *trend = psf->params->data[PM_PAR_E0];
-        psf->trendNx = trend->map->map->numCols;
-        psf->trendNy = trend->map->map->numRows;
-
-        // copy mask back to srcMask
-        for (int i = 0; i < mask->n; i++) {
-            srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = mask->data.PS_TYPE_VECTOR_MASK_DATA[i];
-        }
-
-        psFree (mask);
-        psFree (dz);
-    } else {
-
-        // XXX iterate Nx, Ny based on scatter?
-        // XXX we force the x & y order to be the same
-        // modify the order to correspond to the actual number of matched stars:
-        int order = PS_MAX (psf->trendNx, psf->trendNy);
-        if ((sources->n < 15) && (order >= 3)) order = 2;
-        if ((sources->n < 11) && (order >= 2)) order = 1;
-        if ((sources->n <  8) && (order >= 1)) order = 0;
-        if ((sources->n <  3)) {
-            psError (PS_ERR_UNKNOWN, true, "failed to fit polynomial to shape params");
-            return false;
-        }
-        psf->trendNx = order;
-        psf->trendNy = order;
-
-        // we run 'clipIter' cycles clipping in each of x and y, with only one iteration each.
-        // This way, the parameters masked by one of the fits will be applied to the others
-        for (int i = 0; i < psf->psfTrendStats->clipIter; i++) {
-
-            psStatsOptions meanOption = psStatsMeanOption(psf->psfTrendStats->options);
-            psStatsOptions stdevOption = psStatsStdevOption(psf->psfTrendStats->options);
-
-            pmTrend2D *trend = NULL;
-            float mean, stdev;
-
-            // XXX we are using the same stats structure on each pass: do we need to re-init it?
-            bool status = true;
-
-            trend = psf->params->data[PM_PAR_E0];
-            status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e0, NULL);
-            mean = psStatsGetValue (trend->stats, meanOption);
-            stdev = psStatsGetValue (trend->stats, stdevOption);
-            psTrace ("psModules.objects", 4, "clipped E0 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e0->n);
-            pmSourceVisualPSFModelResid (trend, x, y, e0, srcMask);
-
-            trend = psf->params->data[PM_PAR_E1];
-            status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e1, NULL);
-            mean = psStatsGetValue (trend->stats, meanOption);
-            stdev = psStatsGetValue (trend->stats, stdevOption);
-            psTrace ("psModules.objects", 4, "clipped E1 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e1->n);
-            pmSourceVisualPSFModelResid (trend, x, y, e1, srcMask);
-
-            trend = psf->params->data[PM_PAR_E2];
-            status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e2, NULL);
-            mean = psStatsGetValue (trend->stats, meanOption);
-            stdev = psStatsGetValue (trend->stats, stdevOption);
-            psTrace ("psModules.objects", 4, "clipped E2 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e2->n);
-            pmSourceVisualPSFModelResid (trend, x, y, e2, srcMask);
-
-            if (!status) {
-                psError (PS_ERR_UNKNOWN, true, "failed to fit polynomial to shape params");
-                return false;
-            }
-        }
-    }
-
-    // test dump of the psf parameters
-    if (psTraceGetLevel("psModules.objects") >= 4) {
-        FILE *f = fopen ("pol.dat", "w");
-        fprintf (f, "# x y  :  e0obs e1obs e2obs  : e0fit e1fit e2fit : mask\n");
-        for (int i = 0; i < e0->n; i++) {
-            fprintf (f, "%f %f  :  %f %f %f  : %f %f %f  : %d\n",
-                     x->data.F32[i], y->data.F32[i],
-                     e0->data.F32[i], e1->data.F32[i], e2->data.F32[i],
-                     pmTrend2DEval (psf->params->data[PM_PAR_E0], x->data.F32[i], y->data.F32[i]),
-                     pmTrend2DEval (psf->params->data[PM_PAR_E1], x->data.F32[i], y->data.F32[i]),
-                     pmTrend2DEval (psf->params->data[PM_PAR_E2], x->data.F32[i], y->data.F32[i]),
-                     srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
-        }
-        fclose (f);
-    }
-
-    psFree (e0);
-    psFree (e1);
-    psFree (e2);
-    psFree (mag);
-    return true;
-}
-
-// fit the shape variations as a psImageMap for the given scale factor
-bool pmPSFFitShapeParamsMap (pmPSF *psf, int scale, float *scatterTotal, psVector *mask, psVector *x, psVector *y, psVector *mag, psVector *e0obs, psVector *e1obs, psVector *e2obs, psVector *dz) {
-
-    int Nx, Ny;
-
-    // set the map scale to match the aspect ratio : for a scale of 1, we guarantee
-    // that we have a single cell
-    if (psf->fieldNx > psf->fieldNy) {
-        Nx = scale;
-        float AR = psf->fieldNy / (float) psf->fieldNx;
-        Ny = (int) (Nx * AR + 0.5);
-        Ny = PS_MAX (1, Ny);
-    } else {
-        Ny = scale;
-        float AR = psf->fieldNx / (float) psf->fieldNy;
-        Nx = (int) (Ny * AR + 0.5);
-        Nx = PS_MAX (1, Nx);
-    }
-
-    // do we have enough sources for this fine of a grid?
-    if (x->n < 10*Nx*Ny) {
-        return false;
-    }
-
-    // XXX check this against the exising type
-    pmTrend2DMode psfTrendMode = PM_TREND_MAP;
-
-    psImageBinning *binning = psImageBinningAlloc();
-    binning->nXruff = Nx;
-    binning->nYruff = Ny;
-    binning->nXfine = psf->fieldNx;
-    binning->nYfine = psf->fieldNy;
-    psImageBinningSetScale (binning, PS_IMAGE_BINNING_CENTER);
-    psImageBinningSetSkipByOffset (binning, psf->fieldXo, psf->fieldYo);
-
-    psFree (psf->params->data[PM_PAR_E0]);
-    psFree (psf->params->data[PM_PAR_E1]);
-    psFree (psf->params->data[PM_PAR_E2]);
-
-    int nIter = psf->psfTrendStats->clipIter;
-    psf->psfTrendStats->clipIter = 1;
-    psf->params->data[PM_PAR_E0] = pmTrend2DNoImageAlloc (psfTrendMode, binning, psf->psfTrendStats);
-    psf->params->data[PM_PAR_E1] = pmTrend2DNoImageAlloc (psfTrendMode, binning, psf->psfTrendStats);
-    psf->params->data[PM_PAR_E2] = pmTrend2DNoImageAlloc (psfTrendMode, binning, psf->psfTrendStats);
-    psFree (binning);
-
-    // if the map is 1x1 (a single value), we measure the resulting ensemble scatter
-
-    // if the map is more finely sampled, divide the values into two sets: measure the fit from
-    // one set and the scatter from the other set.
-    psVector *x_fit = NULL;
-    psVector *y_fit = NULL;
-    psVector *x_tst = NULL;
-    psVector *y_tst = NULL;
-
-    psVector *e0obs_fit = NULL;
-    psVector *e1obs_fit = NULL;
-    psVector *e2obs_fit = NULL;
-    psVector *e0obs_tst = NULL;
-    psVector *e1obs_tst = NULL;
-    psVector *e2obs_tst = NULL;
-
-    if (scale == 1) {
-        x_fit  = psMemIncrRefCounter (x);
-        y_fit  = psMemIncrRefCounter (y);
-        x_tst  = psMemIncrRefCounter (x);
-        y_tst  = psMemIncrRefCounter (y);
-        e0obs_fit = psMemIncrRefCounter (e0obs);
-        e1obs_fit = psMemIncrRefCounter (e1obs);
-        e2obs_fit = psMemIncrRefCounter (e2obs);
-        e0obs_tst = psMemIncrRefCounter (e0obs);
-        e1obs_tst = psMemIncrRefCounter (e1obs);
-        e2obs_tst = psMemIncrRefCounter (e2obs);
-    } else {
-        x_fit  = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        y_fit  = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        x_tst  = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        y_tst  = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        e0obs_fit = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        e1obs_fit = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        e2obs_fit = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        e0obs_tst = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        e1obs_tst = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        e2obs_tst = psVectorAlloc (e0obs->n/2, PS_TYPE_F32);
-        for (int i = 0; i < e0obs_fit->n; i++) {
-            // e0obs->n ==  8 or 9:
-            // i = 0, 1, 2, 3 : 2i+0 = 0, 2, 4, 6
-            // i = 0, 1, 2, 3 : 2i+1 = 1, 3, 5, 7
-            x_fit->data.F32[i] = x->data.F32[2*i+0];
-            x_tst->data.F32[i] = x->data.F32[2*i+1];
-            y_fit->data.F32[i] = y->data.F32[2*i+0];
-            y_tst->data.F32[i] = y->data.F32[2*i+1];
-
-            e0obs_fit->data.F32[i] = e0obs->data.F32[2*i+0];
-            e0obs_tst->data.F32[i] = e0obs->data.F32[2*i+1];
-            e1obs_fit->data.F32[i] = e1obs->data.F32[2*i+0];
-            e1obs_tst->data.F32[i] = e1obs->data.F32[2*i+1];
-            e2obs_fit->data.F32[i] = e2obs->data.F32[2*i+0];
-            e2obs_tst->data.F32[i] = e2obs->data.F32[2*i+1];
-        }
-    }
-
-    // the mask marks the values not used to calculate the ApTrend
-    psVector *fitMask = psVectorAlloc (x_fit->n, PS_TYPE_VECTOR_MASK);
-    // copy mask values to fitMask as a starting point
-    for (int i = 0; i < fitMask->n; i++) {
-        fitMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = mask->data.PS_TYPE_VECTOR_MASK_DATA[i];
-    }
-
-    // we run 'clipIter' cycles clipping in each of x and y, with only one iteration each.
-    // This way, the parameters masked by one of the fits will be applied to the others
-    for (int i = 0; i < nIter; i++) {
-        // XXX we are using the same stats structure on each pass: do we need to re-init it?
-        psStatsOptions meanOption = psStatsMeanOption(psf->psfTrendStats->options);
-        psStatsOptions stdevOption = psStatsStdevOption(psf->psfTrendStats->options);
-
-        pmTrend2D *trend = NULL;
-        float mean, stdev;
-
-        // XXX we are using the same stats structure on each pass: do we need to re-init it?
-        bool status = true;
-
-        trend = psf->params->data[PM_PAR_E0];
-        status &= pmTrend2DFit (trend, fitMask, 0xff, x_fit, y_fit, e0obs_fit, NULL);
-        mean = psStatsGetValue (trend->stats, meanOption);
-        stdev = psStatsGetValue (trend->stats, stdevOption);
-        psTrace ("psModules.objects", 4, "clipped E0 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e0obs_fit->n);
-        // printTrendMap (trend);
-        psImageMapCleanup (trend->map);
-        // printTrendMap (trend);
-        pmSourceVisualPSFModelResid (trend, x, y, e0obs, mask);
-
-        trend = psf->params->data[PM_PAR_E1];
-        status &= pmTrend2DFit (trend, fitMask, 0xff, x_fit, y_fit, e1obs_fit, NULL);
-        mean = psStatsGetValue (trend->stats, meanOption);
-        stdev = psStatsGetValue (trend->stats, stdevOption);
-        psTrace ("psModules.objects", 4, "clipped E1 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e1obs_fit->n);
-        // printTrendMap (trend);
-        psImageMapCleanup (trend->map);
-        // printTrendMap (trend);
-        pmSourceVisualPSFModelResid (trend, x, y, e1obs, mask);
-
-        trend = psf->params->data[PM_PAR_E2];
-        status &= pmTrend2DFit (trend, fitMask, 0xff, x_fit, y_fit, e2obs_fit, NULL);
-        mean = psStatsGetValue (trend->stats, meanOption);
-        stdev = psStatsGetValue (trend->stats, stdevOption);
-        psTrace ("psModules.objects", 4, "clipped E2 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e2obs->n);
-        // printTrendMap (trend);
-        psImageMapCleanup (trend->map);
-        // printTrendMap (trend);
-        pmSourceVisualPSFModelResid (trend, x, y, e2obs, mask);
-    }
-    psf->psfTrendStats->clipIter = nIter; // restore default setting
-
-    // construct the fitted values and the residuals
-    psVector *e0fit = pmTrend2DEvalVector (psf->params->data[PM_PAR_E0], fitMask, 0xff, x_tst, y_tst);
-    psVector *e1fit = pmTrend2DEvalVector (psf->params->data[PM_PAR_E1], fitMask, 0xff, x_tst, y_tst);
-    psVector *e2fit = pmTrend2DEvalVector (psf->params->data[PM_PAR_E2], fitMask, 0xff, x_tst, y_tst);
-
-    psVector *e0res = (psVector *) psBinaryOp (NULL, (void *) e0obs_tst, "-", (void *) e0fit);
-    psVector *e1res = (psVector *) psBinaryOp (NULL, (void *) e1obs_tst, "-", (void *) e1fit);
-    psVector *e2res = (psVector *) psBinaryOp (NULL, (void *) e2obs_tst, "-", (void *) e2fit);
-
-    // measure scatter for the unfitted points
-    // psTraceSetLevel ("psLib.math.vectorSampleStdev", 10);
-    // psTraceSetLevel ("psLib.math.vectorClippedStats", 10);
-    pmPSFShapeParamsScatter (scatterTotal, e0res, e1res, e2res, fitMask, 0xff, psStatsStdevOption(psf->psfTrendStats->options));
-    // psTraceSetLevel ("psLib.math.vectorSampleStdev", 0);
-    // psTraceSetLevel ("psLib.math.vectorClippedStats", 0);
-
-    psLogMsg ("psphot.psftry", PS_LOG_INFO, "result of %d x %d grid\n", Nx, Ny);
-    psLogMsg ("psphot.psftry", PS_LOG_INFO, "systematic scatter: %f\n", *scatterTotal);
-
-    psFree (x_fit);
-    psFree (y_fit);
-    psFree (x_tst);
-    psFree (y_tst);
-
-    psFree (e0obs_fit);
-    psFree (e1obs_fit);
-    psFree (e2obs_fit);
-    psFree (e0obs_tst);
-    psFree (e1obs_tst);
-    psFree (e2obs_tst);
-
-    psFree (e0fit);
-    psFree (e1fit);
-    psFree (e2fit);
-
-    psFree (e0res);
-    psFree (e1res);
-    psFree (e2res);
-
-    // XXX copy fitMask values back to mask
-    for (int i = 0; i < fitMask->n; i++) {
-        mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = fitMask->data.PS_TYPE_VECTOR_MASK_DATA[i];
-    }
-    psFree (fitMask);
-
-    return true;
-}
-
-// calculate the scatter of the parameters
-bool pmPSFShapeParamsScatter(float *scatterTotal, psVector *e0res, psVector *e1res, psVector *e2res, psVector *mask, psVectorMaskType maskValue, psStatsOptions stdevOpt)
-{
-
-    // psStats *stats = psStatsAlloc(stdevOpt);
-    psStats *stats = psStatsAlloc(PS_STAT_CLIPPED_STDEV);
-
-    // calculate the root-mean-square of E0, E1, E2
-    float dEsquare = 0.0;
-    psStatsInit (stats);
-    if (!psVectorStats (stats, e0res, NULL, mask, maskValue)) {
-        psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-        return false;
-    }
-    dEsquare += PS_SQR(psStatsGetValue(stats, stdevOpt));
-
-    psStatsInit (stats);
-    if (!psVectorStats (stats, e1res, NULL, mask, maskValue)) {
-        psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-        return false;
-    }
-    dEsquare += PS_SQR(psStatsGetValue(stats, stdevOpt));
-
-    psStatsInit (stats);
-    if (!psVectorStats (stats, e2res, NULL, mask, maskValue)) {
-        psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-        return false;
-    }
-    dEsquare += PS_SQR(psStatsGetValue(stats, stdevOpt));
-
-    *scatterTotal = sqrtf(dEsquare);
-
-    psFree(stats);
-    return true;
-}
-
-// calculate the minimum scatter of the parameters
-bool pmPSFShapeParamsErrors(float *errorFloor, psVector *mag, psVector *e0res, psVector *e1res,
-                            psVector *e2res, psVector *mask, int nGroup, psStatsOptions stdevOpt)
-{
-
-    psStats *statsS = psStatsAlloc(stdevOpt);
-
-    // measure the trend in bins with 10 values each; if < 10 total, use them all
-    int nBin = PS_MAX (mag->n / nGroup, 1);
-
-    // use mag to group parameters in sequence
-    psVector *index = psVectorSortIndex (NULL, mag);
-
-    // subset vectors for mag and dap values within the given range
-    psVector *dE0subset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
-    psVector *dE1subset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
-    psVector *dE2subset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
-    psVector *mkSubset  = psVectorAllocEmpty (nGroup, PS_TYPE_VECTOR_MASK);
-
-    int n = 0;
-    float min = INFINITY;               // Minimum error
-    for (int i = 0; i < nBin; i++) {
-        int j;
-        int nValid = 0;
-        for (j = 0; (j < nGroup) && (n < mag->n); j++, n++) {
-            int N = index->data.U32[n];
-            dE0subset->data.F32[j] = e0res->data.F32[N];
-            dE1subset->data.F32[j] = e1res->data.F32[N];
-            dE2subset->data.F32[j] = e2res->data.F32[N];
-
-            mkSubset->data.PS_TYPE_VECTOR_MASK_DATA[j]   = mask->data.PS_TYPE_VECTOR_MASK_DATA[N];
-            if (!mask->data.PS_TYPE_VECTOR_MASK_DATA[N]) nValid ++;
-        }
-        if (nValid < 3) continue;
-
-        dE0subset->n = j;
-        dE1subset->n = j;
-        dE2subset->n = j;
-        mkSubset->n = j;
-
-        // calculate the root-mean-square of E0, E1, E2
-        float dEsquare = 0.0;
-        psStatsInit (statsS);
-        if (!psVectorStats (statsS, dE0subset, NULL, mkSubset, 0xff)) {
-        }
-        dEsquare += PS_SQR(psStatsGetValue(statsS, stdevOpt));
-
-        psStatsInit (statsS);
-        if (!psVectorStats (statsS, dE1subset, NULL, mkSubset, 0xff)) {
-            psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-            return false;
-        }
-        dEsquare += PS_SQR(psStatsGetValue(statsS, stdevOpt));
-
-        psStatsInit (statsS);
-        if (!psVectorStats (statsS, dE2subset, NULL, mkSubset, 0xff)) {
-            psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-            return false;
-        }
-        dEsquare += PS_SQR(psStatsGetValue(statsS, stdevOpt));
-
-        if (isfinite(dEsquare)) {
-            float err = sqrtf(dEsquare);
-            if (err < min) {
-                min = err;
-            }
-        }
-    }
-    *errorFloor = min;
-
-    psFree (dE0subset);
-    psFree (dE1subset);
-    psFree (dE2subset);
-    psFree (mkSubset);
-
-    psFree(index);
-
-    psFree(statsS);
-
-    return true;
-}
Index: branches/eam_branches/20090820/psModules/src/objects/pmPSFtry.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPSFtry.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPSFtry.h	(revision 25766)
@@ -89,5 +89,18 @@
  *
  */
-pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType mark);
+pmPSFtry *pmPSFtryModel (
+    const psArray *sources,		///< PSF sources to use in the pmPSF model analysis
+    const char *modelName,  		///< human-readable name of desired model
+    pmPSFOptions *options, 
+    psImageMaskType maskVal, 
+    psImageMaskType mark
+    );
+
+/** fit EXT models to all possible psf sources */
+bool pmPSFtryFitEXT (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal);
+
+bool pmPSFtryMakePSF (pmPSFtry *psfTry);
+
+bool pmPSFtryFitPSF (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal);
 
 /** pmPSFtryMetric()
@@ -97,8 +110,5 @@
  *
  */
-bool pmPSFtryMetric(
-    pmPSFtry *psfTry,                  ///< Add comment.
-    pmPSFOptions *options              ///< PSF fitting options
-);
+bool pmPSFtryMetric(pmPSFtry *psfTry);
 
 /** pmPSFtryMetric_Alt()
@@ -112,4 +122,11 @@
     float RADIUS                        ///< Add comment.
 );
+
+bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask);
+
+float psVectorSystematicError (psVector *residuals, psVector *errors, float clipFraction);
+
+/// @}
+# endif
 
 /**
@@ -125,11 +142,3 @@
  *
  */
-bool pmPSFFromPSFtry (pmPSFtry *psfTry);
 
-bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask);
-bool pmPSFFitShapeParamsMap (pmPSF *psf, int scale, float *scatterTotal, psVector *mask, psVector *x, psVector *y, psVector *mag, psVector *e0obs, psVector *e1obs, psVector *e2obs, psVector *dz);
-bool pmPSFShapeParamsScatter(float *scatterTotal, psVector *e0res, psVector *e1res, psVector *e2res, psVector *mask, psVectorMaskType maskValue, psStatsOptions stdevOpt);
-bool pmPSFShapeParamsErrors (float *errorFloor, psVector *mag, psVector *e0res, psVector *e1res, psVector *e2res, psVector *mask, int nGroup, psStatsOptions stdevOpt);
-
-/// @}
-# endif
Index: branches/eam_branches/20090820/psModules/src/objects/pmPSFtryFitEXT.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPSFtryFitEXT.c	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPSFtryFitEXT.c	(revision 25766)
@@ -0,0 +1,97 @@
+/** @file  pmPSFtry.c
+ *
+ *  XXX: need description of file purpose
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.69 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-01-27 06:39:38 $
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+# include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "pmSpan.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmTrend2D.h"
+#include "pmPSF.h"
+#include "pmModel.h"
+#include "pmSource.h"
+#include "pmSourceUtils.h"
+#include "pmPSFtry.h"
+#include "pmModelClass.h"
+#include "pmModelUtils.h"
+#include "pmSourceFitModel.h"
+#include "pmSourcePhotometry.h"
+#include "pmSourceVisual.h"
+
+// Fit an EXT model to all candidates PSF sources.
+// Note: this is independent of the modeled 2D variations in the PSF.
+bool pmPSFtryFitEXT (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal) {
+
+    bool status;
+
+    psTimerStart ("psf.fit");
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
+    int Next = 0;
+    for (int i = 0; i < psfTry->sources->n; i++) {
+
+        pmSource *source = psfTry->sources->data[i];
+        if (!source->moments) {
+            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+            continue;
+        }
+        if (!source->moments->nPixels) {
+            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+            continue;
+        }
+
+        source->modelEXT = pmSourceModelGuess (source, options->type);
+        if (source->modelEXT == NULL) {
+            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y);
+            continue;
+        }
+
+        // set object mask to define valid pixels
+	// XXX 0.5 PIX: is the circle symmetric about the peak coordinate (given 0.5,0.5 center)?
+        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->fitRadius, "OR", markVal);
+
+        // fit model as EXT, not PSF
+        status = pmSourceFitModel (source, source->modelEXT, PM_SOURCE_FIT_EXT, maskVal);
+
+        // clear object mask to define valid pixels
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
+
+        // exclude the poor fits
+        if (!status) {
+            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y);
+            continue;
+        }
+        Next ++;
+    }
+    psLogMsg ("psphot.psftry", PS_LOG_MINUTIA, "fit ext:   %f sec for %d of %ld sources\n", psTimerMark ("psf.fit"), Next, psfTry->sources->n);
+    psTrace ("psModules.object", 3, "keeping %d of %ld PSF candidates (EXT)\n", Next, psfTry->sources->n);
+
+    if (Next == 0) {
+        psError(PS_ERR_UNKNOWN, false, "No sources with good extended fits from which to determine PSF.");
+        return false;
+    }
+
+    return true;
+}
Index: branches/eam_branches/20090820/psModules/src/objects/pmPSFtryFitPSF.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPSFtryFitPSF.c	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPSFtryFitPSF.c	(revision 25766)
@@ -0,0 +1,149 @@
+/** @file  pmPSFtryFitPSF.c
+ *  @brief Fit the PSF model to the candidate PSF stars (part of PSF model generation)
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.69 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-01-27 06:39:38 $
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+# include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "pmSpan.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmTrend2D.h"
+#include "pmPSF.h"
+#include "pmModel.h"
+#include "pmSource.h"
+#include "pmSourceUtils.h"
+#include "pmPSFtry.h"
+#include "pmModelClass.h"
+#include "pmModelUtils.h"
+#include "pmSourceFitModel.h"
+#include "pmSourcePhotometry.h"
+#include "pmSourceVisual.h"
+
+// stage 3: Refit with fixed shape parameters.  This function uses the LMM fitting, but could
+// be re-written to use the simultaneous linear fitting (see psphotFitSourcesLinear.c)
+bool pmPSFtryFitPSF (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal) {
+
+    bool status;
+
+    psTimerStart ("psf.fit");
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
+    // DEBUG code: save the PSF model fit data in detail
+# ifdef DEBUG
+    char filename[64];
+    snprintf (filename, 64, "psffit.%dx%d.dat", psfTry->psf->trendNx, psfTry->psf->trendNy);
+    FILE *f = fopen (filename, "w");
+    psAssert (f, "failed open");
+# endif
+
+    int Npsf = 0;
+    for (int i = 0; i < psfTry->sources->n; i++) {
+
+        pmSource *source = psfTry->sources->data[i];
+	psAssert (source->moments, "how can a psf source not have moments?");
+
+        // masked for: bad model fit, outlier in parameters
+        if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL) {
+            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : source is masked\n", i, source->peak->x, source->peak->y);
+            continue;
+        }
+
+        // set shape for this model based on PSF
+	psFree (source->modelPSF);
+        source->modelPSF = pmModelFromPSF (source->modelEXT, psfTry->psf);
+        if (source->modelPSF == NULL) {
+            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_BAD_MODEL;
+            abort();
+            continue;
+        }
+	// PSF fit and aperture mags use different radii
+        source->modelPSF->fitRadius = options->fitRadius;
+        source->apRadius = options->apRadius;
+
+        // set object mask to define valid pixels for PSF model fit
+        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->fitRadius, "OR", markVal);
+
+        // fit the PSF model to the source
+        status = pmSourceFitModel (source, source->modelPSF, PM_SOURCE_FIT_NORM, maskVal);
+
+        // skip poor fits
+        if (!status) {
+            psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
+            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_PSF_FAIL;
+            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : failed PSF fit\n", i, source->peak->x, source->peak->y);
+            continue;
+        }
+
+        // set object mask to define valid pixels for APERTURE magnitude
+	if (options->fitRadius != options->apRadius) {
+            psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
+	    psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->apRadius, "OR", markVal);
+	}
+
+	// This function calculates the psf and aperture magnitudes
+        status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal); // raw PSF mag, AP mag
+        if (!status || isnan(source->apMag)) {
+            psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
+            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_BAD_PHOT;
+            psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : poor photometry\n", i, source->peak->x, source->peak->y);
+            continue;
+        }
+
+        // clear object mask to define valid pixels
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
+
+        psfTry->fitMag->data.F32[i] = source->psfMag;
+        psfTry->metric->data.F32[i] = source->apMag - source->psfMag;
+        psfTry->metricErr->data.F32[i] = source->errMag;
+
+	// XXX this did not work: modifies shape of psf too much
+        // psfTry->metric->data.F32[i] = -2.5*log10(source->moments->Sum) - source->psfMag;
+
+# ifdef DEBUG
+	fprintf (f, "%6.1f %6.1f : %6.1f %6.1f : %8.3f %8.3f %8.3f : %f : %f %f %f : %f\n",
+		 source->peak->xf, source->peak->yf, 
+		 source->modelPSF->params->data.F32[PM_PAR_XPOS], source->modelPSF->params->data.F32[PM_PAR_YPOS], 
+		 source->psfMag, source->apMag, source->errMag,
+		 source->modelPSF->params->data.F32[PM_PAR_I0], 
+		 source->modelPSF->params->data.F32[PM_PAR_SXX], source->modelPSF->params->data.F32[PM_PAR_SXY], 
+		 source->modelPSF->params->data.F32[PM_PAR_SYY], source->modelPSF->params->data.F32[PM_PAR_7]);
+# endif
+
+        psTrace ("psModules.object", 6, "keeping source %d (%d) of %ld\n", i, Npsf, psfTry->sources->n);
+        Npsf ++;
+    }
+    psfTry->psf->nPSFstars = Npsf;
+
+# ifdef DEBUG
+    fclose (f);
+# endif
+
+    pmSourceVisualShowModelFits (psfTry->psf, psfTry->sources, maskVal);
+
+    psLogMsg ("psphot.psftry", PS_LOG_MINUTIA, "fit psf:   %f sec for %d of %ld sources\n", psTimerMark ("psf.fit"), Npsf, psfTry->sources->n);
+    psTrace ("psModules.object", 3, "keeping %d of %ld PSF candidates (PSF)\n", Npsf, psfTry->sources->n);
+
+    if (Npsf == 0) {
+        psError(PS_ERR_UNKNOWN, false, "No sources with good PSF fits after model is built.");
+        return false;
+    }
+
+    return true;
+}
Index: branches/eam_branches/20090820/psModules/src/objects/pmPSFtryMakePSF.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPSFtryMakePSF.c	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPSFtryMakePSF.c	(revision 25766)
@@ -0,0 +1,267 @@
+/** @file  pmPSFtry.c
+ *  @brief generate a pmPSF from a collection of EXT measurments of likely PSF stars.
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.69 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-01-27 06:39:38 $
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+# include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "pmSpan.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmTrend2D.h"
+#include "pmPSF.h"
+#include "pmModel.h"
+#include "pmSource.h"
+#include "pmSourceUtils.h"
+#include "pmPSFtry.h"
+#include "pmModelClass.h"
+#include "pmModelUtils.h"
+#include "pmSourceFitModel.h"
+#include "pmSourcePhotometry.h"
+#include "pmSourceVisual.h"
+
+/*****************************************************************************
+pmPSFFromPSFtry (psfTry): build a PSF model from a collection of source->modelEXT entries
+using the specified order in X,Y.  The PSF ignores the first 4 (independent) model
+parameters and constructs a polynomial fit to the remaining as a function of image
+coordinate.  Input: psfTry with fitted source->modelEXT collection, pre-allocated psf
+Note: some of the array entries may be NULL (failed fits); ignore them.
+ *****************************************************************************/
+bool pmPSFtryMakePSF (pmPSFtry *psfTry)
+{
+    PS_ASSERT_PTR_NON_NULL(psfTry, false);
+    PS_ASSERT_PTR_NON_NULL(psfTry->sources, false);
+
+    pmPSF *psf = psfTry->psf;
+    psVector *srcMask = psfTry->mask;
+
+    // construct the fit vectors from the collection of objects
+    psVector *x  = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
+    psVector *y  = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
+
+    // construct the x,y terms
+    for (int i = 0; i < psfTry->sources->n; i++) {
+        if (srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue;
+
+        pmSource *source = psfTry->sources->data[i];
+        assert (source->modelEXT); // all unmasked sources should have modelEXT
+
+        x->data.F32[i] = source->modelEXT->params->data.F32[PM_PAR_XPOS];
+        y->data.F32[i] = source->modelEXT->params->data.F32[PM_PAR_YPOS];
+    }
+
+    // fit the shape parameters (SXX, SYY, SXY) as a function of position
+    if (!pmPSFFitShapeParams (psf, psfTry->sources, x, y, srcMask)) {
+        psFree(x);
+        psFree(y);
+        return false;
+    }
+
+    // vector to store the other parameter values
+    psVector *z  = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
+
+    // skip the unfitted parameters (X, Y, Io, Sky) and the shape parameters (SXX, SYY, SXY);
+    // fit the remaining parameters.
+    for (int i = 0; i < psf->params->n; i++) {
+        switch (i) {
+          case PM_PAR_SKY:
+          case PM_PAR_I0:
+          case PM_PAR_XPOS:
+          case PM_PAR_YPOS:
+          case PM_PAR_SXX:
+          case PM_PAR_SYY:
+          case PM_PAR_SXY:
+            continue;
+          default:
+            break;
+        }
+
+        // select the per-object fitted data for this parameter
+        for (int j = 0; j < psfTry->sources->n; j++) {
+	    // skip any masked sources (failed to fit one of the model steps or get a magnitude)
+	    if (srcMask->data.PS_TYPE_VECTOR_MASK_DATA[j]) continue;
+
+            pmSource *source = psfTry->sources->data[j];
+	    assert (source->modelEXT); // all unmasked sources should have modelEXT
+
+            z->data.F32[j] = source->modelEXT->params->data.F32[i];
+        }
+
+	pmTrend2D *trend = psf->params->data[i];
+
+        // fit the collection of measured parameters to the PSF 2D model
+        // the mask is carried from previous steps and updated with this operation
+        // the weight is either the flux error or NULL, depending on 'psf->poissonErrorParams'
+        if (!pmTrend2DFit (trend, srcMask, 0xff, x, y, z, NULL)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to build psf model for parameter %d", i);
+            psFree(x);
+            psFree(y);
+            psFree(z);
+            return false;
+        }
+	if (trend->mode == PM_TREND_MAP) {
+	    // p_psImagePrint (2, trend->map->map, "param N Before"); // XXX TEST:
+	    psImageMapRepair (trend->map->map);
+	    // p_psImagePrint (2, trend->map->map, "param N After"); // XXX TEST:
+	}
+    }
+
+    // test dump of star parameters vs position (compare with fitted values)
+    if (psTraceGetLevel("psModules.objects") >= 4) {
+        FILE *f = fopen ("params.dat", "w");
+
+        for (int j = 0; j < psfTry->sources->n; j++) {
+            pmSource *source = psfTry->sources->data[j];
+            if (source == NULL) continue;
+            if (source->modelEXT == NULL) continue;
+
+            pmModel *modelPSF = pmModelFromPSF (source->modelEXT, psf);
+
+            fprintf (f, "%f %f : ", source->modelEXT->params->data.F32[PM_PAR_XPOS], source->modelEXT->params->data.F32[PM_PAR_YPOS]);
+
+            for (int i = 0; i < psf->params->n; i++) {
+                if (psf->params->data[i] == NULL) {
+		    psFree(modelPSF);
+		    continue;
+		}
+                fprintf (f, "%f %f : ", source->modelEXT->params->data.F32[i], modelPSF->params->data.F32[i]);
+            }
+            fprintf (f, "%f %d\n", source->modelEXT->chisq, source->modelEXT->nIter);
+
+            psFree(modelPSF);
+        }
+        fclose (f);
+    }
+
+    psFree (x);
+    psFree (y);
+    psFree (z);
+    return true;
+}
+
+// fit the shape parameters using the supplied order (pmPSF->trendNx,trendNy)
+bool pmPSFFitShapeParams (pmPSF *psf, psArray *sources, psVector *x, psVector *y, psVector *srcMask) {
+
+    // we are doing a robust fit.  after each pass, we drop points which are more deviant than
+    // three sigma.  the source mask (srcMask) is updated for each pass.  
+
+    // The shape parameters (SXX, SXY, SYY) are strongly coupled.  We have to handle them very
+    // carefully.  First, we convert them to the Ellipse Polarization terms (E0, E1, E2) for
+    // each source and fit this set of parameters.  These values are less tightly coupled, but
+    // are still inter-related.  The fitted values do a good job of constraining the major axis
+    // and the position angle, but the minor axis is weakly measured.  When we apply the PSF
+    // model to construct a source model, we convert the fitted values of E0,E1,E2 to the shape
+    // parameters, with the constraint that the minor axis must be greater than a minimum
+    // threshold.
+
+    // XXX re-read the sextractor manual on handling 'infinitely thin' sources...
+
+    // storage vectors for the polarization terms & mags
+    psVector *e0   = psVectorAlloc (sources->n, PS_TYPE_F32);
+    psVector *e1   = psVectorAlloc (sources->n, PS_TYPE_F32);
+    psVector *e2   = psVectorAlloc (sources->n, PS_TYPE_F32);
+
+    // convert the measured source shape paramters to polarization terms
+    for (int i = 0; i < sources->n; i++) {
+        // skip any masked sources (failed to fit one of the model steps or get a magnitude)
+        if (srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue;
+
+        pmSource *source = sources->data[i];
+        assert (source->modelEXT); // all unmasked sources should have modelEXT
+
+        psEllipsePol pol = pmPSF_ModelToFit (source->modelEXT->params->data.F32);
+
+        e0->data.F32[i] = pol.e0;
+        e1->data.F32[i] = pol.e1;
+        e2->data.F32[i] = pol.e2;
+    }
+
+    // we run 'clipIter' cycles clipping in each of x and y, with only one iteration each.
+    // This way, the parameters masked by one of the fits will be applied to the others
+    // NOTE : trend->stats (below) points to the same data as psfTrendStats; set the value to 1
+    // to limit the iteration within the loop
+    int nIter = psf->psfTrendStats->clipIter;
+    psf->psfTrendStats->clipIter = 1;
+    for (int i = 0; i < nIter; i++) {
+	// XXX we are using the same stats structure on each pass: do we need to re-init it?
+	// XXX we hardwire this to SAMPLE stats above (psphotChoosePSF.c), hardwire here instead?
+	psStatsOptions meanOption = psStatsMeanOption(psf->psfTrendStats->options);
+	psStatsOptions stdevOption = psStatsStdevOption(psf->psfTrendStats->options);
+
+	pmTrend2D *trend = NULL;
+	float mean, stdev;
+
+	// XXX we are using the same stats structure on each pass: do we need to re-init it?
+	bool status = true;
+
+	trend = psf->params->data[PM_PAR_E0];
+	trend->stats->clipIter = 1; // in allocation, this value is set to the value of nIter, but we should use 1 here
+	status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e0, NULL);
+	mean = psStatsGetValue (trend->stats, meanOption);
+	stdev = psStatsGetValue (trend->stats, stdevOption);
+	psTrace ("psModules.objects", 4, "clipped E0 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e0->n);
+        if (psf->psfTrendMode == PM_TREND_MAP) psImageMapCleanup (trend->map);
+	pmSourceVisualPSFModelResid (trend, x, y, e0, srcMask);
+
+	trend = psf->params->data[PM_PAR_E1];
+	trend->stats->clipIter = 1; // in allocation, this value is set to the value of nIter, but we should use 1 here
+	status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e1, NULL);
+	mean = psStatsGetValue (trend->stats, meanOption);
+	stdev = psStatsGetValue (trend->stats, stdevOption);
+	psTrace ("psModules.objects", 4, "clipped E1 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e1->n);
+        if (psf->psfTrendMode == PM_TREND_MAP) psImageMapCleanup (trend->map);
+	pmSourceVisualPSFModelResid (trend, x, y, e1, srcMask);
+
+	trend = psf->params->data[PM_PAR_E2];
+	trend->stats->clipIter = 1; // in allocation, this value is set to the value of nIter, but we should use 1 here
+	status &= pmTrend2DFit (trend, srcMask, 0xff, x, y, e2, NULL);
+	mean = psStatsGetValue (trend->stats, meanOption);
+	stdev = psStatsGetValue (trend->stats, stdevOption);
+	psTrace ("psModules.objects", 4, "clipped E2 : %f +/- %f keeping %ld of %ld\n", mean, stdev, psf->psfTrendStats->clippedNvalues, e2->n);
+        if (psf->psfTrendMode == PM_TREND_MAP) psImageMapCleanup (trend->map);
+	pmSourceVisualPSFModelResid (trend, x, y, e2, srcMask);
+
+	if (!status) {
+	    psError (PS_ERR_UNKNOWN, true, "failed to fit PSF shape params");
+	    return false;
+	}
+    }
+    psf->psfTrendStats->clipIter = nIter;
+
+    // test dump of the psf parameters
+    if (psTraceGetLevel("psModules.objects") >= 4) {
+        FILE *f = fopen ("pol.dat", "w");
+        fprintf (f, "# x y  :  e0obs e1obs e2obs  : e0fit e1fit e2fit : mask\n");
+        for (int i = 0; i < e0->n; i++) {
+            fprintf (f, "%f %f  :  %f %f %f  : %f %f %f  : %d\n",
+                     x->data.F32[i], y->data.F32[i],
+                     e0->data.F32[i], e1->data.F32[i], e2->data.F32[i],
+                     pmTrend2DEval (psf->params->data[PM_PAR_E0], x->data.F32[i], y->data.F32[i]),
+                     pmTrend2DEval (psf->params->data[PM_PAR_E1], x->data.F32[i], y->data.F32[i]),
+                     pmTrend2DEval (psf->params->data[PM_PAR_E2], x->data.F32[i], y->data.F32[i]),
+                     srcMask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
+        }
+        fclose (f);
+    }
+
+    psFree (e0);
+    psFree (e1);
+    psFree (e2);
+    return true;
+}
+
Index: branches/eam_branches/20090820/psModules/src/objects/pmPSFtryMetric.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPSFtryMetric.c	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPSFtryMetric.c	(revision 25766)
@@ -0,0 +1,84 @@
+/** @file  pmPSFtry.c
+ *  @brief: measure the systematic error in the aperture-psf magnitude
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.69 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-01-27 06:39:38 $
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+# include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "pmSpan.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmTrend2D.h"
+#include "pmPSF.h"
+#include "pmModel.h"
+#include "pmSource.h"
+#include "pmSourceUtils.h"
+#include "pmPSFtry.h"
+#include "pmModelClass.h"
+#include "pmModelUtils.h"
+#include "pmSourceFitModel.h"
+#include "pmSourcePhotometry.h"
+#include "pmSourceVisual.h"
+
+// The quality of the PSF model is determined by the systematic scatter in the fit - aperture
+// magnitude.  We use the moments->Sum value, calculated with a Gaussian window, as a proxy for
+// the aperture magnitude.  We measure the systmatic scatter with the function
+// psVectorSystematicError which solves for the value of SysErr that needs to be added in
+// quadrature to the errors of a set of residual measurements in order to yield a ChiSq of 1.0.
+bool pmPSFtryMetric (pmPSFtry *psfTry)
+{
+    PS_ASSERT_PTR_NON_NULL(psfTry, false);
+    PS_ASSERT_PTR_NON_NULL(psfTry->sources, false);
+
+    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
+
+    if (!psVectorStats (stats, psfTry->metric, NULL, psfTry->mask, PSFTRY_MASK_ALL)) {
+        psError(PS_ERR_UNKNOWN, false, "Failed to measured clipped mean");
+	psFree (stats);
+        return false;
+    }
+
+    // generate a residual vector
+    psVector *resid = psVectorAllocEmpty (psfTry->metric->n, PS_TYPE_F32);
+    psVector *error = psVectorAllocEmpty (psfTry->metric->n, PS_TYPE_F32);
+    int n = 0;
+    for (int i = 0; i < psfTry->metric->n; i++) {
+	if (psfTry->mask && (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] && PSFTRY_MASK_ALL)) continue;
+	// if (psfTry->metricErr->data.F32[i] > 0.005) continue;
+	resid->data.F32[n] = psfTry->metric->data.F32[i] - stats->sampleMedian;
+	error->data.F32[n] = psfTry->metricErr->data.F32[i];
+	n++;
+    }
+    resid->n = error->n = n;
+
+    float psfSysErr = psVectorSystematicError (resid, error, 0.05);
+
+    psLogMsg ("pmPSFtryMetric", 4, "apresid: %f +/- %f (systematic error) from statistics of %ld psf stars (%d used)\n", 
+	      stats->sampleMedian, psfSysErr, psfTry->sources->n, n);
+
+    psfTry->psf->ApResid  = stats->sampleMedian;
+    psfTry->psf->dApResid = psfSysErr;
+
+    pmSourceVisualPlotPSFMetric (psfTry);
+
+    psFree (stats);
+    psFree (resid);
+    psFree (error);
+
+    return true;
+}
Index: branches/eam_branches/20090820/psModules/src/objects/pmPSFtryModel.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPSFtryModel.c	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPSFtryModel.c	(revision 25766)
@@ -0,0 +1,214 @@
+/** @file  pmPSFtry.c
+ *
+ *  XXX: need description of file purpose
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.69 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-01-27 06:39:38 $
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+# include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "pmSpan.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmTrend2D.h"
+#include "pmPSF.h"
+#include "pmModel.h"
+#include "pmSource.h"
+#include "pmSourceUtils.h"
+#include "pmPSFtry.h"
+#include "pmModelClass.h"
+#include "pmModelUtils.h"
+#include "pmSourceFitModel.h"
+#include "pmSourcePhotometry.h"
+#include "pmSourceVisual.h"
+
+// build a pmPSFtry for the given model:
+// - fit each source with the free-floating model
+// - construct the pmPSF from the collection of models
+// - fit each source with the PSF-parameter models
+// - measure the pmPSF quality metric (dApResid)
+
+// sources used in for pmPSFtry may be masked by the analysis
+// mask values indicate the reason the source was rejected:
+
+// generate a pmPSFtry with a copy of the test PSF sources
+pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal)
+{
+    // validate the requested model name
+    options->type = pmModelClassGetType (modelName);
+    if (options->type == -1) {
+        psError (PS_ERR_UNKNOWN, true, "invalid model name %s", modelName);
+        return NULL;
+    }
+
+    pmPSFtry *psfTry = pmPSFtryAlloc (sources, options);
+    if (psfTry == NULL) {
+        psError (PS_ERR_UNKNOWN, false, "failed to allocate psf model");
+        return NULL;
+    }
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
+    // stage 1:  fit an EXT model to all candidates PSF sources -- this is independent of the modeled 2D variations in the PSF
+    if (!pmPSFtryFitEXT(psfTry, options, maskVal, markVal)) {
+        psError(PS_ERR_UNKNOWN, false, "failed to fit EXT models to sources for psf model");
+        psFree(psfTry);
+        return NULL;
+    }      
+
+    int orderMin = (options->psfTrendMode == PM_TREND_MAP) ? 1 : 0;
+    int orderMax = PS_MAX (options->psfTrendNx, options->psfTrendNy);
+
+    // XXX set the min number of needed source more carefully (depends on psfTrendMode?)
+    if ((sources->n < 15) && (orderMax >= 3)) orderMax = 2;
+    if ((sources->n < 11) && (orderMax >= 2)) orderMax = 1;
+    if ((sources->n <  8) && (orderMax >= 1)) orderMax = 0;
+    if ((sources->n <  3)) {
+	psError (PS_ERR_UNKNOWN, true, "failed to determine PSF parameters");
+	return NULL;
+    }
+
+    // save the raw source mask (generated by pmPSFtryFitEXT)
+    psVector *srcMask = psVectorCopy (NULL, psfTry->mask, PS_TYPE_VECTOR_MASK);
+
+    // we will save the PSF with the best fit (min systematic error) 
+    pmPSF *minPSF = NULL;
+    psVector *minMask = NULL;
+
+    // as we loop over orders, we need to refer to the initial selection, but we modify the
+    // option values to match the current guess: save the max values here:
+    int Nx = options->psfTrendNx;
+    int Ny = options->psfTrendNy;
+    for (int i = orderMin; i <= orderMax; i++) {
+	
+	if (Nx > Ny) {
+	    options->psfTrendNx = i;
+	    options->psfTrendNy = PS_MAX (orderMin, (int)(i * (Ny / Nx) + 0.5));
+	} else {
+	    options->psfTrendNy = i;
+	    options->psfTrendNx = PS_MAX (orderMin, (int)(i * (Nx / Ny) + 0.5));
+	}
+
+	// free existing data, if any
+	psFree(psfTry->psf);
+	psFree(psfTry->mask);
+
+	// allocate a mask and a psf model using the current Nx,Ny order values;
+	psfTry->psf = pmPSFAlloc (options);
+	psfTry->mask = psVectorCopy (NULL, srcMask, PS_TYPE_VECTOR_MASK);
+
+	// stage 2: construct a psf (pmPSF) from this collection of model fits, including the 2D variation
+	if (!pmPSFtryMakePSF (psfTry)) {
+	    psError(PS_ERR_UNKNOWN, false, "failed to construct a psf model from collection of sources");
+	    psFree(psfTry);
+	    return NULL;
+	}
+
+	// stage 3: refit with fixed shape parameters, measure pmPSFtry->metric
+	if (!pmPSFtryFitPSF (psfTry, options, maskVal, markVal)) {
+	    psError(PS_ERR_UNKNOWN, false, "failed to construct a psf model from collection of sources");
+	    psFree(psfTry);
+	    return NULL;
+	}
+
+	// stage 4: measure systematic error in pmPSFtry->metric
+	if (!pmPSFtryMetric (psfTry)) {
+	    psError(PS_ERR_UNKNOWN, false, "failed to measure systematic error of metric");
+	    psFree(psfTry);
+	    return NULL;
+	}
+
+	if (!minPSF) {
+	    minPSF = psMemIncrRefCounter(psfTry->psf);
+	    minMask = psMemIncrRefCounter(psfTry->mask);
+	}
+
+	if (psfTry->psf->dApResid < minPSF->dApResid) {
+	    psFree (minPSF);
+	    psFree (minMask);
+	    minPSF = psMemIncrRefCounter(psfTry->psf);
+	    minMask = psMemIncrRefCounter(psfTry->mask);
+	}
+    }
+    psFree (srcMask);
+
+    // keep the ones matching the min systematic error:
+    psFree (psfTry->psf);
+    psFree (psfTry->mask);
+    psfTry->psf = minPSF;
+    psfTry->mask = minMask;
+    
+    // XXXXX this is probably not used any more.  Are the chisq of the fits so bad? can we
+    // fix them by softening the errors on the brightest pixels?
+
+    // measure the chi-square trend as a function of flux (PAR[PM_PAR_I0])
+    // this should be linear for Poisson errors and quadratic for constant sky errors
+    psVector *flux  = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
+    psVector *chisq = psVectorAlloc (psfTry->sources->n, PS_TYPE_F32);
+    psVector *mask  = psVectorAlloc (psfTry->sources->n, PS_TYPE_VECTOR_MASK);
+
+    // generate the x and y vectors, and mask missing models
+    for (int i = 0; i < psfTry->sources->n; i++) {
+        pmSource *source = psfTry->sources->data[i];
+        if (source->modelPSF == NULL) {
+            flux->data.F32[i] = 0.0;
+            chisq->data.F32[i] = 0.0;
+            mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xff;
+        } else {
+            flux->data.F32[i] = source->modelPSF->params->data.F32[PM_PAR_I0];
+            chisq->data.F32[i] = source->modelPSF->chisq / source->modelPSF->nDOF;
+            mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0;
+        }
+    }
+
+    // use 3hi/3lo sigma clipping on the chisq fit
+    psStats *stats = options->stats;
+
+    // linear clipped fit of chisq trend vs flux
+    if (options->chiFluxTrend) {
+        bool result = psVectorClipFitPolynomial1D(psfTry->psf->ChiTrend, options->stats,
+                                                  mask, 0xff, chisq, NULL, flux);
+        psStatsOptions meanStat = psStatsMeanOption(options->stats->options); // Statistic for mean
+        psStatsOptions stdevStat = psStatsStdevOption(options->stats->options); // Statistic for stdev
+
+        psLogMsg ("pmPSFtry", 4, "chisq vs flux fit: %f +/- %f\n",
+                  psStatsGetValue(stats, meanStat), psStatsGetValue(stats, stdevStat));
+
+        psFree(flux);
+        psFree(mask);
+        psFree(chisq);
+
+        if (!result) {
+            psError(PS_ERR_UNKNOWN, false, "Failed to fit psf->ChiTrend");
+            psFree(psfTry);
+            return NULL;
+        }
+    }
+
+    for (int i = 0; i < psfTry->psf->ChiTrend->nX + 1; i++) {
+        psLogMsg ("pmPSFtry", 4, "chisq vs flux fit term %d: %f +/- %f\n", i,
+                  psfTry->psf->ChiTrend->coeff[i]*pow(10000, i),
+                  psfTry->psf->ChiTrend->coeffErr[i]*pow(10000,i));
+    }
+
+    psLogMsg ("psphot.pspsf", 3, "try model %s, ap-fit: %f +/- %f : sky bias: %f\n",
+              modelName, psfTry->psf->ApResid, psfTry->psf->dApResid, psfTry->psf->skyBias);
+
+    return (psfTry);
+}
+
Index: branches/eam_branches/20090820/psModules/src/objects/pmPeaks.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPeaks.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPeaks.c	(revision 25766)
@@ -60,7 +60,8 @@
     // if min point is too deviant, use the peak value
     // XXX need to calculate dx, dy correctly
+    // 0.5 PIX: peaks are calculated using the pixel index and converted here to pixel coords
     if ((fabs(min.x) < 1.5) && (fabs(min.y) < 1.5)) {
-        peak->xf = min.x + ix + image->col0;
-        peak->yf = min.y + iy + image->row0;
+        peak->xf = min.x + ix + image->col0 + 0.5;
+        peak->yf = min.y + iy + image->row0 + 0.5;
 
 	// These errors are fractional errors, and should be scaled by the 
@@ -73,6 +74,6 @@
 	peak->yf = PS_MAX (PS_MIN (peak->yf, image->numRows - 1), image->row0);
     } else {
-        peak->xf = ix;
-        peak->yf = iy;
+        peak->xf = ix + 0.5;
+        peak->yf = iy + 0.5; 
 	peak->dx = NAN;
 	peak->dy = NAN;
Index: branches/eam_branches/20090820/psModules/src/objects/pmPetrosian.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPetrosian.c	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPetrosian.c	(revision 25766)
@@ -0,0 +1,107 @@
+/* @file  pmPetrosian.c
+ * low-level petrosian functions
+ *
+ * @author EAM, IfA
+ *
+ * @version $Revision: $
+ * @date $Date: $
+ * Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "pmPetrosian.h"
+
+static void pmPetrosianFree(pmPetrosian *petrosian)
+{
+    if (!petrosian) {
+        return;
+    }
+    psFree(petrosian->radii);
+    psFree(petrosian->fluxes);
+    psFree(petrosian->theta);
+    psFree(petrosian->isophotalRadii);
+
+    psFree(petrosian->radiusElliptical);
+    psFree(petrosian->fluxElliptical);
+
+    psFree(petrosian->binSB);
+    psFree(petrosian->binSBstdev);
+    psFree(petrosian->radialBins);
+    psFree(petrosian->area);
+}
+
+pmPetrosian *pmPetrosianAlloc()
+{
+    pmPetrosian *petrosian = (pmPetrosian *)psAlloc(sizeof(pmPetrosian));
+    psMemSetDeallocator(petrosian, (psFreeFunc) pmPetrosianFree);
+
+    petrosian->radii = NULL;
+    petrosian->fluxes = NULL;
+    petrosian->theta = NULL;
+    petrosian->isophotalRadii = NULL;
+
+    petrosian->radiusElliptical = NULL;
+    petrosian->fluxElliptical = NULL;
+
+    petrosian->radialBins = NULL;
+    petrosian->area = NULL;
+    petrosian->binSB = NULL;
+    petrosian->binSBstdev = NULL;
+
+    petrosian->petrosianRadius = NAN;
+    petrosian->petrosianFlux = NAN;
+
+    // petrosian->axes = {0.0, 0.0, 0.0};
+
+    return petrosian;
+}
+
+bool pmPetrosianFreeVectors(pmPetrosian *petrosian) {
+
+    psFree(petrosian->radii);
+    psFree(petrosian->fluxes);
+    psFree(petrosian->theta);
+    psFree(petrosian->isophotalRadii);
+
+    psFree(petrosian->radiusElliptical);
+    psFree(petrosian->fluxElliptical);
+
+    psFree(petrosian->binSB);
+    psFree(petrosian->binSBstdev);
+    psFree(petrosian->radialBins);
+    psFree(petrosian->area);
+
+    petrosian->radii = NULL;
+    petrosian->fluxes = NULL;
+    petrosian->theta = NULL;
+    petrosian->isophotalRadii = NULL;
+
+    petrosian->radiusElliptical = NULL;
+    petrosian->fluxElliptical = NULL;
+
+    petrosian->radialBins = NULL;
+    petrosian->area = NULL;
+    petrosian->binSB = NULL;
+    petrosian->binSBstdev = NULL;
+    
+    return true;
+}
+
+# define COMPARE_INDEX(A,B) (index->data.F32[A] < index->data.F32[B])
+# define SWAP_INDEX(TYPE,A,B) { \
+  float tmp; \
+  if (A != B) { \
+    tmp = index->data.F32[A]; \
+    index->data.F32[A] = index->data.F32[B]; \
+    index->data.F32[B] = tmp; \
+    tmp = extra->data.F32[A]; \
+    extra->data.F32[A] = extra->data.F32[B]; \
+    extra->data.F32[B] = tmp; \
+  } \
+}
+
+bool pmPetrosianSortPair (psVector *index, psVector *extra) {
+
+    // sort the vector set by the radius
+    PSSORT (index->n, COMPARE_INDEX, SWAP_INDEX, NONE);
+    return true;
+}
Index: branches/eam_branches/20090820/psModules/src/objects/pmPetrosian.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmPetrosian.h	(revision 25766)
+++ branches/eam_branches/20090820/psModules/src/objects/pmPetrosian.h	(revision 25766)
@@ -0,0 +1,44 @@
+/* @file  pmPetrosian.h
+ *
+ * @author EAM, IfA
+ *
+ * @version $Revision: $
+ * @date $Date: $
+ * Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef PM_PETROSIAN_H
+#define PM_PETROSIAN_H
+
+/// @addtogroup Objects Object Detection / Analysis Functions
+/// @{
+
+typedef struct {
+    psArray  *radii;			// radii for raw radial profiles at evenly-spaced angles
+    psArray  *fluxes;			// fluxes measured at above radii
+    psVector *theta;			// angles corresponding to above radial profiles
+    psVector *isophotalRadii;		// isophotal radius for the above angles
+
+    psVector *radiusElliptical;		// normalized radial coordinates for all relevant pixels
+    psVector *fluxElliptical;		// flux for the above radial coordinates
+
+    psVector *binSB;			// mean surface brightness within radial bins
+    psVector *binSBstdev;		// scatter of mean surface brightness within radial bins
+    psVector *radialBins;		// radii corresponding to above binnedBlux
+    psVector *area;			// differential area of the non-overlapping radial bins
+
+    psEllipseAxes axes;			// shape of elliptical contour
+
+    float petrosianRadius;
+    float petrosianFlux;
+
+} pmPetrosian;
+
+pmPetrosian *pmPetrosianAlloc();
+
+bool pmPetrosianFreeVectors(pmPetrosian *petrosian);
+bool pmPetrosianSortPair (psVector *index, psVector *extra);
+
+/// @}
+
+# endif /* PM_PETROSIAN_H */
Index: branches/eam_branches/20090820/psModules/src/objects/pmSource.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSource.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSource.c	(revision 25766)
@@ -282,6 +282,6 @@
 
     psArray *peaks  = NULL;
-    pmPSFClump errorClump = {-1.0, -1.0, 0.0, 0.0};
-    pmPSFClump emptyClump = {+0.0, +0.0, 0.0, 0.0};
+    pmPSFClump errorClump = {-1.0, -1.0, 0.0, 0.0, 0, 0.0};
+    pmPSFClump emptyClump = {+0.0, +0.0, 0.0, 0.0, 0, 0.0};
     pmPSFClump psfClump;
 
@@ -319,5 +319,6 @@
 
         // construct a sigma-plane image
-        int numCols = SX_MAX / PSF_CLUMP_GRID_SCALE, numRows = SY_MAX / PSF_CLUMP_GRID_SCALE; // Size of sigma-plane image
+        int numCols = 1 + SX_MAX / PSF_CLUMP_GRID_SCALE; // Size of sigma-plane image
+	int numRows = 1 + SY_MAX / PSF_CLUMP_GRID_SCALE; // Size of sigma-plane image
         psTrace("psModules.objects", 10, "sigma-plane dimensions: %dx%d\n", numCols, numRows);
         psImage *splane = psImageAlloc(numCols, numRows, PS_TYPE_F32); // sigma-plane image
@@ -332,12 +333,16 @@
             }
 
-            int x = src->peak->x, y = src->peak->y; // Coordinates of peak
-            if (x < region->x0 || x > region->x1 || y < region->y0 || y > region->y1) {
-                continue;
-            }
+	    if (region) {
+		int x = src->peak->x, y = src->peak->y; // Coordinates of peak
+		if (x < region->x0 || x > region->x1 || y < region->y0 || y > region->y1) {
+		    continue;
+		}
+	    }
 
             if (src->mode & PM_SOURCE_MODE_BLEND) {
                 continue;
             }
+
+            if (!src->moments->nPixels) continue;
 
             if (src->moments->SN < PSF_SN_LIM) {
@@ -384,5 +389,5 @@
 
         // find the peak in this image
-        psStats *stats = psStatsAlloc (PS_STAT_MAX);
+        psStats *stats = psStatsAlloc (PS_STAT_MAX | PS_STAT_SAMPLE_STDEV);
         if (!psImageStats (stats, splane, NULL, 0)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n");
@@ -393,4 +398,6 @@
         peaks = pmPeaksInImage (splane, stats[0].max / 2);
         psTrace ("psModules.objects", 2, "clump threshold is %f\n", stats[0].max/2);
+
+	psfClump.nSigma = stats->sampleStdev;
 
         const bool keep_psf_clump = psMetadataLookupBool(NULL, recipe, "KEEP_PSF_CLUMP");
@@ -430,4 +437,9 @@
         psTrace ("psModules.objects", 2, "clump is at %d, %d (%f)\n", clump->x, clump->y, clump->value);
 
+	// XXX store the mean sigma?
+	float meanSigma = psfClump.nSigma;
+	psfClump.nStars = clump->value;
+	psfClump.nSigma = clump->value / meanSigma;
+
         // define section window for clump
         minSx = clump->x * PSF_CLUMP_GRID_SCALE - 2.0*PSF_CLUMP_GRID_SCALE;
@@ -452,8 +464,10 @@
                 continue;
 
-            if (tmpSrc->peak->x < region->x0) continue;
-            if (tmpSrc->peak->x > region->x1) continue;
-            if (tmpSrc->peak->y < region->y0) continue;
-            if (tmpSrc->peak->y > region->y1) continue;
+	    if (region) {
+		if (tmpSrc->peak->x < region->x0) continue;
+		if (tmpSrc->peak->x > region->x1) continue;
+		if (tmpSrc->peak->y < region->y0) continue;
+		if (tmpSrc->peak->y > region->y1) continue;
+	    }
 
             if (tmpSrc->moments->Mxx < minSx)
@@ -919,4 +933,6 @@
     if (model == NULL) return false;  // model must be defined
 
+    bool addNoise = mode & PM_MODEL_OP_NOISE;
+
     if (source->modelFlux) {
         // add in the pixels from the modelFlux image
@@ -940,10 +956,9 @@
 
         psF32 **target = source->pixels->data.F32;
-        if (mode & PM_MODEL_OP_NOISE) {
-            // XXX need to scale by the gain...
+        if (addNoise) {
+	    // when adding noise, we assume the shape and Io have been modified
             target = source->variance->data.F32;
         }
 
-        // XXX need to respect the source and model masks?
         for (int iy = 0; iy < source->modelFlux->numRows; iy++) {
             int oy = iy + dY;
@@ -959,16 +974,27 @@
             }
         }
+	if (!addNoise) {
+	    if (add) {
+		source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
+	    } else {
+		source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
+	    }
+	}
         return true;
     }
 
     psImage *target = source->pixels;
-    if (mode & PM_MODEL_OP_NOISE) {
+    if (addNoise) {
         target = source->variance;
     }
 
-    if (add) {
-        status = pmModelAddWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
-    } else {
-        status = pmModelSubWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
+    if (!addNoise) {
+	if (add) {
+	    status = pmModelAddWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
+	    source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
+	} else {
+	    status = pmModelSubWithOffset (target, source->maskObj, model, PM_MODEL_OP_FULL, maskVal, dx, dy);
+	    source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
+	}
     }
 
Index: branches/eam_branches/20090820/psModules/src/objects/pmSource.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSource.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSource.h	(revision 25766)
@@ -38,6 +38,7 @@
 
 typedef enum {
-    PM_SOURCE_TMPF_MODEL_GUESS = 0x0001,
-    PM_SOURCE_TMPF_SUBTRACTED  = 0x0002,
+    PM_SOURCE_TMPF_MODEL_GUESS   = 0x0001,
+    PM_SOURCE_TMPF_SUBTRACTED    = 0x0002,
+    PM_SOURCE_TMPF_SIZE_MEASURED = 0x0004,
 } pmSourceTmpF;
 
@@ -81,4 +82,5 @@
     float extNsigma;                    ///< Nsigma deviation from PSF to EXT
     float sky, skyErr;                  ///< The sky and its error at the center of the object
+    float apRadius;
     psRegion region;                    ///< area on image covered by selected pixels
     pmSourceExtendedPars *extpars;      ///< extended source parameters
@@ -98,4 +100,6 @@
     float Y;
     float dY;
+    int nStars;
+    float nSigma;
 }
 pmPSFClump;
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceExtendedPars.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceExtendedPars.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceExtendedPars.c	(revision 25766)
@@ -17,30 +17,140 @@
 #endif
 
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
+// #include <stdio.h>
+// #include <math.h>
+// #include <string.h>
 #include <pslib.h>
-#include "pmHDU.h"
-#include "pmFPA.h"
-#include "pmFPAMaskWeight.h"
-#include "pmSpan.h"
-#include "pmFootprint.h"
-#include "pmPeaks.h"
-#include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-
+// #include "pmHDU.h"
+// #include "pmFPA.h"
+// #include "pmFPAMaskWeight.h"
+// #include "pmSpan.h"
+// #include "pmFootprint.h"
+// #include "pmPeaks.h"
+// #include "pmMoments.h"
+// #include "pmResiduals.h"
+// #include "pmGrowthCurve.h"
+// #include "pmTrend2D.h"
+// #include "pmPSF.h"
+// #include "pmModel.h"
+// #include "pmSource.h"
+#include "pmSourceExtendedPars.h"
+
+// *** pmSourceRadialProfile describes the radial profile of a source in elliptical contours, and 
+// intermediate data used to measure the profile
+static void pmSourceRadialProfileFree(pmSourceRadialProfile *profile)
+{
+    if (!profile) {
+        return;
+    }
+    psFree(profile->radii);
+    psFree(profile->fluxes);
+    psFree(profile->theta);
+    psFree(profile->isophotalRadii);
+
+    psFree(profile->radiusElliptical);
+    psFree(profile->fluxElliptical);
+
+    psFree(profile->binSB);
+    psFree(profile->binSBstdev);
+    psFree(profile->binSBerror);
+
+    psFree(profile->radialBins);
+    psFree(profile->area);
+}
+
+pmSourceRadialProfile *pmSourceRadialProfileAlloc()
+{
+    pmSourceRadialProfile *profile = (pmSourceRadialProfile *)psAlloc(sizeof(pmSourceRadialProfile));
+    psMemSetDeallocator(profile, (psFreeFunc) pmSourceRadialProfileFree);
+
+    profile->radii = NULL;
+    profile->fluxes = NULL;
+    profile->theta = NULL;
+    profile->isophotalRadii = NULL;
+
+    profile->radiusElliptical = NULL;
+    profile->fluxElliptical = NULL;
+
+    profile->binSB = NULL;
+    profile->binSBstdev = NULL;
+    profile->binSBerror = NULL;
+
+    profile->radialBins = NULL;
+    profile->area = NULL;
+
+    return profile;
+}
+
+bool psMemCheckSourceRadialProfile(psPtr ptr)
+{
+    PS_ASSERT_PTR(ptr, false);
+    return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceRadialProfileFree);
+}
+
+
+// *** pmSourceRadialProfileFreeVectors frees the intermediate data values
+bool pmSourceRadialProfileFreeVectors(pmSourceRadialProfile *profile) {
+
+    psFree(profile->radii);
+    psFree(profile->fluxes);
+    psFree(profile->theta);
+    psFree(profile->isophotalRadii);
+
+    psFree(profile->radiusElliptical);
+    psFree(profile->fluxElliptical);
+
+    // psFree(profile->binSB);
+    // psFree(profile->binSBstdev);
+    // psFree(profile->binSBerror);
+    
+    // psFree(profile->radialBins);
+    psFree(profile->area);
+
+    profile->radii = NULL;
+    profile->fluxes = NULL;
+    profile->theta = NULL;
+    profile->isophotalRadii = NULL;
+
+    profile->radiusElliptical = NULL;
+    profile->fluxElliptical = NULL;
+
+    // profile->binSB = NULL;
+    // profile->binSBstdev = NULL;
+    // profile->binSBerror = NULL;
+    
+    // profile->radialBins = NULL;
+    profile->area = NULL;
+
+    return true;
+}
+
+// *** pmSourceRadialProfileSortPair is a utility function for sorting a pair of vectors
+# define COMPARE_INDEX(A,B) (index->data.F32[A] < index->data.F32[B])
+# define SWAP_INDEX(TYPE,A,B) { \
+  float tmp; \
+  if (A != B) { \
+    tmp = index->data.F32[A]; \
+    index->data.F32[A] = index->data.F32[B]; \
+    index->data.F32[B] = tmp; \
+    tmp = extra->data.F32[A]; \
+    extra->data.F32[A] = extra->data.F32[B]; \
+    extra->data.F32[B] = tmp; \
+  } \
+}
+
+bool pmSourceRadialProfileSortPair (psVector *index, psVector *extra) {
+
+    // sort the vector set by the radius
+    PSSORT (index->n, COMPARE_INDEX, SWAP_INDEX, NONE);
+    return true;
+}
+
+// *** pmSourceExtendedPars describes the possible collection of extended flux measurements for a source
 static void pmSourceExtendedParsFree (pmSourceExtendedPars *pars) {
     if (!pars) return;
 
     psFree(pars->profile);
-    psFree(pars->annuli);
-    psFree(pars->isophot);
-    psFree(pars->petrosian);
-    psFree(pars->kron);
+    psFree(pars->petrosian_50);
+    psFree(pars->petrosian_80);
     return;
 }
@@ -51,8 +161,6 @@
 
     pars->profile = NULL;
-    pars->annuli = NULL;
-    pars->isophot = NULL;
-    pars->petrosian = NULL;
-    pars->kron = NULL;
+    pars->petrosian_50 = NULL;
+    pars->petrosian_80 = NULL;
 
     return pars;
@@ -66,135 +174,27 @@
 
 
-static void pmSourceRadialProfileFree (pmSourceRadialProfile *profile) {
-    if (!profile) return;
-
-    psFree(profile->radius);
-    psFree(profile->flux);
-    psFree(profile->variance);
+// *** pmSourceExtendedFlux describes the flux within an elliptical aperture of some kind 
+static void pmSourceExtendedFluxFree (pmSourceExtendedFlux *flux) {
+    if (!flux) return;
     return;
 }
 
-pmSourceRadialProfile *pmSourceRadialProfileAlloc (void) {
-
-    pmSourceRadialProfile *profile = (pmSourceRadialProfile *) psAlloc(sizeof(pmSourceRadialProfile));
-    psMemSetDeallocator(profile, (psFreeFunc) pmSourceRadialProfileFree);
-
-    profile->radius = NULL;
-    profile->flux = NULL;
-    profile->variance = NULL;
-
-    return profile;
-}
-
-bool psMemCheckSourceRadialProfile(psPtr ptr)
+pmSourceExtendedFlux *pmSourceExtendedFluxAlloc (void) {
+
+    pmSourceExtendedFlux *flux = (pmSourceExtendedFlux *) psAlloc(sizeof(pmSourceExtendedFlux));
+    psMemSetDeallocator(flux, (psFreeFunc) pmSourceExtendedFluxFree);
+
+    flux->flux = 0.0;
+    flux->fluxErr = 0.0;
+    flux->radius = 0.0;
+    flux->radiusErr = 0.0;
+
+    return flux;
+}
+
+
+bool psMemCheckSourceExtendedFlux(psPtr ptr)
 {
     PS_ASSERT_PTR(ptr, false);
-    return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceRadialProfileFree);
-}
-
-
-static void pmSourceIsophotalValuesFree (pmSourceIsophotalValues *isophot) {
-    if (!isophot) return;
-    return;
-}
-
-pmSourceIsophotalValues *pmSourceIsophotalValuesAlloc (void) {
-
-    pmSourceIsophotalValues *isophot = (pmSourceIsophotalValues *) psAlloc(sizeof(pmSourceIsophotalValues));
-    psMemSetDeallocator(isophot, (psFreeFunc) pmSourceIsophotalValuesFree);
-
-    isophot->mag = 0.0;
-    isophot->magErr = 0.0;
-    isophot->rad = 0.0;
-    isophot->radErr = 0.0;
-
-    return isophot;
-}
-
-
-bool psMemCheckSourceIsophotalValues(psPtr ptr)
-{
-    PS_ASSERT_PTR(ptr, false);
-    return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceIsophotalValuesFree);
-}
-
-
-static void pmSourcePetrosianValuesFree (pmSourcePetrosianValues *petrosian) {
-    if (!petrosian) return;
-    return;
-}
-
-pmSourcePetrosianValues *pmSourcePetrosianValuesAlloc (void) {
-
-    pmSourcePetrosianValues *petrosian = (pmSourcePetrosianValues *) psAlloc(sizeof(pmSourcePetrosianValues));
-    psMemSetDeallocator(petrosian, (psFreeFunc) pmSourcePetrosianValuesFree);
-
-    petrosian->mag = 0.0;
-    petrosian->magErr = 0.0;
-    petrosian->rad = 0.0;
-    petrosian->radErr = 0.0;
-
-    return petrosian;
-}
-
-
-bool psMemCheckSourcePetrosianValues(psPtr ptr)
-{
-    PS_ASSERT_PTR(ptr, false);
-    return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourcePetrosianValuesFree);
-}
-
-static void pmSourceKronValuesFree (pmSourceKronValues *kron) {
-    if (!kron) return;
-    return;
-}
-
-pmSourceKronValues *pmSourceKronValuesAlloc (void) {
-
-    pmSourceKronValues *kron = (pmSourceKronValues *) psAlloc(sizeof(pmSourceKronValues));
-    psMemSetDeallocator(kron, (psFreeFunc) pmSourceKronValuesFree);
-
-    kron->mag = 0.0;
-    kron->magErr = 0.0;
-    kron->rad = 0.0;
-    kron->radErr = 0.0;
-
-    return kron;
-}
-
-
-bool psMemCheckSourceKronValues(psPtr ptr)
-{
-    PS_ASSERT_PTR(ptr, false);
-    return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceKronValuesFree);
-}
-
-
-static void pmSourceAnnuliFree (pmSourceAnnuli *annuli) {
-    if (!annuli) return;
-
-    psFree (annuli->flux);
-    psFree (annuli->fluxErr);
-    psFree (annuli->fluxVar);
-
-    return;
-}
-
-pmSourceAnnuli *pmSourceAnnuliAlloc (void) {
-
-    pmSourceAnnuli *annuli = (pmSourceAnnuli *) psAlloc(sizeof(pmSourceAnnuli));
-    psMemSetDeallocator(annuli, (psFreeFunc) pmSourceAnnuliFree);
-
-    annuli->flux = NULL;
-    annuli->fluxErr = NULL;
-    annuli->fluxVar = NULL;
-
-    return annuli;
-}
-
-
-bool psMemCheckSourceAnnuli(psPtr ptr)
-{
-    PS_ASSERT_PTR(ptr, false);
-    return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceAnnuliFree);
-}
+    return ( psMemGetDeallocator(ptr) == (psFreeFunc) pmSourceExtendedFluxFree);
+}
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceExtendedPars.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceExtendedPars.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceExtendedPars.h	(revision 25766)
@@ -15,56 +15,53 @@
 
 typedef struct {
-  psVector *radius;
-  psVector *flux;
-  psVector *variance;
+    psArray  *radii;			// radii for raw radial profiles at evenly-spaced angles
+    psArray  *fluxes;			// fluxes measured at above radii
+    psVector *theta;			// angles corresponding to above radial profiles
+    psVector *isophotalRadii;		// isophotal radius for the above angles
+
+    psVector *radiusElliptical;		// normalized radial coordinates for all relevant pixels
+    psVector *fluxElliptical;		// flux for the above radial coordinates
+
+    psVector *binSB;			// mean surface brightness within radial bins
+    psVector *binSBstdev;		// scatter of mean surface brightness within radial bins
+    psVector *binSBerror;		// formal error on mean surface brightness within radial bins
+
+    psVector *radialBins;		// radii corresponding to above binnedBlux
+    psVector *area;			// differential area of the non-overlapping radial bins
+
+    psEllipseAxes axes;			// shape of elliptical contour
 } pmSourceRadialProfile;
 
 typedef struct {
-  psVector *flux;
-  psVector *fluxErr;
-  psVector *fluxVar;
-} pmSourceAnnuli;
-
-typedef struct {
-  float mag;
-  float magErr;
-  float rad;
-  float radErr;
-} pmSourceIsophotalValues;
-
-typedef struct {
-  float mag;
-  float magErr;
-  float rad;
-  float radErr;
-} pmSourcePetrosianValues;
-
-typedef struct {
-  float mag;
-  float magErr;
-  float rad;
-  float radErr;
-} pmSourceKronValues;
+  float flux;
+  float fluxErr;
+  float radius;
+  float radiusErr;
+} pmSourceExtendedFlux;
 
 typedef struct {
   pmSourceRadialProfile   *profile;
-  pmSourceAnnuli          *annuli;
-  pmSourceIsophotalValues *isophot;
-  pmSourcePetrosianValues *petrosian;
-  pmSourceKronValues      *kron;
+  pmSourceExtendedFlux    *petrosian_50;
+  pmSourceExtendedFlux    *petrosian_80;
 } pmSourceExtendedPars;
 
-pmSourceExtendedPars *pmSourceExtendedParsAlloc(void);
+// *** pmSourceRadialProfile describes the radial profile of a source in elliptical contours, and 
+// intermediate data used to measure the profile
+pmSourceRadialProfile *pmSourceRadialProfileAlloc();
+bool psMemCheckSourceRadialProfile(psPtr ptr);
+
+// *** pmSourceRadialProfileFreeVectors frees the intermediate data values
+bool pmSourceRadialProfileFreeVectors(pmSourceRadialProfile *profile);
+
+// *** pmSourceExtendedPars describes the possible collection of extended flux measurements for a source
+pmSourceExtendedPars *pmSourceExtendedParsAlloc (void);
 bool psMemCheckSourceExtendedPars(psPtr ptr);
-pmSourceRadialProfile *pmSourceRadialProfileAlloc(void);
-bool psMemCheckSourceRadialProfile(psPtr ptr);
-pmSourceIsophotalValues *pmSourceIsophotalValuesAlloc(void);
-bool psMemCheckSourceIsophotalValues(psPtr ptr);
-pmSourcePetrosianValues *pmSourcePetrosianValuesAlloc(void);
-bool psMemCheckSourcePetrosianValues(psPtr ptr);
-pmSourceKronValues *pmSourceKronValuesAlloc(void);
-bool psMemCheckSourceKronValues(psPtr ptr);
-pmSourceAnnuli *pmSourceAnnuliAlloc(void);
-bool psMemCheckSourceAnnuli(psPtr ptr);
+
+// *** pmSourceExtendedFlux describes the flux within an elliptical aperture of some kind 
+pmSourceExtendedFlux *pmSourceExtendedFluxAlloc(void);
+bool psMemCheckSourceExtendedFlux(psPtr ptr);
+
+// *** pmSourceRadialProfileSortPair is a utility function for sorting a pair of vectors
+bool pmSourceRadialProfileSortPair(psVector *index, psVector *extra);
 
 /// @}
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceFitModel.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceFitModel.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceFitModel.c	(revision 25766)
@@ -96,6 +96,7 @@
 
             // Convert i/j to image space:
-            coord->data.F32[0] = (psF32) (j + source->pixels->col0);
-            coord->data.F32[1] = (psF32) (i + source->pixels->row0);
+	    // 0.5 PIX: the coordinate values must be in pixel coords, not index	    
+            coord->data.F32[0] = (psF32) (j + 0.5 + source->pixels->col0);
+            coord->data.F32[1] = (psF32) (i + 0.5 + source->pixels->row0);
             x->data[nPix] = (psPtr *) coord;
             y->data.F32[nPix] = source->pixels->data.F32[i][j];
@@ -175,7 +176,5 @@
             continue;
         dparams->data.F32[i] = sqrt(covar->data.F32[i][i]);
-        if (psTraceGetLevel("psModules.objects") >= 4) {
-            fprintf (stderr, "%f +/- %f\n", params->data.F32[i], dparams->data.F32[i]);
-        }
+        psTrace ("psModules.objects", 4, "%f +/- %f", params->data.F32[i], dparams->data.F32[i]);
     }
     psTrace ("psModules.objects", 4, "niter: %d, chisq: %f", myMin->iter, myMin->value);
@@ -186,4 +185,5 @@
     model->nPix  = y->n;
     model->nDOF  = y->n - nParams;
+    model->chisqNorm = model->chisq / model->nDOF;
     model->flags |= PM_MODEL_STATUS_FITTED;
     if (!fitStatus) model->flags |= PM_MODEL_STATUS_NONCONVERGE;
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceFitSet.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceFitSet.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceFitSet.c	(revision 25766)
@@ -321,9 +321,7 @@
 
         for (int j = 0; j < model->params->n; j++, n++) {
-            if (psTraceGetLevel("psModules.objects") >= 4) {
-                fprintf (stderr, "%f ", param->data.F32[n]);
-            }
             model->params->data.F32[j] = param->data.F32[n];
             model->dparams->data.F32[j] = dparam->data.F32[n];
+            psTrace ("psModules.objects", 4, "%f +/- %f", param->data.F32[n], dparam->data.F32[n]);
         }
         psTrace ("psModules.objects", 4, " src %d", i);
@@ -483,6 +481,7 @@
 
             // Convert i/j to image space:
-            coord->data.F32[0] = (psF32) (j + source->pixels->col0);
-            coord->data.F32[1] = (psF32) (i + source->pixels->row0);
+	    // 0.5 PIX: the coordinate values must be in pixel coords, not index	    
+            coord->data.F32[0] = (psF32) (j + 0.5 + source->pixels->col0);
+            coord->data.F32[1] = (psF32) (i + 0.5 + source->pixels->row0);
             x->data[nPix] = (psPtr *) coord;
             y->data.F32[nPix] = source->pixels->data.F32[i][j];
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceIO.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceIO.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceIO.c	(revision 25766)
@@ -42,8 +42,82 @@
 #include "pmSource.h"
 #include "pmModelClass.h"
+#include "pmDetEff.h"
 #include "pmSourceIO.h"
 
 #define BLANK_HEADERS "BLANK.HEADERS"   // Name of metadata in camera configuration containing header names
                                         // for putting values into a blank PHU
+
+// lookup the EXTNAME values used for table data and image header segments
+static bool sourceExtensions(psString *headname, // Extension name for header
+                             psString *dataname, // Extension name for data
+                             psString *deteffname, // Extension name for detection efficiency
+                             psString *xsrcname, // Extension name for extended sources
+                             psString *xfitname, // Extension name for extended fits
+                             const pmFPAfile *file, // File of interest
+                             const pmFPAview *view // View to level of interest
+                             )
+{
+    bool status;                        // Status of MD lookup
+
+    // Menu of EXTNAME rules
+    psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES");
+    if (!menu) {
+        psError(PS_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config");
+        return false;
+    }
+
+    // EXTNAME for image header
+    if (headname) {
+        const char *rule = psMetadataLookupStr(&status, menu, "CMF.HEAD");
+        if (!rule) {
+            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.HEAD in EXTNAME.RULES in camera.config");
+            return false;
+        }
+        *headname = pmFPAfileNameFromRule(rule, file, view);
+    }
+
+    // EXTNAME for table data
+    if (dataname) {
+        const char *rule = psMetadataLookupStr(&status, menu, "CMF.DATA");
+        if (!rule) {
+            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DATA in EXTNAME.RULES in camera.config");
+            return false;
+        }
+        *dataname = pmFPAfileNameFromRule(rule, file, view);
+    }
+
+    // EXTNAME for detection efficiency
+    if (deteffname) {
+        const char *rule = psMetadataLookupStr(&status, menu, "CMF.DETEFF");
+        if (!rule) {
+            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DETEFF in EXTNAME.RULES in camera.config");
+            return false;
+        }
+        *deteffname = pmFPAfileNameFromRule(rule, file, view);
+    }
+
+    // EXTNAME for extended source data table
+    if (xsrcname) {
+        const char *rule = psMetadataLookupStr(&status, menu, "CMF.XSRC");
+        if (!rule) {
+            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XSRC in EXTNAME.RULES in camera.config");
+            return false;
+        }
+        *xsrcname = pmFPAfileNameFromRule (rule, file, view);
+    }
+
+    if (xfitname) {
+        // EXTNAME for extended source data table
+        const char *rule = psMetadataLookupStr(&status, menu, "CMF.XFIT");
+        if (!rule) {
+            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XFIT in EXTNAME.RULES in camera.config");
+            return false;
+        }
+        *xfitname = pmFPAfileNameFromRule (rule, file, view);
+    }
+
+    return true;
+}
+
 
 // translations between psphot object types and dophot object types
@@ -271,8 +345,4 @@
 
     char *exttype  = NULL;
-    char *dataname = NULL;
-    char *xsrcname = NULL;
-    char *xfitname = NULL;
-    char *headname = NULL;
 
     // if sources is NULL, write out an empty table
@@ -354,49 +424,12 @@
 
         // define the EXTNAME values for the different data segments:
-        {
-            // lookup the EXTNAME values used for table data and image header segments
-            char *rule = NULL;
-
-            // Menu of EXTNAME rules
-            psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES");
-            if (!menu) {
-                psError(PS_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config");
-                return false;
-            }
-
-            // EXTNAME for image header
-            rule = psMetadataLookupStr(&status, menu, "CMF.HEAD");
-            if (!rule) {
-                psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.HEAD in EXTNAME.RULES in camera.config");
-                return false;
-            }
-            headname = pmFPAfileNameFromRule (rule, file, view);
-
-            // EXTNAME for table data
-            rule = psMetadataLookupStr(&status, menu, "CMF.DATA");
-            if (!rule) {
-                psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DATA in EXTNAME.RULES in camera.config");
-                return false;
-            }
-            dataname = pmFPAfileNameFromRule (rule, file, view);
-
-            if (XSRC_OUTPUT) {
-              // EXTNAME for extended source data table
-              rule = psMetadataLookupStr(&status, menu, "CMF.XSRC");
-              if (!rule) {
-                psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XSRC in EXTNAME.RULES in camera.config");
-                return false;
-              }
-              xsrcname = pmFPAfileNameFromRule (rule, file, view);
-            }
-            if (XFIT_OUTPUT) {
-              // EXTNAME for extended source data table
-              rule = psMetadataLookupStr(&status, menu, "CMF.XFIT");
-              if (!rule) {
-                psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XFIT in EXTNAME.RULES in camera.config");
-                return false;
-              }
-              xfitname = pmFPAfileNameFromRule (rule, file, view);
-            }
+        psString headname = NULL;
+        psString dataname = NULL;
+        psString deteffname = NULL;
+        psString xsrcname = NULL;
+        psString xfitname = NULL;
+        if (!sourceExtensions(&headname, &dataname, &deteffname, XSRC_OUTPUT ? &xsrcname : NULL,
+                              XFIT_OUTPUT ? &xfitname : NULL, file, view)) {
+            return false;
         }
 
@@ -480,49 +513,54 @@
 
             // XXX these are case-sensitive since the EXTYPE is case-sensitive
-            status = false;
+            status = true;
             if (!strcmp (exttype, "SMPDATA")) {
-                status = pmSourcesWrite_SMPDATA (file->fits, sources, file->header, outhead, dataname);
+                status &= pmSourcesWrite_SMPDATA (file->fits, sources, file->header, outhead, dataname);
             }
             if (!strcmp (exttype, "PS1_DEV_0")) {
-                status = pmSourcesWrite_PS1_DEV_0 (file->fits, sources, file->header, outhead, dataname);
+                status &= pmSourcesWrite_PS1_DEV_0 (file->fits, sources, file->header, outhead, dataname);
             }
             if (!strcmp (exttype, "PS1_DEV_1")) {
-                status = pmSourcesWrite_PS1_DEV_1 (file->fits, sources, file->header, outhead, dataname);
+                status &= pmSourcesWrite_PS1_DEV_1 (file->fits, sources, file->header, outhead, dataname);
             }
             if (!strcmp (exttype, "PS1_CAL_0")) {
-                status = pmSourcesWrite_PS1_CAL_0 (file->fits, readout, sources, file->header, outhead, dataname);
+                status &= pmSourcesWrite_PS1_CAL_0 (file->fits, readout, sources, file->header, outhead, dataname);
             }
             if (!strcmp (exttype, "PS1_V1")) {
-                status = pmSourcesWrite_CMF_PS1_V1 (file->fits, readout, sources, file->header, outhead, dataname);
+                status &= pmSourcesWrite_CMF_PS1_V1 (file->fits, readout, sources, file->header, outhead, dataname);
             }
             if (!strcmp (exttype, "PS1_V2")) {
-                status = pmSourcesWrite_CMF_PS1_V2 (file->fits, readout, sources, file->header, outhead, dataname);
-            }
+                status &= pmSourcesWrite_CMF_PS1_V2 (file->fits, readout, sources, file->header, outhead, dataname);
+            }
+
+            if (deteffname) {
+                status &= pmReadoutWriteDetEff(file->fits, readout, outhead, deteffname);
+            }
+
             if (xsrcname) {
               if (!strcmp (exttype, "PS1_DEV_1")) {
-                  status = pmSourcesWrite_PS1_DEV_1_XSRC (file->fits, sources, xsrcname, recipe);
+                  status &= pmSourcesWrite_PS1_DEV_1_XSRC (file->fits, sources, xsrcname, recipe);
               }
               if (!strcmp (exttype, "PS1_CAL_0")) {
-                  status = pmSourcesWrite_PS1_CAL_0_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe);
+                  status &= pmSourcesWrite_PS1_CAL_0_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe);
               }
               if (!strcmp (exttype, "PS1_V1")) {
-                  status = pmSourcesWrite_CMF_PS1_V1_XSRC (file->fits, sources, xsrcname, recipe);
+                  status &= pmSourcesWrite_CMF_PS1_V1_XSRC (file->fits, sources, xsrcname, recipe);
               }
               if (!strcmp (exttype, "PS1_V2")) {
-                  status = pmSourcesWrite_CMF_PS1_V2_XSRC (file->fits, sources, xsrcname, recipe);
+                  status &= pmSourcesWrite_CMF_PS1_V2_XSRC (file->fits, sources, xsrcname, recipe);
               }
             }
             if (xfitname) {
               if (!strcmp (exttype, "PS1_DEV_1")) {
-                  status = pmSourcesWrite_PS1_DEV_1_XFIT (file->fits, sources, xfitname);
+                  status &= pmSourcesWrite_PS1_DEV_1_XFIT (file->fits, sources, xfitname);
               }
               if (!strcmp (exttype, "PS1_CAL_0")) {
-                  status = pmSourcesWrite_PS1_CAL_0_XFIT (file->fits, readout, sources, file->header, xfitname);
+                  status &= pmSourcesWrite_PS1_CAL_0_XFIT (file->fits, readout, sources, file->header, xfitname);
               }
               if (!strcmp (exttype, "PS1_V1")) {
-                  status = pmSourcesWrite_CMF_PS1_V1_XFIT (file->fits, sources, xfitname);
+                  status &= pmSourcesWrite_CMF_PS1_V1_XFIT (file->fits, sources, xfitname);
               }
               if (!strcmp (exttype, "PS1_V2")) {
-                  status = pmSourcesWrite_CMF_PS1_V2_XFIT (file->fits, sources, xfitname);
+                  status &= pmSourcesWrite_CMF_PS1_V2_XFIT (file->fits, sources, xfitname);
               }
             }
@@ -534,4 +572,5 @@
                 psFree (xfitname);
                 psFree (outhead);
+                psFree (deteffname);
                 return false;
             }
@@ -545,4 +584,5 @@
         psFree (xfitname);
         psFree (outhead);
+	psFree (deteffname);
         break;
 
@@ -572,6 +612,6 @@
     // not needed if only one chip
     if (file->fpa->chips->n == 1) {
-	pmSourceIO_WriteMatchedRefs (file->fits, file->fpa, config);
-	return true;
+        pmSourceIO_WriteMatchedRefs (file->fits, file->fpa, config);
+        return true;
     }
 
@@ -885,26 +925,11 @@
         hdu = pmFPAviewThisHDU (view, file->fpa);
 
-        // lookup the EXTNAME values used for table data and image header segments
-        char *rule = NULL;
-        // Menu of EXTNAME rules
-        psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "EXTNAME.RULES");
-        if (!menu) {
-            psError(PS_ERR_UNKNOWN, true, "missing EXTNAME.RULES in camera.config");
-            return false;
-        }
-        // EXTNAME for image header
-        rule = psMetadataLookupStr(&status, menu, "CMF.HEAD");
-        if (!rule) {
-            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.HEAD in EXTNAME.RULES in camera.config");
-            return false;
-        }
-        char *headname = pmFPAfileNameFromRule (rule, file, view);
-        // EXTNAME for table data
-        rule = psMetadataLookupStr(&status, menu, "CMF.DATA");
-        if (!rule) {
-            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.DATA in EXTNAME.RULES in camera.config");
-            return false;
-        }
-        char *dataname = pmFPAfileNameFromRule (rule, file, view);
+        // define the EXTNAME values for the different data segments:
+        psString headname = NULL;
+        psString dataname = NULL;
+        psString deteffname = NULL;
+        if (!sourceExtensions(&headname, &dataname, &deteffname, NULL, NULL, file, view)) {
+            return false;
+        }
 
         // advance to the IMAGE HEADER extension
@@ -915,4 +940,5 @@
                 psFree (headname);
                 psFree (dataname);
+                psFree (deteffname);
                 return true;
             }
@@ -958,4 +984,14 @@
                 sources = pmSourcesRead_CMF_PS1_V2 (file->fits, hdu->header);
             }
+
+            if (!pmReadoutReadDetEff(file->fits, readout, deteffname)) {
+#if 0
+                psError(PS_ERR_IO, false, "Unable to read detection efficiency");
+                return false;
+#else
+                // No great loss
+                psErrorClear();
+#endif
+            }
         }
 
@@ -963,4 +999,5 @@
         psFree (headname);
         psFree (dataname);
+	psFree (deteffname);
         psFree (tableHeader);
         break;
@@ -1070,3 +1107,3 @@
 }
 
-    
+
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 25766)
@@ -128,5 +128,5 @@
             nDOF = model->nDOF;
             nPix = model->nPix;
-            apRadius = model->radiusFit; // XXX should we really use the fitRadius for aperture Radius?
+            apRadius = source->apRadius;
             errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
         } else {
@@ -308,4 +308,5 @@
         source->crNsigma  = psMetadataLookupF32 (&status, row, "CR_NSIGMA");
         source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA");
+        source->apRadius  = psMetadataLookupS32 (&status, row, "AP_MAG_RADIUS");
 
         // note that some older versions used PSF_PROBABILITY: this was not well defined.
@@ -313,5 +314,4 @@
         model->nDOF       = psMetadataLookupS32 (&status, row, "PSF_NDOF");
         model->nPix       = psMetadataLookupS32 (&status, row, "PSF_NPIX");
-        model->radiusFit  = psMetadataLookupS32 (&status, row, "AP_MAG_RADIUS");
 
         source->moments = pmMomentsAlloc ();
@@ -353,8 +353,8 @@
 
     // which extended source analyses should we perform?
-    bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
-    bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
-    bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
-    bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
+    // bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
+    // bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
+    // bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
+    // bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
 
     psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
@@ -396,4 +396,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG",        PS_DATA_F32, "Sigma in EXT y coordinate",                  yErr);
 
+# if (0)
         // Petrosian measurements
         // XXX insert header data: petrosian ref radius, flux ratio
@@ -476,4 +477,5 @@
         }
 
+# endif	
         psArrayAdd (table, 100, row);
         psFree (row);
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 25766)
@@ -128,5 +128,5 @@
             nDOF = model->nDOF;
             nPix = model->nPix;
-            apRadius = model->radiusFit; // XXX should we really use the fitRadius for aperture Radius?
+            apRadius = source->apRadius;
             errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
         } else {
@@ -308,4 +308,5 @@
         source->crNsigma  = psMetadataLookupF32 (&status, row, "CR_NSIGMA");
         source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA");
+        source->apRadius  = psMetadataLookupS32 (&status, row, "AP_MAG_RADIUS");
 
         // note that some older versions used PSF_PROBABILITY: this was not well defined.
@@ -313,5 +314,4 @@
         model->nDOF       = psMetadataLookupS32 (&status, row, "PSF_NDOF");
         model->nPix       = psMetadataLookupS32 (&status, row, "PSF_NPIX");
-        model->radiusFit  = psMetadataLookupS32 (&status, row, "AP_MAG_RADIUS");
 
         source->moments = pmMomentsAlloc ();
@@ -353,8 +353,8 @@
 
     // which extended source analyses should we perform?
-    bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
-    bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
-    bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
-    bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
+    // bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
+    // bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
+    // bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
+    // bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
 
     psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
@@ -396,4 +396,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG",        PS_DATA_F32, "Sigma in EXT y coordinate",                  yErr);
 
+# if (0)
         // Petrosian measurements
         // XXX insert header data: petrosian ref radius, flux ratio
@@ -476,4 +477,5 @@
         }
 
+# endif
         psArrayAdd (table, 100, row);
         psFree (row);
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_PS1_CAL_0.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_PS1_CAL_0.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_PS1_CAL_0.c	(revision 25766)
@@ -349,8 +349,8 @@
 
     // which extended source analyses should we perform?
-    bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
-    bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
-    bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
-    bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
+    // bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
+    // bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
+    // bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
+    // bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
 
     psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
@@ -410,4 +410,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG",        PS_DATA_F32, "Sigma in EXT y coordinate",                  yErr);
 
+# if (0)
 	// Petrosian measurements
 	// XXX insert header data: petrosian ref radius, flux ratio
@@ -501,4 +502,5 @@
 	    }
 	}
+# endif
 
 	psArrayAdd (table, 100, row);
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_PS1_DEV_1.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_PS1_DEV_1.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_PS1_DEV_1.c	(revision 25766)
@@ -300,8 +300,8 @@
 
     // which extended source analyses should we perform?
-    bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
-    bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
-    bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
-    bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
+    // bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
+    // bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
+    // bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
+    // bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
 
     psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
@@ -343,4 +343,6 @@
         psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG",        PS_DATA_F32, "Sigma in EXT y coordinate",                  yErr);
 
+// XXX disable these outputs until we clean up the names
+# if (0)
 	// Petrosian measurements
 	// XXX insert header data: petrosian ref radius, flux ratio
@@ -422,4 +424,5 @@
 	    }
 	}
+# endif
 
 	psArrayAdd (table, 100, row);
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_RAW.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_RAW.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceIO_RAW.c	(revision 25766)
@@ -119,5 +119,5 @@
                  logChi, logChiNorm,
                  source[0].peak->SN,
-                 model[0].radiusFit,
+                 source[0].apRadius,
                  source[0].pixWeight,
                  model[0].nDOF,
@@ -181,5 +181,5 @@
                  log10(model[0].chisqNorm/model[0].nDOF),
                  source[0].peak->SN,
-                 model[0].radiusFit,
+                 source[0].apRadius,
                  source[0].pixWeight,
                  model[0].nDOF,
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceMatch.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceMatch.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceMatch.c	(revision 25766)
@@ -221,5 +221,5 @@
         } else {
             // Match with the master list
-            psTree *tree = psTreePlant(2, SOURCES_MAX_LEAF, xMaster, yMaster); // kd Tree with sources
+            psTree *tree = psTreePlant(2, SOURCES_MAX_LEAF, PS_TREE_EUCLIDEAN, xMaster, yMaster); // kd Tree
             long numMatch = 0;          // Number of matches
 
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceMoments.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceMoments.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceMoments.c	(revision 25766)
@@ -36,6 +36,4 @@
 #include "pmSource.h"
 
-bool pmSourceMoments_Old(pmSource *source, psF32 radius);
-
 /******************************************************************************
 pmSourceMoments(source, radius): this function takes a subImage defined in the
@@ -50,8 +48,7 @@
     pmSource->mask (optional)
 
-XXX: The peak calculations are done in image coords, not subImage coords.
-
-this version clips input pixels on S/N
-XXX EAM : this version returns false for several reasons
+The peak calculations are done in image coords, not subImage coords.
+
+this version optionally clips input pixels on S/N 
 *****************************************************************************/
 # define VALID_RADIUS(X,Y,RAD2) (((RAD2) >= (PS_SQR(X) + PS_SQR(Y))) ? 1 : 0)
@@ -64,5 +61,5 @@
     PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false);
 
-    // XXX supply sky in a different way?
+    // use sky from moments if defined, 0.0 otherwise
     psF32 sky = 0.0;
     if (source->moments == NULL) {
@@ -91,10 +88,18 @@
     // col0,row0: a pixel (x,y) in the primary image has coordinates of (x-col0, y-row0) in
     // this subimage.  we subtract off the peak coordinates, adjusted to this subimage, to have
-    // minimal round-off error in the sums
-
-    psF32 xOff  = source->peak->x;
-    psF32 yOff  = source->peak->y;
-    psF32 xPeak = source->peak->x - source->pixels->col0; // coord of peak in subimage
-    psF32 yPeak = source->peak->y - source->pixels->row0; // coord of peak in subimage
+    // minimal round-off error in the sums.  since these values are subtracted just to minimize
+    // the dynamic range and are added back below, the exact value does not matter. these are
+    // (int) so they can be used in the image index below.
+
+    int xOff  = source->peak->x;
+    int yOff  = source->peak->y;
+    int xPeak = source->peak->x - source->pixels->col0; // coord of peak in subimage
+    int yPeak = source->peak->y - source->pixels->row0; // coord of peak in subimage
+
+    // we are guaranteed to have a valid pixel and variance at this location (right? right?)
+    // psF32 weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]);
+    // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
+    // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel");
+    // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel");
 
     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
@@ -126,21 +131,20 @@
             psF32 wDiff = *vWgt;
 
-	    // skip pixels below specified significance level
+	    // skip pixels below specified significance level.  this is allowed, but should be
+	    // avoided -- the over-weights the wings of bright stars compared to those of faint
+	    // stars.
             if (PS_SQR(pDiff) < minSN2*wDiff) continue;
             if (pDiff < 0) continue;
 
+	    // Apply a Gaussian window function.  Be careful with the window function.  S/N
+	    // weighting over weights the sky for faint sources
 	    if (sigma > 0.0) {
-	      // apply a pseudo-gaussian weight
-
-	      // XXX a lot of extra flops; can we do pre-calculate?
-	      psF32 z  = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2;
-	      assert (z >= 0.0);
-	      psF32 t = 1.0 + z*(1.0 + z/2.0*(1.0 + z/3.0));
-	      psF32 weight  = 1.0 / t;
-
-	      // fprintf (stderr, "%6.1f %6.1f  %8.1f %8.1f  %5.3f  ", xDiff, yDiff, pDiff, wDiff, weight);
-
-	      wDiff *= weight;
-	      pDiff *= weight;
+		// XXX a lot of extra flops; can we pre-calculate?
+		psF32 z  = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2;
+		assert (z >= 0.0);
+		psF32 weight  = exp(-z);
+
+		wDiff *= weight;
+		pDiff *= weight;
 	    } 
 
@@ -154,9 +158,7 @@
 	    Y1  += yWght;
 
-	    // fprintf (stderr, " : %6.1f %6.1f  %8.1f %8.1f\n", X1, Y1, Sum, Var);
-
-            peakPixel = PS_MAX (*vPix, peakPixel);
-            numPixels++;
-        }
+	    peakPixel = PS_MAX (*vPix, peakPixel);
+	    numPixels++;
+	}
     }
 
@@ -164,6 +166,6 @@
     // XXX EAM - the limit is a bit arbitrary.  make it user defined?
     if ((numPixels < 0.75*R2) || (Sum <= 0)) {
-        psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, (int)(0.75*R2), Sum);
-        return (false);
+	psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, (int)(0.75*R2), Sum);
+	return (false);
     }
 
@@ -172,6 +174,6 @@
     float My = Y1/Sum;
     if ((fabs(Mx) > radius) || (fabs(My) > radius)) {
-        psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y);
-        return (false);
+	psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y);
+	return (false);
     }
 
@@ -179,6 +181,9 @@
 
     // add back offset of peak in primary image
-    source->moments->Mx = Mx + xOff;
-    source->moments->My = My + yOff;
+    // also offset from pixel index to pixel coordinate
+    // (the calculation above uses pixel index instead of coordinate)
+    // 0.5 PIX: moments are calculated using the pixel index and converted here to pixel coords
+    source->moments->Mx = Mx + xOff + 0.5;
+    source->moments->My = My + yOff + 0.5;
 
     source->moments->Sum = Sum;
@@ -205,5 +210,6 @@
     Sum = 0.0;  // the second pass may include slightly different pixels, re-determine Sum
 
-    // center of mass in subimage
+    // center of mass in subimage.  Note: the calculation below uses pixel index, so we do not
+    // correct xCM, yCM to pixel coordinate here.
     psF32 xCM = Mx + xPeak; // coord of peak in subimage
     psF32 yCM = My + yPeak; // coord of peak in subimage
@@ -211,87 +217,85 @@
     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
 
-        psF32 yDiff = row - yCM;
+	psF32 yDiff = row - yCM;
 	if (fabs(yDiff) > radius) continue;
 
-        psF32 *vPix = source->pixels->data.F32[row];
-        psF32 *vWgt = source->variance->data.F32[row];
-        psImageMaskType  *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
-
-        for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
-            if (vMsk) {
-                if (*vMsk) {
-                    vMsk++;
-                    continue;
-                }
-                vMsk++;
-            }
-            if (isnan(*vPix)) continue;
-
-            psF32 xDiff = col - xCM;
+	psF32 *vPix = source->pixels->data.F32[row];
+	psF32 *vWgt = source->variance->data.F32[row];
+	psImageMaskType  *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
+
+	for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
+	    if (vMsk) {
+		if (*vMsk) {
+		    vMsk++;
+		    continue;
+		}
+		vMsk++;
+	    }
+	    if (isnan(*vPix)) continue;
+
+	    psF32 xDiff = col - xCM;
 	    if (fabs(xDiff) > radius) continue;
 
-            // radius is just a function of (xDiff, yDiff)
-            psF32 r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
-            psF32 r  = sqrt(r2);
-            if (r > radius) continue;
-
-            psF32 pDiff = *vPix - sky;
-            psF32 wDiff = *vWgt;
-
-            // XXX EAM : should this limit be user-defined?
-
-            if (PS_SQR(pDiff) < minSN2*wDiff) continue;
-            if (pDiff < 0) continue;
-
+	    // radius is just a function of (xDiff, yDiff)
+	    psF32 r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
+	    psF32 r  = sqrt(r2);
+	    if (r > radius) continue;
+
+	    psF32 pDiff = *vPix - sky;
+	    psF32 wDiff = *vWgt;
+
+	    // skip pixels below specified significance level.  this is allowed, but should be
+	    // avoided -- the over-weights the wings of bright stars compared to those of faint
+	    // stars.
+	    if (PS_SQR(pDiff) < minSN2*wDiff) continue;
+	    if (pDiff < 0) continue;
+
+	    // Apply a Gaussian window function.  Be careful with the window function.  S/N
+	    // weighting over weights the sky for faint sources
 	    if (sigma > 0.0) {
-	      // apply a pseudo-gaussian weight
-
-	      // XXX a lot of extra flops; can we do pre-calculate?
-	      psF32 z  = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2;
-	      assert (z >= 0.0);
-	      psF32 t = 1.0 + z*(1.0 + z/2.0*(1.0 + z/3.0));
-	      psF32 weight  = 1.0 / t;
-
-	      // fprintf (stderr, "%6.1f %6.1f  %8.1f %8.1f  %5.3f  ", xDiff, yDiff, pDiff, wDiff, weight);
-
-	      wDiff *= weight;
-	      pDiff *= weight;
+		// XXX a lot of extra flops; can we do pre-calculate?
+		psF32 z  = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2;
+		assert (z >= 0.0);
+		psF32 weight  = exp(-z);
+
+		wDiff *= weight;
+		pDiff *= weight;
 	    } 
 
-            Sum += pDiff;
-
-            psF32 x = xDiff * pDiff;
-            psF32 y = yDiff * pDiff;
-
-            psF32 xx = xDiff * x;
-            psF32 xy = xDiff * y;
-            psF32 yy = yDiff * y;
-
-            psF32 xxx = xDiff * xx / r;
-            psF32 xxy = xDiff * xy / r;
-            psF32 xyy = xDiff * yy / r;
-            psF32 yyy = yDiff * yy / r;
-
-            psF32 xxxx = xDiff * xxx / r2;
-            psF32 xxxy = xDiff * xxy / r2;
-            psF32 xxyy = xDiff * xyy / r2;
-            psF32 xyyy = xDiff * yyy / r2;
-            psF32 yyyy = yDiff * yyy / r2;
-
-            XX  += xx;
-            XY  += xy;
-            YY  += yy;
-
-            XXX  += xxx;
-            XXY  += xxy;
-            XYY  += xyy;
-            YYY  += yyy;
-
-            XXXX  += xxxx;
-            XXXY  += xxxy;
-            XXYY  += xxyy;
-            XYYY  += xyyy;
-            YYYY  += yyyy;
-        }
+	    Sum += pDiff;
+
+	    psF32 x = xDiff * pDiff;
+	    psF32 y = yDiff * pDiff;
+
+	    psF32 xx = xDiff * x;
+	    psF32 xy = xDiff * y;
+	    psF32 yy = yDiff * y;
+
+	    psF32 xxx = xDiff * xx / r;
+	    psF32 xxy = xDiff * xy / r;
+	    psF32 xyy = xDiff * yy / r;
+	    psF32 yyy = yDiff * yy / r;
+
+	    psF32 xxxx = xDiff * xxx / r2;
+	    psF32 xxxy = xDiff * xxy / r2;
+	    psF32 xxyy = xDiff * xyy / r2;
+	    psF32 xyyy = xDiff * yyy / r2;
+	    psF32 yyyy = yDiff * yyy / r2;
+
+	    XX  += xx;
+	    XY  += xy;
+	    YY  += yy;
+
+	    XXX  += xxx;
+	    XXY  += xxy;
+	    XYY  += xyy;
+	    YYY  += yyy;
+
+	    XXXX  += xxxx;
+	    XXXY  += xxxy;
+	    XXYY  += xxyy;
+	    XYYY  += xyyy;
+	    YYYY  += yyyy;
+	}
     }
 
@@ -312,151 +316,18 @@
 
     if (source->moments->Mxx < 0) {
-      fprintf (stderr, "error: neg second moment??\n");
+	fprintf (stderr, "error: neg second moment??\n");
     }
     if (source->moments->Myy < 0) {
-      fprintf (stderr, "error: neg second moment??\n");
+	fprintf (stderr, "error: neg second moment??\n");
     }
 
     psTrace ("psModules.objects", 4, "Mxx: %f  Mxy: %f  Myy: %f  Mxxx: %f  Mxxy: %f  Mxyy: %f  Myyy: %f  Mxxxx: %f  Mxxxy: %f  Mxxyy: %f  Mxyyy: %f  Mxyyy: %f\n",
-             source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy,
-             source->moments->Mxxx,  source->moments->Mxxy,  source->moments->Mxyy,  source->moments->Myyy,
-             source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy);
+	     source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy,
+	     source->moments->Mxxx,  source->moments->Mxxy,  source->moments->Mxyy,  source->moments->Myyy,
+	     source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy);
 
     psTrace ("psModules.objects", 3, "peak %f %f (%f = %f) Mx: %f  My: %f  Sum: %f  Mxx: %f  Mxy: %f  Myy: %f  sky: %f  Npix: %d\n",
-             source->peak->xf, source->peak->yf, source->peak->flux, source->peak->SN, source->moments->Mx,   source->moments->My, Sum, source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy, sky, numPixels);
-
-    if (source->moments->Mxx < 0) {
-        fprintf (stderr, "error: neg second moment??\n");
-    }
-    if (source->moments->Myy < 0) {
-        fprintf (stderr, "error: neg second moment??\n");
-    }
-
-    // XXX TEST:
-    // pmSourceMoments_Old (source, radius);
+	     source->peak->xf, source->peak->yf, source->peak->flux, source->peak->SN, source->moments->Mx,   source->moments->My, Sum, source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy, sky, numPixels);
+
     return(true);
 }
-
-
-bool pmSourceMoments_Old(pmSource *source, psF32 radius)
-{
-    PS_ASSERT_PTR_NON_NULL(source, false);
-    PS_ASSERT_PTR_NON_NULL(source->peak, false);
-    PS_ASSERT_PTR_NON_NULL(source->pixels, false);
-    PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false);
-
-    psF32 sky = 0.0;
-    if (source->moments == NULL) {
-        source->moments = pmMomentsAlloc();
-    } else {
-        sky = source->moments->Sky;
-    }
-
-    // Sum = SUM (z - sky)
-    // X1  = SUM (x - xc)*(z - sky)
-    // X2  = SUM (x - xc)^2 * (z - sky)
-    // XY  = SUM (x - xc)*(y - yc)*(z - sky)
-    psF32 peakPixel = -PS_MAX_F32;
-    psS32 numPixels = 0;
-    psF32 Sum = 0.0;
-    psF32 Var = 0.0;
-    psF32 X1 = 0.0;
-    psF32 Y1 = 0.0;
-    psF32 X2 = 0.0;
-    psF32 Y2 = 0.0;
-    psF32 XY = 0.0;
-    psF32 x  = 0;
-    psF32 y  = 0;
-    psF32 R2 = PS_SQR(radius);
-
-    // a note about coordinates: coordinates of objects throughout psphot refer to the primary
-    // image coordinates.  the source->pixels image has an offset relative to its parent of
-    // col0,row0: a pixel (x,y) in the primary image has coordinates of (x-col0, y-row0) in
-    // this subimage.  we subtract off the peak coordinates, adjusted to this subimage, to have
-    // minimal round-off error in the sums
-
-    psF32 xPeak = source->peak->x - source->pixels->col0; // coord of peak in subimage
-    psF32 yPeak = source->peak->y - source->pixels->row0; // coord of peak in subimage
-
-    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
-
-        psF32 *vPix = source->pixels->data.F32[row];
-        psF32 *vWgt = source->variance->data.F32[row];
-        psImageMaskType  *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];
-
-        for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {
-            if (vMsk) {
-                if (*vMsk) {
-                    vMsk++;
-                    continue;
-                }
-                vMsk++;
-            }
-            if (isnan(*vPix)) continue;
-
-            psF32 xDiff = col - xPeak;
-            psF32 yDiff = row - yPeak;
-
-            // radius is just a function of (xDiff, yDiff)
-            if (!VALID_RADIUS(xDiff, yDiff, R2)) continue;
-
-            psF32 pDiff = *vPix - sky;
-            psF32 wDiff = *vWgt;
-
-            // XXX EAM : should this limit be user-defined?
-            if (PS_SQR(pDiff) < wDiff) continue;
-
-            Var += wDiff;
-            Sum += pDiff;
-
-            psF32 xWght = xDiff * pDiff;
-            psF32 yWght = yDiff * pDiff;
-
-            X1  += xWght;
-            Y1  += yWght;
-
-            X2  += xDiff * xWght;
-            XY  += xDiff * yWght;
-            Y2  += yDiff * yWght;
-
-            peakPixel = PS_MAX (*vPix, peakPixel);
-            numPixels++;
-        }
-    }
-
-    // if we have less than (1/4) of the possible pixels, force a retry
-    // XXX EAM - the limit is a bit arbitrary.  make it user defined?
-    if ((numPixels < 0.75*R2) || (Sum <= 0)) {
-        psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, (int)(0.75*R2), Sum);
-        return (false);
-    }
-
-    psTrace ("psModules.objects", 4, "sky: %f  Sum: %f  X1: %f  Y1: %f  X2: %f  Y2: %f  XY: %f  Npix: %d\n",
-             sky, Sum, X1, Y1, X2, Y2, XY, numPixels);
-
-    //
-    // first moment X  = X1/Sum + xc
-    // second moment X = sqrt (X2/Sum - (X1/Sum)^2)
-    // Sxy             = XY / Sum
-    //
-    x = X1/Sum;
-    y = Y1/Sum;
-    if ((fabs(x) > radius) || (fabs(y) > radius)) {
-        psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n",
-                 source->peak->x, source->peak->y);
-        return (false);
-    }
-
-# if (PS_TRACE_ON)
-    float Sxx = PS_MAX(X2/Sum - PS_SQR(x), 0);
-    float Sxy = XY / Sum;
-    float Syy = PS_MAX(Y2/Sum - PS_SQR(y), 0);
-
-    psTrace ("psModules.objects", 3,
-             "sky: %f  Sum: %f  x: %f  y: %f  Sx: %f  Sy: %f  Sxy: %f\n",
-             sky, Sum, x, y, Sxx, Sxy, Syy);
-# endif
-
-    return(true);
-}
-
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourcePhotometry.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourcePhotometry.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourcePhotometry.c	(revision 25766)
@@ -84,4 +84,5 @@
 
     // we must have a valid model
+    // XXX allow aperture magnitudes for sources without a model
     model = pmSourceGetModel (&isPSF, source);
     if (model == NULL) {
@@ -90,4 +91,5 @@
     }
 
+    // XXX handle negative flux, low-significance
     if (model->dparams->data.F32[PM_PAR_I0] > 0) {
         SN = model->params->data.F32[PM_PAR_I0] / model->dparams->data.F32[PM_PAR_I0];
@@ -101,37 +103,32 @@
 
     // measure PSF model photometry
-    if (psf->FluxScale) {
+    // XXX TEST: do not use flux scale
+    if (0 && psf->FluxScale) {
         // the source peak pixel is guaranteed to be on the image, and only minimally different from the source center
         double fluxScale = pmTrend2DEval (psf->FluxScale, (float)source->peak->x, (float)source->peak->y);
-        if (!isfinite(fluxScale)) {
-            // XXX objects on the edge can be slightly outside -- if we get an
-            // error, use the full fit.
-            psErrorClear();
-            status = pmSourcePhotometryModel (&source->psfMag, source->modelPSF);
-        } else {
-            if (isfinite(fluxScale) && (fluxScale > 0.0)) {
-                source->psfMag = -2.5*log10(fluxScale * source->modelPSF->params->data.F32[PM_PAR_I0]);
-            } else {
-                source->psfMag = NAN;
-            }
-        }
+	psAssert (isfinite(fluxScale), "how can the flux scale be invalid? source at %d, %d\n", source->peak->x, source->peak->y);
+	psAssert (fluxScale > 0.0, "how can the flux scale be negative? source at %d, %d\n", source->peak->x, source->peak->y);
+	source->psfMag = -2.5*log10(fluxScale * source->modelPSF->params->data.F32[PM_PAR_I0]);
     } else {
         status = pmSourcePhotometryModel (&source->psfMag, source->modelPSF);
     }
 
-    // if we have a collection of model fits, one of them is a pointer to modelEXT?
-    // XXX not guaranteed
+    // if we have a collection of model fits, check if one of them is a pointer to modelEXT
     if (source->modelFits) {
-      for (int i = 0; i < source->modelFits->n; i++) {
-        pmModel *model = source->modelFits->data[i];
-        status = pmSourcePhotometryModel (&model->mag, model);
-      }
-      if (source->modelEXT) {
-        source->extMag = source->modelEXT->mag;
-      }
+        bool foundEXT = false;
+	for (int i = 0; i < source->modelFits->n; i++) {
+	    pmModel *model = source->modelFits->data[i];
+	    status = pmSourcePhotometryModel (&model->mag, model);
+	    if (model == source->modelEXT) foundEXT = true;
+	}
+	if (foundEXT) {
+	    source->extMag = source->modelEXT->mag;
+	} else {
+	    status = pmSourcePhotometryModel (&source->extMag, source->modelEXT);
+	}
     } else {
-      if (source->modelEXT) {
-        status = pmSourcePhotometryModel (&source->extMag, source->modelEXT);
-      }
+	if (source->modelEXT) {
+	    status = pmSourcePhotometryModel (&source->extMag, source->modelEXT);
+	}
     }
 
@@ -160,11 +157,6 @@
     }
 
-    // replace source flux
-    // XXX need to be certain which model and size of mask for prior subtraction
-    // XXX full model or just analytical?
-    // XXX use pmSourceAdd instead?
-    if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
-        pmModelAdd (source->pixels, source->maskObj, model, PM_MODEL_OP_FULL, maskVal);
-    }
+    // if we measure aperture magnitudes, the source must not currently be subtracted!
+    psAssert (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED), "cannot measure ap mags if source is subtracted!");
 
     // if we are measuring aperture photometry and applying the growth correction,
@@ -201,9 +193,10 @@
     if (isfinite (source->apMag) && isPSF && psf) {
         if (psf->growth && (mode & PM_SOURCE_PHOT_GROWTH)) {
-            source->apMag += pmGrowthCurveCorrect (psf->growth, model->radiusFit);
+            source->apMag += pmGrowthCurveCorrect (psf->growth, source->apRadius);
         }
         if (mode & PM_SOURCE_PHOT_APCORR) {
+	    // XXX this should be removed -- we no longer fit for the 'sky bias'
             rflux   = pow (10.0, 0.4*source->psfMag);
-            source->apMag -= PS_SQR(model->radiusFit)*rflux * psf->skyBias + psf->skySat / rflux;
+            source->apMag -= PS_SQR(source->apRadius)*rflux * psf->skyBias + psf->skySat / rflux;
         }
     }
@@ -211,10 +204,4 @@
         psFree(flux);
         psFree(mask);
-    }
-
-    // if source was originally subtracted, re-subtract object, leave local sky
-    // XXX replace with pmSourceSub...
-    if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
-        pmModelSub (source->pixels, source->maskObj, model, PM_MODEL_OP_FULL, maskVal);
     }
 
@@ -763,55 +750,2 @@
     return flux;
 }
-
-// XXX this is test code to verify the shift is doing the right thing (seems to be)
-# if (0)
-// measure centroid of unshifted gaussian (should be 16.0,16.0)
-        {
-	  psImage *image = source->pixels;
-	  float xo = 0.0;
-	  float yo = 0.0;
-	  float xo2 = 0.0;
-	  float yo2 = 0.0;
-	  float no = 0.0;
-	  for (int j = 0; j < image->numRows; j++)
-	  {
-	    for (int i = 0; i < image->numCols; i++) {
-	      xo += i*image->data.F32[j][i];
-	      yo += j*image->data.F32[j][i];
-	      xo2 += i*i*image->data.F32[j][i];
-	      yo2 += j*j*image->data.F32[j][i];
-	      no += image->data.F32[j][i];
-	    }
-	  }
-	  xo /= no;
-	  yo /= no;
-	  xo2 = sqrt (xo2/no - xo*xo);
-	  yo2 = sqrt (yo2/no - yo*yo);
-	  fprintf (stderr, "pre-shift centroid: %f,%f, sigma: %f,%f: flux: %f\n", xo, yo, xo2, yo2, no);
-        }
-
-// measure centroid of unshifted gaussian (should be 16.0,16.0)
-        {
-	  psImage *image = flux;
-	  float xo = 0.0;
-	  float yo = 0.0;
-	  float xo2 = 0.0;
-	  float yo2 = 0.0;
-	  float no = 0.0;
-	  for (int j = 0; j < image->numRows; j++)
-	  {
-	    for (int i = 0; i < image->numCols; i++) {
-	      xo += i*image->data.F32[j][i];
-	      yo += j*image->data.F32[j][i];
-	      xo2 += i*i*image->data.F32[j][i];
-	      yo2 += j*j*image->data.F32[j][i];
-	      no += image->data.F32[j][i];
-	    }
-	  }
-	  xo /= no;
-	  yo /= no;
-	  xo2 = sqrt (xo2/no - xo*xo);
-	  yo2 = sqrt (yo2/no - yo*yo);
-	  fprintf (stderr, "pre-shift centroid: %f,%f, sigma: %f,%f: flux: %f\n", xo, yo, xo2, yo2, no);
-        }
-# endif
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceVisual.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceVisual.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceVisual.c	(revision 25766)
@@ -5,4 +5,7 @@
 #include <pslib.h>
 #include "pmTrend2D.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmSource.h"
 #include "pmSourceVisual.h"
 
@@ -15,6 +18,6 @@
 
 static int kapa1 = -1;
+static int kapa2 = -1;
 static bool plotPSF = true;
-// static int kapa2 = -1;
 // static int kapa3 = -1;
 
@@ -27,12 +30,9 @@
 bool pmSourcePlotPoints3D (int myKapa, Graphdata *graphdata, psVector *xn, psVector *yn, psVector *zn, float theta, float phi);
 
-
-bool pmSourceVisualPSFModelResid (pmTrend2D *trend, psVector *x, psVector *y, psVector *param, psVector *mask) {
-
-    KapaSection section;  // put the positive profile in one and the residuals in another?
+bool pmSourceVisualPlotPSFMetric (pmPSFtry *psfTry) {
 
     Graphdata graphdata;
 
-    if (!pmVisualIsVisual() || !plotPSF) return true;
+    if (!pmVisualIsVisual()) return true;
 
     if (kapa1 == -1) {
@@ -45,41 +45,249 @@
     }
 
+    KapaClearSections (kapa1);
+    KapaInitGraph (&graphdata);
+
+    psVector *x = psVectorAllocEmpty (psfTry->sources->n, PS_TYPE_F32);
+    psVector *y = psVectorAllocEmpty (psfTry->sources->n, PS_TYPE_F32);
+    psVector *dy = psVectorAllocEmpty(psfTry->sources->n, PS_TYPE_F32);
+
+    graphdata.xmin = +32.0;
+    graphdata.xmax = -32.0;
+    graphdata.ymin = +32.0;
+    graphdata.ymax = -32.0;
+
+    // construct the plot vectors
+    int n = 0;
+    for (int i = 0; i < psfTry->sources->n; i++) {
+	if (psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & PSFTRY_MASK_ALL) continue;
+        x->data.F32[n] = psfTry->fitMag->data.F32[i];
+	y->data.F32[n] = psfTry->metric->data.F32[i];
+        dy->data.F32[n] = psfTry->metricErr->data.F32[i];
+        graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
+        graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
+        graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]);
+        graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]);
+	n++;
+    }
+    x->n = y->n = dy->n = n;
+
+    float range;
+    range = graphdata.xmax - graphdata.xmin;
+    graphdata.xmax += 0.05*range;
+    graphdata.xmin -= 0.05*range;
+    range = graphdata.ymax - graphdata.ymin;
+    graphdata.ymax += 0.05*range;
+    graphdata.ymin -= 0.05*range;
+
+    // better choice for range?
+    // graphdata.xmin = -17.0;
+    // graphdata.xmax =  -9.0;
+    graphdata.ymin = -0.51;
+    graphdata.ymax = +0.51;
+
+    KapaSetLimits (kapa1, &graphdata);
+
+    KapaSetFont (kapa1, "helvetica", 14);
+    KapaBox (kapa1, &graphdata);
+    KapaSendLabel (kapa1, "PSF Mag", KAPA_LABEL_XM);
+    KapaSendLabel (kapa1, "Ap Mag - PSF Mag", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ptype = 2;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    graphdata.etype |= 0x01;
+
+    KapaPrepPlot (kapa1, n, &graphdata);
+    KapaPlotVector (kapa1, n, x->data.F32, "x");
+    KapaPlotVector (kapa1, n, y->data.F32, "y");
+    KapaPlotVector (kapa1, n, dy->data.F32, "dym");
+    KapaPlotVector (kapa1, n, dy->data.F32, "dyp");
+
+    psFree (x);
+    psFree (y);
+    psFree (dy);
+
+    pmVisualAskUser(NULL);
+    return true;
+}
+
+// to see the structure of the psf model, place the sources in a fake image 1/10th the size
+// at their appropriate relative location. later sources stomp on earlier sources
+bool pmSourceVisualShowModelFits (pmPSF *psf, psArray *sources, psImageMaskType maskVal) {
+
+    if (!pmVisualIsVisual()) return true;
+
+    if (kapa2 == -1) {
+        kapa2 = KapaOpenNamedSocket ("kapa", "pmSource:images");
+        if (kapa2 == -1) {
+            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+            pmVisualSetVisual(false);
+            return false;
+        }
+    }
+
+    // create images 1/10 scale:
+    psImage *image = psImageAlloc (0.1*psf->fieldNx, 0.1*psf->fieldNy, PS_TYPE_F32);
+    psImage *model = psImageAlloc (0.1*psf->fieldNx, 0.1*psf->fieldNy, PS_TYPE_F32);
+    psImage *resid = psImageAlloc (0.1*psf->fieldNx, 0.1*psf->fieldNy, PS_TYPE_F32);
+    psImageInit (image, 0.0);
+    psImageInit (model, 0.0);
+    psImageInit (resid, 0.0);
+
+    for (int i = sources->n - 1; i >= 0; i--) {
+	pmSource *source = sources->data[i];
+	if (!source) continue;
+	if (!source->pixels) continue;
+
+	pmSourceCacheModel (source, maskVal);
+	if (!source->modelFlux) continue;
+
+	pmModel *srcModel = pmSourceGetModel (NULL, source);
+	if (!model) continue;
+
+	float norm = srcModel->params->data.F32[PM_PAR_I0];
+
+	int Xo = 0.1*srcModel->params->data.F32[PM_PAR_XPOS];
+	int Yo = 0.1*srcModel->params->data.F32[PM_PAR_YPOS];
+
+	// insert source pixels in the image at 1/10th offset
+	for (int iy = 0; iy < source->pixels->numRows; iy++) {
+	    int jy = iy + Yo;
+	    if (jy >= image->numRows) continue;
+	    for (int ix = 0; ix < source->pixels->numCols; ix++) {
+		int jx = ix + Xo;
+		if (jx >= image->numCols) continue;
+		if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) continue;
+		if (source->modelFlux->data.F32[iy][ix] < 0.001) continue;
+		image->data.F32[jy][jx] = source->pixels->data.F32[iy][ix];
+		model->data.F32[jy][jx] = source->modelFlux->data.F32[iy][ix];
+		resid->data.F32[jy][jx] = source->pixels->data.F32[iy][ix] - norm*source->modelFlux->data.F32[iy][ix];
+	    }
+	}
+    }
+
+    // KapaClearSections (kapa2);
+    pmVisualScaleImage (kapa2, image, "image", 0, true);
+    pmVisualScaleImage (kapa2, model, "model", 1, true);
+    pmVisualScaleImage (kapa2, resid, "resid", 2, true);
+
+# ifdef DEBUG
+    { 
+	psFits *fits = psFitsOpen ("image.fits", "w");
+	psFitsWriteImage (fits, NULL, image, 0, NULL);
+	psFitsClose (fits);
+	fits = psFitsOpen ("model.fits", "w");
+	psFitsWriteImage (fits, NULL, model, 0, NULL);
+	psFitsClose (fits);
+	fits = psFitsOpen ("resid.fits", "w");
+	psFitsWriteImage (fits, NULL, resid, 0, NULL);
+	psFitsClose (fits);
+    }
+# endif
+
+    psFree (image);
+    psFree (model);
+    psFree (resid);
+
+    pmVisualAskUser(NULL);
+    return true;
+}
+
+bool pmSourceVisualShowModelFit (pmSource *source) {
+
+    if (!pmVisualIsVisual()) return true;
+    if (!source->pixels) return false;
+    if (!source->modelFlux) return false;
+
+    if (kapa2 == -1) {
+        kapa2 = KapaOpenNamedSocket ("kapa", "pmSource:images");
+        if (kapa2 == -1) {
+            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+            pmVisualSetVisual(false);
+            return false;
+        }
+    }
+
+    // KapaClearSections (kapa2);
+    pmVisualScaleImage (kapa2, source->pixels, "source", 0, false);
+    pmVisualScaleImage (kapa2, source->modelFlux, "model", 1, false);
+
+    pmModel *model = pmSourceGetModel (NULL, source);
+    float norm = model->params->data.F32[PM_PAR_I0];
+
+    psImage *resid = psImageAlloc (source->pixels->numCols, source->pixels->numRows, PS_TYPE_F32);
+    for (int iy = 0; iy < source->pixels->numRows; iy++) {
+	for (int ix = 0; ix < source->pixels->numCols; ix++) {
+	    if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
+		resid->data.F32[iy][ix] = NAN;
+		continue;
+	    }
+	    resid->data.F32[iy][ix] = source->pixels->data.F32[iy][ix] - norm*source->modelFlux->data.F32[iy][ix];
+	}
+    }
+    pmVisualScaleImage (kapa2, resid, "resid", 2, false);
+
+    psFree (resid);
+
+    pmVisualAskUser(NULL);
+    return true;
+}
+
+bool pmSourceVisualPSFModelResid (pmTrend2D *trend, psVector *x, psVector *y, psVector *param, psVector *mask) {
+
+    KapaSection section;  // put the positive profile in one and the residuals in another?
+
+    Graphdata graphdata;
+
+    if (!pmVisualIsVisual() || !plotPSF) return true;
+
+    if (kapa1 == -1) {
+        kapa1 = KapaOpenNamedSocket ("kapa", "pmSource:plots");
+        if (kapa1 == -1) {
+            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+            pmVisualSetVisual(false);
+            return false;
+        }
+    }
+
     KapaClearPlots (kapa1);
     KapaInitGraph (&graphdata);
 
-    float min = +1e32;
-    float max = -1e32;
-    float Min = +1e32;
-    float Max = -1e32;
+    float Xmin = +1e32;
+    float Xmax = -1e32;
+    float Ymin = +1e32;
+    float Ymax = -1e32;
+    float Fmin = +1e32;
+    float Fmax = -1e32;
 
     psVector *resid = psVectorAlloc (x->n, PS_TYPE_F32);
     psVector *model = psVectorAlloc (x->n, PS_TYPE_F32);
 
+    psVector *xm = psVectorAlloc (x->n, PS_TYPE_F32);
+    psVector *ym = psVectorAlloc (x->n, PS_TYPE_F32);
+    psVector *Fm = psVectorAlloc (x->n, PS_TYPE_F32);
+
+    int n = 0;
     for (int i = 0; i < x->n; i++) {
         model->data.F32[i] = pmTrend2DEval (trend, x->data.F32[i], y->data.F32[i]);
         resid->data.F32[i] = param->data.F32[i] - model->data.F32[i];
         if (mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) continue;
-        min = PS_MIN (min, resid->data.F32[i]);
-        max = PS_MAX (max, resid->data.F32[i]);
-        Min = PS_MIN (min, param->data.F32[i]);
-        Max = PS_MAX (max, param->data.F32[i]);
-    }
-
-    psVector *xn = psVectorAlloc (x->n, PS_TYPE_F32);
-    psVector *yn = psVectorAlloc (x->n, PS_TYPE_F32);
-    psVector *zn = psVectorAlloc (x->n, PS_TYPE_F32);
-    psVector *Zn = psVectorAlloc (x->n, PS_TYPE_F32);
-    psVector *Fn = psVectorAlloc (x->n, PS_TYPE_F32);
-    for (int i = 0; i < x->n; i++) {
-        xn->data.F32[i] = x->data.F32[i] / 5000.0;
-        yn->data.F32[i] = y->data.F32[i] / 5000.0;
-        zn->data.F32[i] = (resid->data.F32[i] - min) / (max - min);
-        Zn->data.F32[i] = (param->data.F32[i] - Min) / (Max - Min);
-        Fn->data.F32[i] = (model->data.F32[i] - Min) / (Max - Min);
-    }
+        Xmin = PS_MIN (Xmin, x->data.F32[i]);
+        Xmax = PS_MAX (Xmax, x->data.F32[i]);
+        Ymin = PS_MIN (Ymin, y->data.F32[i]);
+        Ymax = PS_MAX (Ymax, y->data.F32[i]);
+        Fmin = PS_MIN (Fmin, param->data.F32[i]);
+        Fmax = PS_MAX (Fmax, param->data.F32[i]);
+	xm->data.F32[n] = x->data.F32[i];
+	ym->data.F32[n] = y->data.F32[i];
+	Fm->data.F32[n] = param->data.F32[i];
+	n++;
+    }
+    xm->n = ym->n = Fm->n = n;
 
     // view 1 on resid
-    section.dx = 0.5;
-    section.dy = 0.33;
+    section.dx = 1.0;
+    section.dy = 0.5;
     section.x = 0.0;
     section.y = 0.0;
@@ -88,67 +296,98 @@
     KapaSetSection (kapa1, &section);
     psFree (section.name);
-    pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, zn, 30.0*PS_RAD_DEG, -15.0*PS_RAD_DEG);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.xmin = Xmin;
+    graphdata.xmax = Xmax;
+    graphdata.ymin = Fmin;
+    graphdata.ymax = Fmax;
+
+    { 
+	float range;
+	range = graphdata.xmax - graphdata.xmin;
+	graphdata.xmax += 0.05*range;
+	graphdata.xmin -= 0.05*range;
+	range = graphdata.ymax - graphdata.ymin;
+	graphdata.ymax += 0.05*range;
+	graphdata.ymin -= 0.05*range;
+    }
+
+    KapaSetLimits (kapa1, &graphdata);
+    KapaSetFont (kapa1, "helvetica", 14);
+    KapaBox (kapa1, &graphdata);
+    KapaSendLabel (kapa1, "X (pixels)", KAPA_LABEL_XM);
+    KapaSendLabel (kapa1, "Model Param", KAPA_LABEL_YM);
+
+    graphdata.ptype = 2;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot (kapa1,   x->n, &graphdata);
+    KapaPlotVector (kapa1, x->n, x->data.F32, "x");
+    KapaPlotVector (kapa1, x->n, param->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 1;
+    KapaPrepPlot (kapa1,   xm->n, &graphdata);
+    KapaPlotVector (kapa1, xm->n, xm->data.F32, "x");
+    KapaPlotVector (kapa1, xm->n, Fm->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 1;
+    KapaPrepPlot (kapa1,   x->n, &graphdata);
+    KapaPlotVector (kapa1, x->n, x->data.F32, "x");
+    KapaPlotVector (kapa1, x->n, model->data.F32, "y");
 
     // view 2 on resid
-    section.dx = 0.5;
-    section.dy = 0.33;
-    section.x = 0.5;
-    section.y = 0.0;
+    section.dx = 1.0;
+    section.dy = 0.5;
+    section.x = 0.0;
+    section.y = 0.5;
     section.name = NULL;
     psStringAppend (&section.name, "a2");
     KapaSetSection (kapa1, &section);
     psFree (section.name);
-    pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, zn, -60.0*PS_RAD_DEG, -15.0*PS_RAD_DEG);
-
-    // view 3 on resid
-    section.dx = 0.5;
-    section.dy = 0.33;
-    section.x = 0.0;
-    section.y = 0.33;
-    section.name = NULL;
-    psStringAppend (&section.name, "a3");
-    KapaSetSection (kapa1, &section);
-    psFree (section.name);
-    pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, Zn, 30.0*PS_RAD_DEG, -15.0*PS_RAD_DEG);
-
-    // view 4 on resid
-    section.dx = 0.5;
-    section.dy = 0.33;
-    section.x = 0.5;
-    section.y = 0.33;
-    section.name = NULL;
-    psStringAppend (&section.name, "a4");
-    KapaSetSection (kapa1, &section);
-    psFree (section.name);
-    pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, Zn, -60.0*PS_RAD_DEG, -15.0*PS_RAD_DEG);
-
-    // view 5 on resid
-    section.dx = 0.5;
-    section.dy = 0.33;
-    section.x = 0.0;
-    section.y = 0.66;
-    section.name = NULL;
-    psStringAppend (&section.name, "a5");
-    KapaSetSection (kapa1, &section);
-    psFree (section.name);
-    pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, Fn, 30.0*PS_RAD_DEG, -15.0*PS_RAD_DEG);
-
-    // view 6 on resid
-    section.dx = 0.5;
-    section.dy = 0.33;
-    section.x = 0.5;
-    section.y = 0.66;
-    section.name = NULL;
-    psStringAppend (&section.name, "a6");
-    KapaSetSection (kapa1, &section);
-    psFree (section.name);
-    pmSourcePlotPoints3D (kapa1, &graphdata, xn, yn, Fn, -60.0*PS_RAD_DEG, -15.0*PS_RAD_DEG);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.xmin = Ymin;
+    graphdata.xmax = Ymax;
+    graphdata.ymin = Fmin;
+    graphdata.ymax = Fmax;
+    { 
+	float range;
+	range = graphdata.xmax - graphdata.xmin;
+	graphdata.xmax += 0.05*range;
+	graphdata.xmin -= 0.05*range;
+	range = graphdata.ymax - graphdata.ymin;
+	graphdata.ymax += 0.05*range;
+	graphdata.ymin -= 0.05*range;
+    }
+
+    KapaSetLimits (kapa1, &graphdata);
+    KapaSetFont (kapa1, "helvetica", 14);
+    KapaBox (kapa1, &graphdata);
+    KapaSendLabel (kapa1, "Y (pixels)", KAPA_LABEL_XM);
+    KapaSendLabel (kapa1, "Model Param", KAPA_LABEL_YM);
+
+    graphdata.ptype = 2;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot (kapa1,   y->n, &graphdata);
+    KapaPlotVector (kapa1, y->n, y->data.F32, "x");
+    KapaPlotVector (kapa1, y->n, param->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 1;
+    KapaPrepPlot (kapa1,   xm->n, &graphdata);
+    KapaPlotVector (kapa1, xm->n, ym->data.F32, "x");
+    KapaPlotVector (kapa1, xm->n, Fm->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 1;
+    KapaPrepPlot (kapa1,   y->n, &graphdata);
+    KapaPlotVector (kapa1, y->n, y->data.F32, "x");
+    KapaPlotVector (kapa1, y->n, model->data.F32, "y");
 
     psFree (resid);
-
-    psFree (xn);
-    psFree (yn);
-    psFree (zn);
-    psFree (Zn);
+    psFree (model);
 
     // pause and wait for user input:
@@ -159,6 +398,8 @@
 }
 
-// send in normalized points
+// Somewhat broken 3D plotting function (was used by pmSourceVisualPSFModelResid, but not anymore)
 bool pmSourcePlotPoints3D (int myKapa, Graphdata *graphdata, psVector *xn, psVector *yn, psVector *zn, float theta, float phi) {
+
+    return true;
 
     psVector *xv = psVectorAlloc (PS_MAX(6, 2*xn->n), PS_TYPE_F32);
@@ -192,9 +433,4 @@
     KapaSetLimits (myKapa, graphdata);
 
-    // KapaSetFont (myKapa, "helvetica", 14);
-    // KapaBox (myKapa, graphdata);
-    // KapaSendLabel (myKapa, "&ss&h_x| (pixels)", KAPA_LABEL_XM);
-    // KapaSendLabel (myKapa, "&ss&h_y| (pixels)", KAPA_LABEL_YM);
-
     graphdata->color = KapaColorByName ("black");
     graphdata->ptype = 100;
Index: branches/eam_branches/20090820/psModules/src/objects/pmSourceVisual.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmSourceVisual.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmSourceVisual.h	(revision 25766)
@@ -18,4 +18,7 @@
 
 bool pmSourceVisualPSFModelResid (pmTrend2D *trend, psVector *x, psVector *y, psVector *param, psVector *mask);
+bool pmSourceVisualPlotPSFMetric (pmPSFtry *try);
+bool pmSourceVisualShowModelFit (pmSource *source);
+bool pmSourceVisualShowModelFits (pmPSF *psf, psArray *sources, psImageMaskType maskVal);
 
 /// @}
Index: branches/eam_branches/20090820/psModules/src/objects/pmTrend2D.c
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmTrend2D.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmTrend2D.c	(revision 25766)
@@ -298,2 +298,21 @@
     return PM_TREND_NONE;
 }
+
+bool pmTrend2DPrintMap (pmTrend2D *trend) {
+
+    if (!trend->map) return false;
+    if (!trend->map->map) return false;
+
+    for (int j = 0; j < trend->map->map->numRows; j++) {
+        for (int i = 0; i < trend->map->map->numCols; i++) {
+            fprintf (stderr, "%5.2f  ", trend->map->map->data.F32[j][i]);
+        }
+        fprintf (stderr, "\t\t\t");
+        for (int i = 0; i < trend->map->map->numCols; i++) {
+            fprintf (stderr, "%5.2f  ", trend->map->error->data.F32[j][i]);
+        }
+        fprintf (stderr, "\n");
+    }
+    return true;
+}
+
Index: branches/eam_branches/20090820/psModules/src/objects/pmTrend2D.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/objects/pmTrend2D.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/objects/pmTrend2D.h	(revision 25766)
@@ -97,4 +97,6 @@
 pmTrend2DMode pmTrend2DModeFromString(psString name);
 
+bool pmTrend2DPrintMap (pmTrend2D *trend);
+
 /// @}
 # endif
Index: branches/eam_branches/20090820/psModules/src/psmodules.h
===================================================================
--- branches/eam_branches/20090820/psModules/src/psmodules.h	(revision 25206)
+++ branches/eam_branches/20090820/psModules/src/psmodules.h	(revision 25766)
@@ -133,4 +133,5 @@
 #include <pmSourceVisual.h>
 #include <pmSourceMatch.h>
+#include <pmDetEff.h>
 
 // The following headers are from random locations, here because they cross bounds
Index: branches/eam_branches/20090820/psModules/test/objects/tap_pmGrowthCurve.c
===================================================================
--- branches/eam_branches/20090820/psModules/test/objects/tap_pmGrowthCurve.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/test/objects/tap_pmGrowthCurve.c	(revision 25766)
@@ -131,30 +131,30 @@
         source->mode = PM_SOURCE_MODE_PSFSTAR;
 
-        source->modelPSF->radiusFit = 15.0;
+        source->apRadius = 15.0;
 
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         double refMag = source->apMag;
 
-        source->modelPSF->radiusFit = 10.0;
-        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
-        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
-
-        source->modelPSF->radiusFit = 8.0;
-        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
-        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
-
-        source->modelPSF->radiusFit = 6.0;
+        source->apRadius = 10.0;
+        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
+        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
+
+        source->apRadius = 8.0;
+        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
+        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
+
+        source->apRadius = 6.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, +0.0003, 0.0001, "growth offset is is %f", refMag - source->apMag);
 
-        source->modelPSF->radiusFit = 4.0;
+        source->apRadius = 4.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, +0.0020, 0.0001, "growth offset is is %f", refMag - source->apMag);
 
-        source->modelPSF->radiusFit = 3.0;
+        source->apRadius = 3.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, -0.0001, 0.0001, "growth offset is is %f", refMag - source->apMag);
 
-        source->modelPSF->radiusFit = 2.0;
+        source->apRadius = 2.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, -0.0075, 0.0001, "growth offset is is %f", refMag - source->apMag);
@@ -234,29 +234,29 @@
         source->mode = PM_SOURCE_MODE_PSFSTAR;
 
-        source->modelPSF->radiusFit = 15.0;
+        source->apRadius = 15.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         double refMag = source->apMag;
 
-        source->modelPSF->radiusFit = 10.0;
-        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
-        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
-
-        source->modelPSF->radiusFit = 8.0;
-        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
-        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
-
-        source->modelPSF->radiusFit = 6.0;
+        source->apRadius = 10.0;
+        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
+        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
+
+        source->apRadius = 8.0;
+        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
+        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
+
+        source->apRadius = 6.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, +0.0004, 0.0001, "growth offset is is %f", refMag - source->apMag);
 
-        source->modelPSF->radiusFit = 4.0;
+        source->apRadius = 4.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, +0.0026, 0.0001, "growth offset is is %f", refMag - source->apMag);
 
-        source->modelPSF->radiusFit = 3.0;
+        source->apRadius = 3.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, -0.0001, 0.0001, "growth offset is is %f", refMag - source->apMag);
 
-        source->modelPSF->radiusFit = 2.0;
+        source->apRadius = 2.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, -0.0103, 0.0001, "growth offset is is %f", refMag - source->apMag);
@@ -336,29 +336,29 @@
         source->mode = PM_SOURCE_MODE_PSFSTAR;
 
-        source->modelPSF->radiusFit = 15.0;
+        source->apRadius = 15.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         double refMag = source->apMag;
 
-        source->modelPSF->radiusFit = 10.0;
-        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
-        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
-
-        source->modelPSF->radiusFit = 8.0;
-        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
-        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
-
-        source->modelPSF->radiusFit = 6.0;
+        source->apRadius = 10.0;
+        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
+        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
+
+        source->apRadius = 8.0;
+        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
+        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
+
+        source->apRadius = 6.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, +0.0006, 0.0001, "growth offset is is %f", refMag - source->apMag);
 
-        source->modelPSF->radiusFit = 4.0;
+        source->apRadius = 4.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, +0.0038, 0.0001, "growth offset is is %f", refMag - source->apMag);
 
-        source->modelPSF->radiusFit = 3.0;
-        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
-        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
-
-        source->modelPSF->radiusFit = 2.0;
+        source->apRadius = 3.0;
+        pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
+        ok_float_tol(refMag - source->apMag, +0.0000, 0.0001, "growth offset is is %f", refMag - source->apMag);
+
+        source->apRadius = 2.0;
         pmSourceMagnitudes (source, psf, PM_SOURCE_PHOT_GROWTH | PM_SOURCE_PHOT_INTERP, 0);
         ok_float_tol(refMag - source->apMag, -0.0164, 0.0001, "growth offset is is %f", refMag - source->apMag);
Index: branches/eam_branches/20090820/psModules/test/objects/tap_pmModel.c
===================================================================
--- branches/eam_branches/20090820/psModules/test/objects/tap_pmModel.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/test/objects/tap_pmModel.c	(revision 25766)
@@ -77,5 +77,5 @@
         ok(model->nDOF == 0, "pmModelAlloc() set pmModel->nDOF correctly");
         ok(model->nIter == 0, "pmModelAlloc() set pmModel->nIter correctly");
-        ok(model->radiusFit == 0, "pmModelAlloc() set pmModel->radiusFit correctly");
+        ok(model->fitRadius == 0, "pmModelAlloc() set pmModel->fitRadius correctly");
         ok(model->flags == PM_MODEL_STATUS_NONE, "pmModelAlloc() set pmModel->flags correctly");
         ok(model->residuals == NULL, "pmModelAlloc() set pmModel->residuals correctly");
@@ -132,5 +132,5 @@
         modelSrc->nIter = 3;
         modelSrc->flags = PM_MODEL_STATUS_NONE;
-        modelSrc->radiusFit = 4;
+        modelSrc->fitRadius = 4;
         pmModel *modelDst = pmModelCopy(modelSrc);
         ok(modelDst != NULL && psMemCheckModel(modelDst), "pmModelCopy() returned a non-NULL pmModel");
@@ -139,5 +139,5 @@
         ok(modelDst->nIter == 3, "pmModelCopy() set the pmModel->nIter member correctly");
         ok(modelDst->flags == PM_MODEL_STATUS_NONE, "pmModelCopy() set the pmModel->flags member correctly");
-        ok(modelDst->radiusFit == 4, "pmModelCopy() set the pmModel->radiusFit member correctly");
+        ok(modelDst->fitRadius == 4, "pmModelCopy() set the pmModel->fitRadius member correctly");
 
         psFree(modelSrc);
Index: branches/eam_branches/20090820/psModules/test/objects/tap_pmModelUtils.c
===================================================================
--- branches/eam_branches/20090820/psModules/test/objects/tap_pmModelUtils.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/test/objects/tap_pmModelUtils.c	(revision 25766)
@@ -81,5 +81,5 @@
         ok(tmpModel->nIter == testModelPSF->nIter, "pmModelFromPSF() set the model->nIter correctly");
         ok(tmpModel->flags == testModelPSF->flags, "pmModelFromPSF() set the model->flags correctly");
-        ok(tmpModel->radiusFit == testModelPSF->radiusFit, "pmModelFromPSF() set the model->radiusFit correctly");
+        ok(tmpModel->fitRadius == testModelPSF->fitRadius, "pmModelFromPSF() set the model->fitRadius correctly");
         ok(tmpModel->modelFunc == testModelPSF->modelFunc, "pmModelFromPSF() set the model->modelFunc correctly");
         ok(tmpModel->modelFlux == testModelPSF->modelFlux, "pmModelFromPSF() set the model->modelFlux correctly");
@@ -140,5 +140,5 @@
         ok(tmpModel->nIter == testModelPSF->nIter, "pmModelFromPSF() set the model->nIter correctly");
         ok(tmpModel->flags == testModelPSF->flags, "pmModelFromPSF() set the model->flags correctly");
-        ok(tmpModel->radiusFit == testModelPSF->radiusFit, "pmModelFromPSF() set the model->radiusFit correctly");
+        ok(tmpModel->fitRadius == testModelPSF->fitRadius, "pmModelFromPSF() set the model->fitRadius correctly");
         ok(tmpModel->modelFunc == testModelPSF->modelFunc, "pmModelFromPSF() set the model->modelFunc correctly");
         ok(tmpModel->modelFlux == testModelPSF->modelFlux, "pmModelFromPSF() set the model->modelFlux correctly");
Index: branches/eam_branches/20090820/psModules/test/objects/tap_pmSourcePhotometry.c
===================================================================
--- branches/eam_branches/20090820/psModules/test/objects/tap_pmSourcePhotometry.c	(revision 25206)
+++ branches/eam_branches/20090820/psModules/test/objects/tap_pmSourcePhotometry.c	(revision 25766)
@@ -96,5 +96,5 @@
     source->modelPSF = pmModelFromPSF (modelRef, psf);
     source->modelPSF->dparams->data.F32[PM_PAR_I0] = 1;
-    source->modelPSF->radiusFit = radius;
+    source->apRadius = radius;
 
     // measure photometry for centered source (fractional pix : 0.5,0.5)
Index: branches/eam_branches/20090820/psastro/src/psastroChipAstrom.c
===================================================================
--- branches/eam_branches/20090820/psastro/src/psastroChipAstrom.c	(revision 25206)
+++ branches/eam_branches/20090820/psastro/src/psastroChipAstrom.c	(revision 25766)
@@ -97,5 +97,6 @@
                 // write the elapsed time here; this will be updated in psastroMosaicAstrometry, if called
                 psMetadataAddF32 (updates, PS_LIST_TAIL, "DT_ASTR", PS_META_REPLACE, "elapsed psastro time", psTimerMark ("psastroAnalysis"));
-
+		
+		fpa->wcsCDkeys = psMetadataLookupBool(&status, recipe , "PSASTRO.WCS.USECDKEYS");
                 pmAstromWriteWCS (updates, fpa, chip, NONLIN_TOL);
 
Index: branches/eam_branches/20090820/psconfig/psconfig.bash.in
===================================================================
--- branches/eam_branches/20090820/psconfig/psconfig.bash.in	(revision 25206)
+++ branches/eam_branches/20090820/psconfig/psconfig.bash.in	(revision 25766)
@@ -35,5 +35,7 @@
 # environment variables
 export PATH=`/bin/csh -f $PSCONFDIR/psconfig.csh --path $version`
+export CPATH=`/bin/csh -f $PSCONFDIR/psconfig.csh --cpath $version`
 export ARCH=`/bin/csh -f $PSCONFDIR/psconfig.csh --arch $version`
+export LIBRARY_PATH=`/bin/csh -f $PSCONFDIR/psconfig.csh --library_path $version`
 export LD_LIBRARY_PATH=`/bin/csh -f $PSCONFDIR/psconfig.csh --ld_library_path $version`
 export PKG_CONFIG_PATH=`/bin/csh -f $PSCONFDIR/psconfig.csh --pkg_config_path $version`
Index: branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.dist
===================================================================
--- branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.dist	(revision 25206)
+++ branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.dist	(revision 25766)
@@ -74,4 +74,5 @@
   YYYYY  extsrc/gpcsw           ipp-2-9          -0
   YYYYY  magic                  ipp-2-9          -0
+  YYYYY  magic/censorObjects    ipp-2-9          -0
 
 # there are externally required C libraries and perl modules (see INSTALL)
Index: branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.libs
===================================================================
--- branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.libs	(revision 25206)
+++ branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.libs	(revision 25766)
@@ -20,7 +20,8 @@
 
 # Build tools
+bin m4                   NONE           NONE   m4-1.4.13.tar.gz         m4-1.4.13        N NONE NONE NONE
 bin autoconf             NONE           NONE   autoconf-2.63.tar.gz     autoconf-2.63    N NONE NONE NONE
 bin automake             NONE           NONE   automake-1.10.tar.gz     automake-1.10    N NONE NONE NONE
-bin libtool              NONE           NONE   libtool-2.2.6a.tar.gz    libtool-2.2.6    N NONE NONE NONE
+bin libtool              NONE           NONE   libtool-2.2.6-p1.tar.gz  libtool-2.2.6-p1 N NONE NONE NONE
 bin pkg-config           NONE           NONE   pkg-config-0.23.tar.gz   pkg-config-0.23  N NONE NONE NONE
 
Index: branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.perl
===================================================================
--- branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.perl	(revision 25206)
+++ branches/eam_branches/20090820/psconfig/tagsets/ipp-2.9.perl	(revision 25766)
@@ -3,5 +3,5 @@
   00    Module::Build                  Module-Build-0.2806.tar.gz               0.2806
   01    ExtUtils::MakeMaker            ExtUtils-MakeMaker-6.31.tar.gz           0
-  02    Params::Validate               Params-Validate-0.91.tar.gz       0.77
+  02    Params::Validate               Params-Validate-0.92.tar.gz              0.92
 #  02    Apache::Test                   Apache-Test-1.29.tar.gz                  1.29
   03    DateTime::TimeZone             DateTime-TimeZone-0.59.tar.gz            0
@@ -82,2 +82,7 @@
   78    SQL::Interp                     SQL-Interp-1.06.tar.gz
   79    Log::Dispatch::Email::MailSend  Log-Dispatch-2.22.tar.gz
+  80    Abstract::Meta::Class          Abstract-Meta-Class-0.13.tar.gz
+  81    DBIx::Connection               DBIx-Connection-0.13.tar.gz
+  82    Simple::SAX::Serializer        Simple-SAX-Serializer-0.05.tar.gz
+  83    Test::Distribution             Test-Distribution-2.00.tar.gz
+  84    Test::DBUnit                   Test-DBUnit-0.20.tar.gz                 0.20
Index: branches/eam_branches/20090820/psphot/doc/efficiency.txt
===================================================================
--- branches/eam_branches/20090820/psphot/doc/efficiency.txt	(revision 25766)
+++ branches/eam_branches/20090820/psphot/doc/efficiency.txt	(revision 25766)
@@ -0,0 +1,51 @@
+Strategy for efficiency analysis (a.k.a. "fake" stage)
+
+Want:
+* Detection efficiency as a function of instrumental magnitude
+* Masked fraction
+
+Given:
+* Image
+* Mask
+* Variance
+* PSF
+* Sources on image
+* Recipe:
+  + Magnitude bins (relative to guessed detection limit) for fake sources
+  + Number of fake sources for each bin
+
+
+
+Algorithm:
+* Determine mean instrumental magnitude detection limit
+  + Have:
+    - Mean variance
+    - Smoothing size
+    - Covariance
+    - Threshold
+  + Calculate mean peak flux of source at threshold
+  + Integrate PSF to determine magnitude
+* Remove all real sources from image
+* Add fake sources into image
+* Smooth image, variance (maybe only at positions of fake sources?)
+* Count number of sources masked
+* Count number of fake sources above significance level as a function of fake source magnitude
+
+
+If the required density of fake sources is so high that they begin to
+overlap, we will need to do add sources, smooth, and count
+independently for each magnitude bin.  This could be optimised
+using the distributive property of convolutions (f*[g+h]=f*g+f*h)
+if we smooth the image first, and then add in smoothed PSFs.
+
+
+For a 5% statistical measurement of the detection efficiency per bin, we want
+dN/N = 0.05 ==> N ~ 400 for Poisson statistics.
+Assume a 80% masked fraction, so want 500 sources per bin.
+For 5 magnitude bins, want 2500 sources
+Assume worst case PSF is 15 pix FWHM --> ~ 51 pixels for 4-sigma either side
+Total area is 6502500 pixels.
+Chip images are 4846x4868 = 23590328 pixels = 3.6 times the worst total area.
+Not too bad (especially since this is pretty much worst case, and we only
+care about the central pixel, which is much smaller)
+==> Let's just throw all sources on the same image.
Index: branches/eam_branches/20090820/psphot/doc/notes.20090523.txt
===================================================================
--- branches/eam_branches/20090820/psphot/doc/notes.20090523.txt	(revision 25206)
+++ branches/eam_branches/20090820/psphot/doc/notes.20090523.txt	(revision 25766)
@@ -1,2 +1,29 @@
+
+20090809 : more on extended sources:
+
+ my algorithm for getting the petrosian radii and fluxes is:
+
+  * measure radial profile by interpolation to specific locations along the radial line
+    (at low radii, this gives much more accurate results; at high radii, we may need to 
+    average a group of pixels -- say, for 15 deg separations, choose a box that is 
+    < 5 degree in width -- this is > 1 pixel at a distance of 12 pixels.
+
+    psphotRadialProfilesByAngle
+
+  * find intersection of profile with isophot
+
+    psphotRadiusFromProfile -> r50(theta)
+
+  * generate r50x, r50y and fit to ellipse
+
+    psphotEllipticalContour
+
+  * generate elliptical profile
+
+    psphotEllipticalProfile
+
+  * convert to \alpha r_i < r < \beta r_i bins
+
+    psphotPetrosianRadialBins
 
 20090725 : extended source radial profiles
@@ -54,6 +81,4 @@
     *** get rest of math from my notebook...
 
-
-
 20090525 : some clarity of issues:
 
Index: branches/eam_branches/20090820/psphot/doc/notes.txt
===================================================================
--- branches/eam_branches/20090820/psphot/doc/notes.txt	(revision 25206)
+++ branches/eam_branches/20090820/psphot/doc/notes.txt	(revision 25766)
@@ -1,2 +1,93 @@
+
+2009.09.26
+
+  Remaining PSPHOT Issues:
+
+  o soften errors a bit for bright stars?  (essentially allow a
+    systematic error on the flat of some percentage).  this may help
+    the very saturated stars (peaks > 10k) which seem to be
+    excessively driven by the cores.
+    ** did not seem to be a big success --> makes things worse for f =
+    0.01, about the same for f = 0.005
+
+  o clean up and remove test bits of code.
+
+  o clean up psphot.config files : drop unused, fix some conflicting
+    names, reduce camera-specific options, make S/N limits
+    consistent...
+
+  * PSF Eval & ChiSq test??
+
+  * EXT fail fit?  lack of iterations?
+
+  * extended source output
+
+  * still some concerns with the source size analysis: the parameters
+    space seems fine (Mxx, Myy, nSigma), but we need to define more
+    sophisticated boundaries (perhaps include dMag or Mag).  
+
+  * some optimization issues:	      
+    * too many re-calculations of all magnitude / aperture data
+    * is FluxScale really faster?  do we need a finer mapping? (5x5
+      clearly yields too much scatter)
+    * is psphotFitSourcesLinear.c (build matrix) super-slow when optimized?
+
+  * very saturated stars are somewhat segmented.
+
+  * footprint coverage in dense simtest image 005.001?
+
+  * footprint S/N limit vs peaks S/N limit?
+
+  * warning about burntool table?
+
+  * is the residual map failing to be masked at the radius?
+
+  * PSF 2D convergence : how to choose between marginally different
+    options?  (note that the GPC1 images may go to 2x2 instead of 3x3)
+
+  * -visual needs more fine-grained control
+
+  * visualization graphs should reset the sections in general.
+
+  * some excess verbosity (my log level is 9, lower?)
+
+  ----- 
+
+  Apparently I'm getting bad psf vs ap mags because of the difference
+  between linear and non-linear fits.  I think this is due to the
+  weighting schemes:
+
+  psphotChoosePSF & psphotBlendFit depend on POISSON.ERRORS.PHOT.LMM,
+  which is set to TRUE => use Poisson errors
+
+  psphotFitSourcesLinear depends on CONSTANT_PHOTOMETRIC_WEIGHTS,
+  which is set to TRUE => do not use Poisson errors.
+
+  nothing seems to use the value POISSON.ERRORS.PHOT.LIN
+
+  ** Poisson errors seeem to be working much better than Constant
+     errors (as judged by consistency between PSF and APERTURE
+     magnitdues).  Not sure I understand this.  It could be that the
+     implementation of Constant errors in the linear fitting analysis
+     is busted.  
+
+  ** Also, I was getting some additional scatter from the FluxScale
+     (lookup-table for Io -> mags).  
+
+     * surprisingly, it is not clear that the FluxScale method is
+       faster than the more accurate integration technique...
+
+2009.09.25
+
+  Notes on pmSourceMagnitudes:
+
+  * in psphotChoosePSF, in pmPSFtry: raw PSF & raw AP
+  * in psphotChoosePSF, psphotMakeGrowthCurve: uses direct all to pmSourcePhotometryAper
+  * in psphotSourceSize, in psphotSourceSizePSF, raw PSF & raw AP (but uses moments->Sum) for PSF stars
+    NOTE: on the initial call, the PSF stars may have had multiple models tried and the psfMag
+    may not be the value for the chosen model.  
+  * in psphotSourceSize, in psphotSourceClassRegion, raw PSF & raw AP for all sources for which size is not yet measured.
+  * in psphotApResid: raw PSF & raw AP for STARS only
+  * in psphotMagnitudes; corrected PSF & AP mags
 
 2009.01.24
Index: branches/eam_branches/20090820/psphot/doc/outline.txt
===================================================================
--- branches/eam_branches/20090820/psphot/doc/outline.txt	(revision 25206)
+++ branches/eam_branches/20090820/psphot/doc/outline.txt	(revision 25766)
@@ -2,20 +2,55 @@
 Here is a summary outline of the steps taken by psphotReadout:
 
-* setup (choose recipe, choose readout, define break-point)
-* create mask and weight images if needed, set mask for analysis region
-* psphotImageMedian : construct a background model image and subtract it
-* psphotFindPeaks   : smooth and find the peak pixels from the smoothed image
-  - no pmSource defined yet, only pmPeak
-* psphotSourceStats : create sources for each peak and measure their moments
-  - pmSource defined here, with pixels covering SKY_OUTER_RADIUS
-  - no pmModel is defined yet.
-* psphotBasicDeblend : identify blended sources by proximity and valley depth
-* psphotRoughClass : source classification guess based on moments
-  - set the source.type,mode.
-  - re-calculate moments for saturated stars
-* psphotChoosePSF : define the psf model
-  - this generates model fits to the identified psf stars
-    (one for each tested model)
-  - these models are not kept (seems like a waste, but later fits must be consistent)
-* psphotGuessModels : set the initial PSF model for each object (even EXTENDED)
-  - creates modelPSF entries
+* setup (choose recipe, readout, etc)
+
+* create mask and weight images if needed
+
+* construct a background model image and subtract it
+
+* generate the significance image (smoothed by small Gaussian)
+
+* find peaks and associated footprints
+
+* create sources for each peak and measure moments
+  - scan over several window sigma values and choose an optimal window size
+  - at this stage, the moments are aimed at identifying psf-like objects
+
+* identify blended sources by proximity and valley depth
+
+* crude source classification guess based on moments & saturated pixels
+  - major goal is to identify the psf-stars
+  - allows for 2D variations in the psf 
+
+* use the selected PSF candidate stars to generate a PSF model	
+  - fits PSF model parameters as a function of position
+  - uses psfMag - apMag to choose order of 2D  (minimize systematic error in this value)
+  - generates a PSF residual image & optional 2D variations
+
+* fit all detected sources to the psf model (linear fit for normalization only)
+
+* high-quality source classification
+  - uses Mxx, Myy, psfMag - moment->Sum (equiv to apMags) 
+  * should the extended / psf cut be a function of galactic latitude?
+  * should the cosmic ray / psf cut be a function of galactic latitude?
+
+* non-linear fit for all brighter sources to single psf, double psf, or extended source model
+  - sources identified as extended above are fitted with extended source model
+  * are group / clumps of sources being fitted in the best way?
+  * is the psf-model ap mag being measured in an appropriate-size aperture?
+  * is the criterion for choosing between 2 psfs and extended source OK?
+  * is the test for double psf OK? (uses moments to guess starting positions)
+  
+* subtract, re-detect, measure faint sources (PSF-only)
+
+* optional extended source aperture-like measurements (petrosian, etc)
+
+* optional extended source non-linear fits (Sersic, etc)
+
+* measure psfMag-apMag correcion (2D)
+  * convert analysis to use systematic error measurement 
+
+* generate magnitudes
+
+* measure detection efficiency
+
+* output
Index: branches/eam_branches/20090820/psphot/src/Makefile.am
===================================================================
--- branches/eam_branches/20090820/psphot/src/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/Makefile.am	(revision 25766)
@@ -25,5 +25,7 @@
 libpsphot_la_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
 
-bin_PROGRAMS = psphot psphotTest psphotMomentsStudy
+bin_PROGRAMS = psphot psphotTest psphotMomentsStudy 
+# bin_PROGRAMS = psphotPetrosianStudy 
+# bin_PROGRAMS = psphot
 
 psphot_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
@@ -38,4 +40,8 @@
 psphotMomentsStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
 psphotMomentsStudy_LDADD = libpsphot.la
+
+# psphotPetrosianStudy_CFLAGS = $(PSPHOT_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
+# psphotPetrosianStudy_LDFLAGS = $(PSPHOT_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
+# psphotPetrosianStudy_LDADD = libpsphot.la
 
 psphot_SOURCES = \
@@ -61,4 +67,7 @@
 psphotMomentsStudy_SOURCES = \
         psphotMomentsStudy.c
+
+# psphotPetrosianStudy_SOURCES = \
+#         psphotPetrosianStudy.c
 
 libpsphot_la_SOURCES = \
@@ -104,9 +113,4 @@
 	psphotExtendedSourceAnalysis.c \
 	psphotExtendedSourceFits.c     \
-	psphotRadialProfile.c	       \
-	psphotPetrosian.c	       \
-	psphotIsophotal.c	       \
-	psphotAnnuli.c		       \
-	psphotKron.c		       \
 	psphotKernelFromPSF.c	       \
 	psphotPSFConvModel.c	       \
@@ -128,7 +132,26 @@
 	psphotCheckStarDistribution.c  \
 	psphotThreadTools.c  	       \
-	psphotAddNoise.c
+	psphotAddNoise.c               \
+	psphotRadialProfile.c	       \
+        psphotRadialProfileByAngles.c  \
+	psphotRadiiFromProfiles.c      \
+        psphotEllipticalContour.c      \
+        psphotEllipticalProfile.c      \
+	psphotPetrosian.c	       \
+        psphotPetrosianRadialBins.c    \
+        psphotPetrosianStats.c         \
+	psphotEfficiency.c
 
-# dropped? psphotGrowthCurve.c
+# re-instate these
+#	psphotIsophotal.c	       \
+#	psphotAnnuli.c		       \
+#	psphotKron.c		       \
+#       psphotPetrosianVisual.c        \
+#
+
+# test versions
+#       psphotPetrosianProfile.c       \
+#       psphotPetrosianAnalysis.c      \
+#
 
 include_HEADERS = \
Index: branches/eam_branches/20090820/psphot/src/psphot.h
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphot.h	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphot.h	(revision 25766)
@@ -49,14 +49,14 @@
 bool            psphotPSFstats (pmReadout *readout, psMetadata *recipe, pmPSF *psf);
 bool            psphotMomentsStats (pmReadout *readout, psMetadata *recipe, psArray *sources);
-bool            psphotFitSourcesLinear (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, bool final);
+bool            psphotFitSourcesLinear (pmReadout *readout, psArray *sources, const psMetadata *recipe, const pmPSF *psf, bool final);
 bool            psphotReplaceUnfitSources (psArray *sources, psImageMaskType maskVal);
 
 bool            psphotReplaceAllSources (psArray *sources, psMetadata *recipe);
-bool            psphotRemoveAllSources (psArray *sources, psMetadata *recipe);
+bool            psphotRemoveAllSources (const psArray *sources, const psMetadata *recipe);
 
 bool            psphotBlendFit (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf);
 bool            psphotBlendFit_Threaded (psThreadJob *job);
 
-psArray        *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections);
+psArray        *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections, bool setWindow);
 bool            psphotSourceStats_Threaded (psThreadJob *job);
 
@@ -64,5 +64,5 @@
 bool            psphotGuessModel_Threaded (psThreadJob *job);
 
-bool            psphotMagnitudes (pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources, pmPSF *psf);
+bool            psphotMagnitudes (pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources, const pmPSF *psf);
 bool            psphotMagnitudes_Threaded (psThreadJob *job);
 
@@ -71,9 +71,9 @@
 
 bool            psphotApResid (pmConfig *config, pmReadout *readout, psArray *sources, pmPSF *psf);
-bool            psphotApResidMags_Threaded (psThreadJob *job);
 
 bool            psphotSkyReplace (pmConfig *config, const pmFPAview *view);
 bool            psphotExtendedSourceAnalysis (pmReadout *readout, psArray *sources, psMetadata *recipe);
 bool            psphotExtendedSourceFits (pmReadout *readout, psArray *sources, psMetadata *recipe);
+bool            psphotEfficiency(pmConfig *config, pmReadout *readout, const pmFPAview *view, const pmPSF *psf, psMetadata *recipe, const psArray *realSources);
 
 // thread-related:
@@ -86,5 +86,5 @@
 psImage        *psphotSignificanceImage (pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal);
 psArray        *psphotFindPeaks (psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int nMax);
-bool            psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal);
+bool            psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int pass, psImageMaskType maskVal);
 psErrorCode     psphotCullPeaks(const psImage *img, const psImage *weight, const psMetadata *recipe, psArray *footprints);
 
@@ -93,6 +93,6 @@
 
 // used by ApResid
-bool            psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, psVector *mask, int nGroup);
-bool            psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag);
+pmTrend2D      *psphotApResidTrend (float *apResidSysErr, pmReadout *readout, int Nx, int Ny, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag);
+bool            psphotApResidMags_Threaded (psThreadJob *job);
 
 // basic support functions
@@ -108,4 +108,5 @@
 bool            psphotInitRadiusEXT (psMetadata *recipe, pmModelType type);
 bool            psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
+float           psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal);
 
 // output functions
@@ -147,7 +148,7 @@
 pmPSF          *psphotLoadPSF (pmConfig *config, const pmFPAview *view, psMetadata *recipe);
 bool            psphotSetHeaderNstars (psMetadata *recipe, psArray *sources);
-bool            psphotAddNoise (pmReadout *readout, psArray *sources, psMetadata *recipe);
-bool            psphotSubNoise (pmReadout *readout, psArray *sources, psMetadata *recipe);
-bool            psphotAddOrSubNoise (pmReadout *readout, psArray *sources, psMetadata *recipe, bool add);
+bool            psphotAddNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe);
+bool            psphotSubNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe);
+bool            psphotAddOrSubNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe, bool add);
 bool            psphotRadialPlot (int *kapa, const char *filename, pmSource *source);
 bool            psphotSourcePlots (pmReadout *readout, psArray *sources, psMetadata *recipe);
@@ -158,5 +159,5 @@
 bool            psphotSetState (pmSource *source, bool curState, psImageMaskType maskVal);
 bool            psphotDeblendSatstars (pmReadout *readout, psArray *sources, psMetadata *recipe);
-bool            psphotSourceSize (pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, long first);
+bool            psphotSourceSize (pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, long first);
 
 bool            psphotMakeResiduals (psArray *sources, psMetadata *recipe, pmPSF *psf, psImageMaskType maskVal);
@@ -166,9 +167,11 @@
 psKernel       *psphotKernelFromPSF (pmSource *source, int nPix);
 
-bool            psphotRadialProfile (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
-bool            psphotPetrosian (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
-bool            psphotIsophotal (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
-bool            psphotAnnuli (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
-bool            psphotKron (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
+// functions related to extended source analysis
+bool  psphotRadialProfile (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
+bool  psphotRadialProfilesByAngles (pmSource *source, int Nsec, float Rmax);
+float psphotRadiusFromProfile (pmSource *source, psVector *radius, psVector *flux, float fluxMin, float fluxMax);
+bool  psphotRadiiFromProfiles (pmSource *source, float fluxMin, float fluxMax);
+bool  psphotEllipticalProfile (pmSource *source);
+bool  psphotEllipticalContour (pmSource *source);
 
 // psphotVisual functions
@@ -189,6 +192,29 @@
 bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources);
 bool psphotVisualShowResidualImage (pmReadout *readout);
-bool psphotVisualPlotApResid (psArray *sources);
-bool psphotVisualPlotSourceSize (psArray *sources);
+bool psphotVisualPlotApResid (psArray *sources, float mean, float error);
+bool psphotVisualPlotSourceSize (psMetadata *recipe, psArray *sources);
+bool psphotVisualShowPetrosians (psArray *sources);
+
+// bool psphotPetrosianAnalysis (pmReadout *readout, psArray *sources, psMetadata *recipe);
+// bool psphotPetrosianProfile (pmReadout *readout, pmSource *source, float skynoise);
+
+bool psphotPetrosian (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal);
+bool psphotPetrosianRadialBins (pmSource *source, float radiusMax, float skynoise);
+bool psphotPetrosianStats (pmSource *source);
+
+// XXX old versions, currently disabled
+// bool            psphotIsophotal (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
+// bool            psphotAnnuli (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
+// bool            psphotKron (pmSource *source, psMetadata *recipe, psImageMaskType maskVal);
+
+// XXX visualization functions related to radial profiles (disabled)
+// bool psphotPetrosianVisualProfileByAngle (psVector *radius, psVector *flux);
+// bool psphotPetrosianVisualProfileRadii (psVector *radius, psVector *flux, psVector *radiusBin, psVector *fluxBin, float peakFlux, float RadiusRef);
+// bool psphotPetrosianVisualEllipticalContour (pmPetrosian *petrosian);
+// bool psphotPetrosianVisualStats (psVector *radBin, psVector *fluxBin, 
+// 				 psVector *refRadius, psVector *meanSB, 
+// 				 psVector *petRatio, psVector *petRatioErr, psVector *fluxSum, 
+// 				 float petRadius, float ratioForRadius,
+// 				 float petFlux, float radiusForFlux);
 
 bool psphotImageQuality (psMetadata *recipe, psArray *sources);
Index: branches/eam_branches/20090820/psphot/src/psphotAddNoise.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotAddNoise.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotAddNoise.c	(revision 25766)
@@ -1,13 +1,13 @@
 # include "psphotInternal.h"
 
-bool psphotAddNoise (pmReadout *readout, psArray *sources, psMetadata *recipe) {
+bool psphotAddNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe) {
   return psphotAddOrSubNoise (readout, sources, recipe, true);
 }
 
-bool psphotSubNoise (pmReadout *readout, psArray *sources, psMetadata *recipe) {
+bool psphotSubNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe) {
   return psphotAddOrSubNoise (readout, sources, recipe, false);
 }
 
-bool psphotAddOrSubNoise (pmReadout *readout, psArray *sources, psMetadata *recipe, bool add) {
+bool psphotAddOrSubNoise (pmReadout *readout, const psArray *sources, const psMetadata *recipe, bool add) {
 
     bool status = false;
@@ -42,5 +42,5 @@
     PS_ASSERT (status, false);
     if (isfinite(GAIN)) {
-	FACTOR /= GAIN;
+        FACTOR /= GAIN;
     }
 
@@ -50,4 +50,5 @@
 
         // skip sources which were not subtracted
+	// NOTE: this bit is not modified when pmSourceOp applies to noise
         if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) continue;
 
@@ -70,7 +71,7 @@
         oldshape.sxy = PAR[PM_PAR_SXY];
 
-	// XXX can this be done more intelligently?
-	if (oldI0 == 0.0) continue;
-	if (!isfinite(oldI0)) continue;
+        // XXX can this be done more intelligently?
+        if (oldI0 == 0.0) continue;
+        if (!isfinite(oldI0)) continue;
 
         // increase size and height of source
@@ -79,5 +80,5 @@
         axes.minor *= SIZE;
         newshape = psEllipseAxesToShape (axes);
-        PAR[PM_PAR_I0]  = FACTOR*PS_SQR(oldI0);
+        PAR[PM_PAR_I0]  = FACTOR*oldI0;
         PAR[PM_PAR_SXX] = newshape.sx;
         PAR[PM_PAR_SYY] = newshape.sy;
Index: branches/eam_branches/20090820/psphot/src/psphotApResid.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotApResid.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotApResid.c	(revision 25766)
@@ -33,10 +33,8 @@
     if (!measureAptrend) {
         // save nan values since these were not calculated
-        psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
-        psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
         psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
         psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
+        psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
         psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
-        psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
         return true;
     }
@@ -53,8 +51,10 @@
     maskVal |= markVal;
 
-    // S/N limit to perform full non-linear fits
+    // clipping for extreme outliers
+    // XXX this is not currently defined in the recipe
     float MAX_AP_OFFSET = psMetadataLookupF32 (&status, recipe, "MAX_AP_OFFSET");
 
-    // this is the smallest radius allowed: need to at least extend growth curve down to this...
+    // options for how the photometry is calculated
+    // XXX are these sensible?
     bool IGNORE_GROWTH = psMetadataLookupBool (&status, recipe, "IGNORE_GROWTH");
     bool INTERPOLATE_AP = psMetadataLookupBool (&status, recipe, "INTERPOLATE_AP");
@@ -100,4 +100,5 @@
 	    PS_ARRAY_ADD_SCALAR(job->args, photMode, PS_TYPE_S32);
 	    PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
+	    PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
 
 	    PS_ARRAY_ADD_SCALAR(job->args, 0,        PS_TYPE_S32); // this is used as a return value for Nskip
@@ -110,17 +111,4 @@
 	    }
 	    psFree(job);
-
-# if (0)
-		int nskip = 0;
-		int nfail = 0;
-
-		if (!psphotApResidMags_Unthreaded (&nskip, &nfail, sources, psf, photMode, maskVal)) {
-		    psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
-		    return false;
-		}
-		Nskip += nskip;
-		Nfail += nfail;
-# endif
-
 	}
 
@@ -138,7 +126,7 @@
 	    } else {
 		psScalar *scalar = NULL;
-		scalar = job->args->data[4];
+		scalar = job->args->data[5];
 		Nskip += scalar->data.S32;
-		scalar = job->args->data[5];
+		scalar = job->args->data[6];
 		Nfail += scalar->data.S32;
 	    }
@@ -150,5 +138,4 @@
 
     // gather the stats to assess the aperture residuals
-    psVector *mask    = psVectorAllocEmpty (300, PS_TYPE_VECTOR_MASK);
     psVector *mag     = psVectorAllocEmpty (300, PS_TYPE_F32);
     psVector *xPos    = psVectorAllocEmpty (300, PS_TYPE_F32);
@@ -158,4 +145,9 @@
     Npsf = 0;
 
+# ifdef DEBUG    
+    FILE *f = fopen ("apresid.dat", "w");
+    psAssert (f, "failed open");
+# endif
+
     for (int i = 0; i < sources->n; i++) {
         source = sources->data[i];
@@ -170,8 +162,12 @@
 	if (source->mode &  PM_SOURCE_MODE_EXT_LIMIT) SKIPSTAR ("EXTENDED");
 	if (source->mode &  PM_SOURCE_MODE_CR_LIMIT) SKIPSTAR ("COSMIC RAY");
+	if (source->mode &  PM_SOURCE_MODE_DEFECT) SKIPSTAR ("DEFECT");
 	    
         if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
             continue;
         }
+
+	// XXX make this user-configurable?
+	if (source->errMag > 0.01) continue;
 
         // aperture residual for this source
@@ -185,19 +181,24 @@
         }
 
-        mag->data.F32[Npsf]     = source->psfMag;
-        apResid->data.F32[Npsf] = dap;
-        xPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_XPOS];
-        yPos->data.F32[Npsf]    = model->params->data.F32[PM_PAR_YPOS];
-
-        mask->data.PS_TYPE_VECTOR_MASK_DATA[Npsf] = 0;
-
-        dMag->data.F32[Npsf] = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
-
-        psVectorExtend (mag,     100, 1);
-        psVectorExtend (mask,    100, 1);
-        psVectorExtend (xPos,    100, 1);
-        psVectorExtend (yPos,    100, 1);
-        psVectorExtend (dMag,    100, 1);
-        psVectorExtend (apResid, 100, 1);
+# ifdef DEBUG
+	fprintf (f, "%6.1f %6.1f : %6.1f %6.1f : %8.3f %8.3f %8.3f : %f : %f %f %f : %f\n",
+		 source->peak->xf, source->peak->yf, 
+		 source->modelPSF->params->data.F32[PM_PAR_XPOS], source->modelPSF->params->data.F32[PM_PAR_YPOS], 
+		 source->psfMag, source->apMag, source->errMag,
+		 source->modelPSF->params->data.F32[PM_PAR_I0], 
+		 source->modelPSF->params->data.F32[PM_PAR_SXX], source->modelPSF->params->data.F32[PM_PAR_SXY], source->modelPSF->params->data.F32[PM_PAR_SYY], 
+		 source->modelPSF->params->data.F32[PM_PAR_7]);
+# endif
+	if (!isfinite(source->psfMag)) psAbort ("nan in psfMag");
+	if (!isfinite(source->errMag)) psAbort ("nan in errMag");
+	if (!isfinite(source->apMag)) psAbort ("nan in apMag");
+	if (!isfinite(model->params->data.F32[PM_PAR_XPOS])) psAbort ("nan in xPos");
+	if (!isfinite(model->params->data.F32[PM_PAR_YPOS])) psAbort ("nan in yPos");
+
+        psVectorAppend (mag, source->psfMag);
+        psVectorAppend (dMag,source->errMag);
+        psVectorAppend (apResid, dap);
+        psVectorAppend (xPos, model->params->data.F32[PM_PAR_XPOS]);
+        psVectorAppend (yPos, model->params->data.F32[PM_PAR_YPOS]);
         Npsf ++;
     }
@@ -205,4 +206,8 @@
     psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "measure aperture residuals for %d objects (%d skipped, %d failed, %ld invalid)\n",
               Npsf, Nskip, Nfail, sources->n - Npsf - Nskip - Nfail);
+
+# ifdef DEBUG
+    fclose (f);
+# endif
 
     // XXX choose a better value here?
@@ -212,47 +217,149 @@
     }
 
-    // XXX deprecating the old code which allowed the ApResid to be fitted as a function of flux and r^2/flux
-    // XXX is this asymmetric clipping still needed?  this analysis should come after neighbors are subtracted...
-    // 3hi/1lo sigma clipping on the rflux vs metric fit
-    // systematic error information
-    float errorScale = 0.0;
-    float errorFloor = 0.0;
-
+    // XXX set the min number of needed source more carefully
+    if ((Npsf < 15) && (APTREND_ORDER_MAX >= 4)) APTREND_ORDER_MAX = 3;
+    if ((Npsf < 11) && (APTREND_ORDER_MAX >= 3)) APTREND_ORDER_MAX = 2;
+    if ((Npsf <  8) && (APTREND_ORDER_MAX >= 2)) APTREND_ORDER_MAX = 1;
+
+    psFree (psf->ApTrend);
+    psf->ApTrend = NULL;
     float errorFloorMin = FLT_MAX;
-    int entryMin = -1;
-
-    // Fit out the dap vs mag trend, iterate over spatial scale until error Floor increases.
-    // Stop if Npsf / (Nx * Ny) < 3
+
+    // as we loop over orders, we need to refer to the initial selection, but we modify the
+    // option values to match the current guess: save the max values here:
+    int NX = readout->image->numCols;
+    int NY = readout->image->numRows;
     for (int i = 1; i <= APTREND_ORDER_MAX; i++) {
-
-        if (!psphotApResidTrend (readout, psf, Npsf, i, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag)) {
-            break;
-        }
-
-        // store the resulting errorFloor values and the scales, redo the best
+	
+	int Nx, Ny;
+	if (NX > NY) {
+	    Nx = i;
+	    Ny = PS_MAX (1, (int)(i * (NY / (float)(NX)) + 0.5));
+	} else {
+	    Ny = i;
+	    Nx = PS_MAX (1, (int)(i * (NX / (float)(NY)) + 0.5));
+	}
+
+	float errorFloor;
+        pmTrend2D *apTrend = psphotApResidTrend (&errorFloor, readout, Nx, Ny, xPos, yPos, apResid, dMag);
+	if (!apTrend) {
+	    continue;
+	}
+
+	// apply ApTrend results
+	// float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
+	// float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
+	// float ApResid = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
+	// if (!isfinite(ApResid)) psAbort("nan apresid @ center");
+
+        // store the minimum errorFloor and best ApTrend to keep
         if (errorFloor < errorFloorMin) {
             errorFloorMin = errorFloor;
-            entryMin = i;
+	    psFree (psf->ApTrend);
+	    psf->ApTrend = psMemIncrRefCounter(apTrend);
         }
-    }
-    if (entryMin == -1) {
+	psFree (apTrend);
+    }
+    if (psf->ApTrend == NULL) {
         psWarning("Failed to find a valid aperture residual value");
 	goto escape;
     }
 
-    // XXX catch error condition
-    psphotApResidTrend (readout, psf, Npsf, entryMin, &errorScale, &errorFloor, mask, xPos, yPos, apResid, dMag);
+    // apply ApTrend results
+    float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
+    float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
+
+    psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
+    psf->dApResid = errorFloorMin;
+    psf->nApResid = Npsf;
+
+    // save results for later output
+    psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
+    psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
+    psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
+    psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
+
+    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
+    psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
+
+    psFree (xPos);
+    psFree (yPos);
+    psFree (apResid);
+    psFree (mag);
+    psFree (dMag);
+
+    psphotVisualPlotApResid (sources, psf->ApResid, psf->dApResid);
+
+    return true;
+
+escape:
+    // save nan values since these were not calculated
+    psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
+    psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
+    psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
+    psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
+
+    psFree (xPos);
+    psFree (yPos);
+    psFree (apResid);
+    psFree (mag);
+    psFree (dMag);
+    return false;
+}
+
+pmTrend2D *psphotApResidTrend (float *apResidSysErr, pmReadout *readout, int Nx, int Ny, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
+
+    // the mask marks the values not used to calculate the ApTrend
+    psVector *mask = psVectorAlloc(xPos->n, PS_TYPE_VECTOR_MASK);
+    psVectorInit (mask, 0);
+
+    // XXX allow user to set this optionally?
+    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN | PS_STAT_SAMPLE_STDEV);
+
+    // measure Trend2D for the current spatial scale
+    pmTrend2D *apTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
+
+    // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
+    // XXX use this or not?  probably not, since this is the point of the systematic error analysis
+    psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
+    for (int i = 0; i < dMag->n; i++) {
+        dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.005);
+    }
+
+    // XXX test for errors here
+    if (!pmTrend2DFit (apTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft)) {
+        psWarning("Failed to fit trend for %d x %d map", Nx, Ny);
+	psFree (apTrend);
+	return NULL;
+    }
+    if (apTrend->mode == PM_TREND_MAP) {
+	// p_psImagePrint (2, apTrend->map->map, "ApTrend Before"); // XXX TEST:
+	psImageMapRepair (apTrend->map->map);
+	// p_psImagePrint (2, apTrend->map->map, "ApTrend After"); // XXX TEST:
+    }
 
     // construct the fitted values and the residuals
-    psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
+    psVector *apResidFit = pmTrend2DEvalVector (apTrend, mask, 0xff, xPos, yPos);
     psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
-    psVector *dMagSys = (psVector *) psBinaryOp (NULL, (void *) dMag, "*", (void *) psScalarAlloc(errorScale, PS_TYPE_F32));
-
-    if (psTraceGetLevel("psphot") >= 2) {
-        FILE *dumpFile = fopen ("apresid.dat", "w");
+
+    // measure systematic error
+    *apResidSysErr = psVectorSystematicError (apResidRes, dMag, 0.10);
+    if (!isfinite(*apResidSysErr)) {
+        psWarning("Failed to find systematic error for %d x %d map", Nx, Ny);
+	psFree (apTrend);
+	return NULL;
+    }
+
+    psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid\n", Nx, Ny);
+    psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *apResidSysErr);
+
+    if (psTraceGetLevel("psphot") >= 4) {
+	char filename[64];
+	snprintf (filename, 64, "apresid.%dx%d.dat", Nx, Ny);
+        FILE *dumpFile = fopen (filename, "w");
         for (int i = 0; i < xPos->n; i++) {
-            fprintf (dumpFile, "%f %f  %f %f %f  %f %f  %x\n",
+            fprintf (dumpFile, "%f %f  %f %f  %f %f  %x\n",
                      xPos->data.F32[i], yPos->data.F32[i],
-                     mag->data.F32[i], dMag->data.F32[i], dMagSys->data.F32[i],
+                     dMag->data.F32[i], hypot(dMag->data.F32[i], *apResidSysErr),
                      apResid->data.F32[i], apResidRes->data.F32[i],
                      mask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
@@ -261,204 +368,5 @@
     }
 
-    // apply ApTrend results
-    float xc = 0.5*readout->image->numCols + readout->image->col0 + 0.5;
-    float yc = 0.5*readout->image->numRows + readout->image->row0 + 0.5;
-
-    psf->ApResid  = pmTrend2DEval (psf->ApTrend, xc, yc); // ap-fit at chip center
-    psf->dApResid = errorFloor;
-    psf->nApResid = Npsf;
-
-    // save results for later output
-    psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   0.0);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   0.0);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   psf->ApResid);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", psf->dApResid);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", psf->growth->apLoss);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", psf->nApResid);
-
-    psLogMsg ("psphot.apresid", PS_LOG_DETAIL, "aperture residual: %f +/- %f\n", psf->ApResid, psf->dApResid);
-    psLogMsg ("psphot.apresid", PS_LOG_INFO, "measure full-frame aperture residuals for %d sources: %f sec\n", Npsf, psTimerMark ("psphot.apresid"));
-
-    psFree (mag);
     psFree (mask);
-    psFree (xPos);
-    psFree (yPos);
-
-    psFree (apResid);
-    psFree (apResidFit);
-    psFree (apResidRes);
-
-    psFree (dMagSys);
-    psFree (dMag);
-
-    psphotVisualPlotApResid (sources);
-
-    return true;
-
-escape:
-    // save nan values since these were not calculated
-    psMetadataAdd (recipe, PS_LIST_TAIL, "SKYBIAS",  PS_DATA_F32 | PS_META_REPLACE, "aperture sky bias",   NAN);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "SKYSAT",   PS_DATA_F32 | PS_META_REPLACE, "aperture-determined saturation",   NAN);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "APMIFIT",  PS_DATA_F32 | PS_META_REPLACE, "aperture residual",   NAN);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "DAPMIFIT", PS_DATA_F32 | PS_META_REPLACE, "ap residual scatter", NAN);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "APLOSS",   PS_DATA_F32 | PS_META_REPLACE, "aperture loss (mag)", NAN);
-    psMetadataAdd (recipe, PS_LIST_TAIL, "NAPMIFIT", PS_DATA_S32 | PS_META_REPLACE, "number of apresid stars", 0);
-
-    psFree (mag);
-    psFree (mask);
-    psFree (xPos);
-    psFree (yPos);
-    psFree (apResid);
-    psFree (dMag);
-    return false;
-}
-
-/*
-  (aprMag' - fitMag) = rflux*skyBias + ApTrend(x,y)
-  (aprMag - rflux*skyBias) - fitMag = ApTrend(x,y)
-  (aprMag - rflux*skyBias) = fitMag + ApTrend(x,y)
-*/
-
-// XXX this still sucks...  need a better way to estimate the error floor...
-bool psphotMagErrorScale (float *errorScale, float *errorFloor, psVector *dMag, psVector *dap, psVector *mask, int nGroup) {
-
-    psStats *statsS = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
-    psStats *statsM = psStatsAlloc (PS_STAT_SAMPLE_MEAN);
-
-    // measure the trend in bins with 10 values each; if < 10 total, use them all
-    int nBin = PS_MAX (dMag->n / nGroup, 1);
-
-    // output vectors for ApResid trend
-    psVector *dSo = psVectorAlloc (nBin, PS_TYPE_F32);
-    psVector *dMo = psVectorAlloc (nBin, PS_TYPE_F32);
-    psVector *dRo = psVectorAlloc (nBin, PS_TYPE_F32);
-
-    // use dMag to group the dMag and dap vectors
-    psVector *index = psVectorSortIndex (NULL, dMag);
-
-    // subset vectors for dMag and dap values within the given range
-    psVector *dMSubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
-    psVector *dASubset = psVectorAllocEmpty (nGroup, PS_TYPE_F32);
-    psVector *mkSubset = psVectorAllocEmpty (nGroup, PS_TYPE_VECTOR_MASK);
-
-    int n = 0;
-    for (int i = 0; i < dMo->n; i++) {
-        int j;
-        for (j = 0; (j < nGroup) && (n < dMag->n); j++, n++) {
-            int N = index->data.U32[n];
-            dMSubset->data.F32[j] = dMag->data.F32[N];
-            dASubset->data.F32[j] = dap->data.F32[N];
-            mkSubset->data.PS_TYPE_VECTOR_MASK_DATA[j] = mask->data.PS_TYPE_VECTOR_MASK_DATA[N];
-        }
-        dMSubset->n = j;
-        dASubset->n = j;
-        mkSubset->n = j;
-
-        psStatsInit (statsS);
-        psStatsInit (statsM);
-
-        if (j > 2) {
-            if (!psVectorStats (statsS, dASubset, NULL, mkSubset, 0xff)) {
-		psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-		return false;
-	    }
-            if (!psVectorStats (statsM, dMSubset, NULL, mkSubset, 0xff)) {
-		psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-		return false;
-	    }
-            dSo->data.F32[i] = statsS->robustStdev;
-            dMo->data.F32[i] = statsM->sampleMean;
-            dRo->data.F32[i] = statsS->robustStdev / statsM->sampleMean;
-        } else {
-            dSo->data.F32[i] = NAN;
-            dMo->data.F32[i] = NAN;
-            dRo->data.F32[i] = NAN;
-        }
-    }
-    psFree (dMSubset);
-    psFree (dASubset);
-    psFree (mkSubset);
-
-    psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);
-    if (!psVectorStats (stats, dRo, NULL, NULL, 0)) {
-	psError(PS_ERR_UNKNOWN, false, "failure to measure stats");
-	return false;
-    }
-
-    *errorScale = stats->sampleMedian;
-    for (int i = 0; i < dSo->n; i++) {
-        *errorFloor = dSo->data.F32[i];
-        if (fabs(*errorFloor) <= FLT_EPSILON) continue;
-        if (isfinite(*errorFloor)) break;
-    }
-
-    psFree (stats);
-    psFree (index);
-
-    psFree (dRo);
-    psFree (dMo);
-    psFree (dSo);
-
-    psFree (statsS);
-    psFree (statsM);
-
-    return true;
-}
-
-bool psphotApResidTrend (pmReadout *readout, pmPSF *psf, int Npsf, int scale, float *errorScale, float *errorFloor, psVector *mask, psVector *xPos, psVector *yPos, psVector *apResid, psVector *dMag) {
-
-    int Nx, Ny;
-
-    if (readout->image->numCols > readout->image->numRows) {
-        Nx = scale;
-        float AR = readout->image->numRows / (float) readout->image->numCols;
-        Ny = (int) (Nx * AR + 0.5);
-        Ny = PS_MAX (1, Ny);
-    } else {
-        Ny = scale;
-        float AR = readout->image->numRows / (float) readout->image->numCols;
-        Nx = (int) (Ny * AR + 0.5);
-        Nx = PS_MAX (1, Nx);
-    }
-
-    // require at least 10 stars per spatial bin
-    if (Npsf < 10*Nx*Ny) {
-        return false;
-    }
-
-    // the mask marks the values not used to calculate the ApTrend
-    psVectorInit (mask, 0);
-
-    // XXX stats structure for use by ApTrend : make parameters user setable
-    psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
-    stats->min = 2.0;
-    stats->max = 3.0;
-
-    // measure Trend2D for the current spatial scale
-    psFree (psf->ApTrend);
-    psf->ApTrend = pmTrend2DAlloc (PM_TREND_MAP, readout->image, Nx, Ny, stats);
-
-    // XXX somewhat arbitrary: soften the errors so the few bright stars do not totally dominate:
-    psVector *dMagSoft = psVectorAlloc (dMag->n, PS_TYPE_F32);
-    for (int i = 0; i < dMag->n; i++) {
-        dMagSoft->data.F32[i] = hypot(dMag->data.F32[i], 0.01);
-    }
-
-    // XXX test for errors here
-    pmTrend2DFit (psf->ApTrend, mask, 0xff, xPos, yPos, apResid, dMagSoft);
-
-    // construct the fitted values and the residuals
-    psVector *apResidFit = pmTrend2DEvalVector (psf->ApTrend, mask, 0xff, xPos, yPos);
-    psVector *apResidRes = (psVector *) psBinaryOp (NULL, (void *) apResid, "-", (void *) apResidFit);
-
-    // measure systematic errorFloor & systematic / photon scale factor
-    // XXX this is a bit arbitrary, but it forces ~3 stars from the bright bin per spatial bin
-    int nGroup = PS_MAX (3*Nx*Ny, 10);
-    psphotMagErrorScale (errorScale, errorFloor, dMag, apResidRes, mask, nGroup);
-
-    psLogMsg ("psphot.apresid", PS_LOG_INFO, "result of %d x %d grid (%d stars per bin)\n", Nx, Ny, nGroup);
-    psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic error / photon error: %f\n", *errorScale);
-    psLogMsg ("psphot.apresid", PS_LOG_INFO, "systematic scatter floor: %f\n", *errorFloor);
-
     psFree (stats);
     psFree (dMagSoft);
@@ -466,5 +374,5 @@
     psFree (apResidRes);
 
-    return true;
+    return apTrend;
 }
 
@@ -480,4 +388,5 @@
     pmSourcePhotometryMode photMode = PS_SCALAR_VALUE(job->args->data[2],S32);
     psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[3],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
 
     for (int i = 0; i < sources->n; i++) {
@@ -490,61 +399,42 @@
         if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
 
-        if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
-            Nskip ++;
-            psTrace ("psphot", 3, "skip : bad source mag");
-            continue;
+        // replace object in image
+        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
+            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
         }
 
-        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
-            Nfail ++;
-            psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
-            continue;
-        }
-        source->mode |= PM_SOURCE_MODE_AP_MAGS;
+	// clear the mask bit and set the circular mask pixels
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
+	psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
+
+	bool status = pmSourceMagnitudes (source, psf, photMode, maskVal);
+
+	// clear the mask bit 
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
+
+        // re-subtract the object, leave local sky
+        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+
+	if (!status) {
+	    Nskip ++;
+	    psTrace ("psphot", 3, "skip : bad source mag");
+	    continue;
+	}
+    
+	if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
+	    Nfail ++;
+	    psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
+	    continue;
+	}
+	source->mode |= PM_SOURCE_MODE_AP_MAGS;
     }
 
     // change the value of a scalar on the array (wrap this and put it in psArray.h)
-    scalar = job->args->data[4];
+    scalar = job->args->data[5];
     scalar->data.S32 = Nskip;
 
-    scalar = job->args->data[5];
+    scalar = job->args->data[6];
     scalar->data.S32 = Nfail;
 
     return true;
 }
-
-# if (0)
-bool psphotApResidMags_Unthreaded (int *nskip, int *nfail, psArray *sources, pmPSF *psf, pmSourcePhotometryMode photMode, psImageMaskType maskVal) {
-
-    int Nskip = 0;
-    int Nfail = 0;
-
-    for (int i = 0; i < sources->n; i++) {
-        pmSource *source = (pmSource *) sources->data[i];
-
-        if (source->type != PM_SOURCE_TYPE_STAR) SKIPSTAR ("NOT STAR");
-        if (source->mode &  PM_SOURCE_MODE_SATSTAR) SKIPSTAR ("SATSTAR");
-        if (source->mode &  PM_SOURCE_MODE_BLEND) SKIPSTAR ("BLEND");
-        if (source->mode &  PM_SOURCE_MODE_FAIL) SKIPSTAR ("FAIL STAR");
-        if (source->mode &  PM_SOURCE_MODE_POOR) SKIPSTAR ("POOR STAR");
-
-        if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
-            Nskip ++;
-            psTrace ("psphot", 3, "skip : bad source mag");
-            continue;
-        }
-
-        if (!isfinite(source->apMag) || !isfinite(source->psfMag)) {
-            Nfail ++;
-            psTrace ("psphot", 3, "fail : nan mags : %f %f", source->apMag, source->psfMag);
-            continue;
-        }
-    }
-
-    // change the value of a scalar on the array (wrap this and put it in psArray.h)
-    *nskip = Nskip;
-    *nfail = Nfail;
-
-    return true;
-}
-# endif
Index: branches/eam_branches/20090820/psphot/src/psphotBlendFit.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotBlendFit.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotBlendFit.c	(revision 25766)
@@ -254,5 +254,4 @@
         pmSourceCacheModel (source, maskVal);
         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-        source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     }
 
@@ -365,5 +364,4 @@
         pmSourceCacheModel (source, maskVal);
         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-        source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     }
 
@@ -374,4 +372,8 @@
     *nfail = Nfail;
 
+    // moments are modified by the fit; re-display
+    psphotVisualPlotMoments (recipe, sources);
+    psphotVisualShowResidualImage (readout);
+
     return true;
 }
Index: branches/eam_branches/20090820/psphot/src/psphotChoosePSF.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotChoosePSF.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotChoosePSF.c	(revision 25766)
@@ -1,18 +1,3 @@
 # include "psphotInternal.h"
-
-void psphotCountPSFStars (psArray *sources) {
-
-    int nPSF = 0;
-
-    // select the candidate PSF stars (pointers to original sources)
-    for (int i = 0; i < sources->n; i++) {
-        pmSource *source = sources->data[i];
-        if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
-            nPSF ++;
-        }
-    }
-
-    fprintf (stderr, "N PSF: %d\n", nPSF);
-}
 
 // try PSF models and select best option
@@ -73,6 +58,18 @@
     // get the fixed PSF fit radius
     // XXX check that PSF_FIT_RADIUS < SKY_OUTER_RADIUS
-    options->radius = psMetadataLookupF32 (&status, recipe, "PSF_FIT_RADIUS");
-    assert (status);
+    // options->radius = psMetadataLookupF32 (&status, recipe, "PSF_FIT_RADIUS");
+    // assert (status);
+
+    // We have calculated a Gaussian window function, use that for both the PSF fit radius and
+    // the aperture radius (scaling SIGMA)
+    float gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
+    float fitScale = psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS_SCALE");
+    float apScale = psMetadataLookupF32(&status, recipe, "PSF_APERTURE_SCALE");
+    options->fitRadius = (int)(fitScale*gaussSigma);
+    options->apRadius = (int)(apScale*gaussSigma);
+
+    // XXX use the same radii for standard analysis as for the PSF creation
+    psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_FIT_RADIUS", PS_META_REPLACE, "fit radius", options->fitRadius);
+    psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_APERTURE", PS_META_REPLACE, "psf aperture", options->apRadius);
 
     // XXX ROBUST seems to be too agressive given the small numbers.
@@ -99,6 +96,4 @@
 
     psArray *stars = psArrayAllocEmpty (sources->n);
-
-    // psphotCountPSFStars (sources);
 
     // select the candidate PSF stars (pointers to original sources)
@@ -115,11 +110,7 @@
     }
 
-    // psphotCountPSFStars (sources);
-
     // check that the identified psf stars sufficiently cover the region; if not, extend the
     // limits somewhat
     psphotCheckStarDistribution (stars, sources, options);
-
-    // psphotCountPSFStars (sources);
 
     psLogMsg ("psphot.pspsf", PS_LOG_DETAIL, "selected candidate %ld PSF objects\n", stars->n);
@@ -289,10 +280,8 @@
     // XXX test dump of psf star data and psf-subtracted image
     if (psTraceGetLevel("psphot.psfstars") > 5) {
-        psphotDumpPSFStars (readout, try, options->radius, maskVal, markVal);
+        psphotDumpPSFStars (readout, try, options->fitRadius, maskVal, markVal);
     }
 
     // save only the best model;
-    // XXX we are not saving the fitted sources
-    // XXX do we want to keep them so we may optionally write them out?
     pmPSF *psf = psMemIncrRefCounter(try->psf);
     psFree (models);
@@ -305,6 +294,4 @@
     }
 
-    // psphotCountPSFStars (sources);
-
     char *modelName = pmModelClassGetName (psf->type);
     psLogMsg ("psphot.pspsf", PS_LOG_INFO, "select psf model: %f sec\n", psTimerMark ("psphot.choose.psf"));
@@ -341,5 +328,8 @@
             // create modelPSF from this model
             pmModel *modelPSF = pmModelFromPSFforXY (psf, xc, yc, 1.0);
-            if (!modelPSF) continue;
+            if (!modelPSF) {
+		fprintf (stderr, "?");
+		continue;
+	    }
 
             // get the model full-width at half-max
@@ -354,5 +344,8 @@
 
             float FWHM_MINOR = FWHM_MAJOR * (axes.minor / axes.major);
-            if (!isfinite(FWHM_MAJOR) || !isfinite(FWHM_MINOR)) continue;
+            if (!isfinite(FWHM_MAJOR) || !isfinite(FWHM_MINOR)) {
+		fprintf (stderr, "!");
+		continue;
+	    }
             psVectorAppend (fwhmMajor, FWHM_MAJOR);
             psVectorAppend (fwhmMinor, FWHM_MINOR);
Index: branches/eam_branches/20090820/psphot/src/psphotEfficiency.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotEfficiency.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotEfficiency.c	(revision 25766)
@@ -0,0 +1,480 @@
+# include "psphotInternal.h"
+
+#define MODEL_MASK (PM_MODEL_STATUS_NONCONVERGE | PM_MODEL_STATUS_OFFIMAGE | \
+                    PM_MODEL_STATUS_BADARGS | PM_MODEL_STATUS_LIMITS) // Mask to apply to models
+
+//#define TESTING
+
+
+// Calculate the limiting magnitude for an image
+//
+// We limit ourselves to calculating the peak flux in the smoothed image, which should be close (modulo
+// non-Gaussian PSF) to the limiting flux in the un-smoothed original image.
+static bool effLimit(float *magLim,           // Limiting magntiude, to return
+                     int *radius,             // Radius for fake sources, to return
+                     float *minFlux,          // Minimum flux for fake sources, to return
+                     float *norm,             // Normalisation of PSF (conversion: peak --> integrated flux)
+                     float *covarFactor,// Covariance factor
+                     const pmReadout *ro,     // Readout of interest
+                     const pmPSF *psf,        // Point-spread function
+                     float thresh,            // Threshold for source identification
+                     float smoothSigma,       // Gaussian smoothing sigma
+                     float smoothNsigma,      // Smoothing limit
+                     psImageMaskType maskVal  // Value to mask
+                     )
+{
+    PM_ASSERT_READOUT_NON_NULL(ro, false);
+    PM_ASSERT_READOUT_VARIANCE(ro, false);
+    assert(magLim);
+    assert(radius);
+    assert(minFlux);
+    assert(norm);
+    assert(covarFactor);
+
+    psKernel *kernel = psImageSmoothKernel(smoothSigma, smoothNsigma); // Kernel used for smoothing
+    psKernel *newCovar = psImageCovarianceCalculate(kernel, ro->covariance); // Covariance matrix
+    psFree(kernel);
+    *covarFactor = psImageCovarianceFactor(newCovar); // Variance factor
+    psFree(newCovar);
+
+    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for variance
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);        // Random number generator
+    if (!psImageBackground(stats, NULL, ro->variance, ro->mask, maskVal, rng) ||
+        !isfinite(stats->robustMedian)) {
+        psError(PSPHOT_ERR_DATA, false, "Unable to determine mean variance");
+        psFree(stats);
+        psFree(rng);
+        return false;
+    }
+    psFree(rng);
+    float meanVar = stats->robustMedian; // Mean variance
+    psFree(stats);
+
+    // Need to normalise out difference between Gaussian and real PSF
+    pmModel *normModel = pmModelFromPSFforXY(psf, 0.5 * ro->variance->numCols,
+                                             0.5 * ro->variance->numRows, 1.0); // Model for normalisation
+    if (!normModel || (normModel->flags & MODEL_MASK)) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate PSF model.");
+        psFree(normModel);
+        return false;
+    }
+    *norm = normModel->modelFlux(normModel->params); // Total flux for peak of 1.0
+    psFree(normModel);
+
+    // The signal-to-noise of the smoothed image is: S/N ~ I_smooth / sqrt(variance * factor)
+    // since the variance factor tells us the variance in the smoothed image.  Now, the trick is working
+    // out what the intensity in the smoothed image is, and how it is related to the flux.  We are
+    // convolving Io G_* with G_PSF/2pi.w^2, where G_* is the approximately-Gaussian PSF of the star,
+    // G_PSF is the pretty-close-matching Gaussian of the convolution kernel, Io is the peak flux in the
+    // unsmoothed image, and w is the width of the Gaussian.  Now, a normalised 2D Gaussian convolved
+    // with itself has a normalisation of 1/2pi(w^2+w^2) = 1/4pi.w^2.  Therefore:
+    // I_smooth = Flux / 2*norm.
+    float peakLim = thresh * sqrtf(meanVar * *covarFactor); // Limiting peak value in smoothed image
+    float fluxLim = 2.0 * *norm * peakLim; // Limiting flux in original
+    *magLim = -2.5 * log10f(fluxLim);
+    psTrace("psphot.fake", 1, "Limiting peak: %f\n", peakLim);
+    psTrace("psphot.fake", 1, "Limiting flux: %f\n", fluxLim);
+    psTrace("psphot.fake", 1, "Limiting mag: %f\n", *magLim);
+
+    *radius = smoothSigma * smoothNsigma;
+
+    *minFlux = 0.1 * sqrtf(meanVar);
+
+    return true;
+}
+
+/// Generate a fake image and add it in to the existing readout
+static bool effGenerate(psImage **xSrc, psImage **ySrc, // Positions of sources
+                        const pmReadout *ro,            // Readout of interest
+                        const pmPSF *psf,               // Point-spread function
+                        const psVector *magOffsets,     // Magnitude offsets for fake sources
+                        int numSources,                 // Number of fake sources for each bin
+                        float refMag,                   // Reference magnitude
+                        int radius,                     // Radius for fake sources
+                        float minFlux                   // Minimum flux for fake sources
+                        )
+{
+    PM_ASSERT_READOUT_NON_NULL(ro, false);
+    PM_ASSERT_READOUT_IMAGE(ro, false);
+    PS_ASSERT_VECTOR_NON_NULL(magOffsets, false);
+    PS_ASSERT_VECTOR_TYPE(magOffsets, PS_TYPE_F32, false);
+    assert(xSrc);
+    assert(ySrc);
+
+    int numBins = magOffsets->n;                                    // Number of bins
+    int numCols = ro->image->numCols, numRows = ro->image->numRows; // Size of image
+
+    *xSrc = psImageRecycle(*xSrc, numSources, numBins, PS_TYPE_F32);
+    *ySrc = psImageRecycle(*ySrc, numSources, numBins, PS_TYPE_F32);
+
+    psVector *xAll = psVectorAlloc(numBins * numSources, PS_TYPE_F32);
+    psVector *yAll = psVectorAlloc(numBins * numSources, PS_TYPE_F32);
+    psVector *magAll = psVectorAlloc(numBins * numSources, PS_TYPE_F32);
+
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
+    for (int i = 0, index = 0; i < numBins; i++) {
+        float mag = refMag + magOffsets->data.F32[i]; // Instrumental magnitude of sources
+
+        for (int j = 0; j < numSources; j++, index++) {
+            xAll->data.F32[index] = psRandomUniform(rng) * numCols;
+            yAll->data.F32[index] = psRandomUniform(rng) * numRows;
+            magAll->data.F32[index] = mag;
+        }
+        memcpy((*xSrc)->data.F32[i], &xAll->data.F32[i * numSources],
+               numSources * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+        memcpy((*ySrc)->data.F32[i], &yAll->data.F32[i * numSources],
+               numSources * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+    }
+    psFree(rng);
+
+    pmReadout *fakeRO = pmReadoutAlloc(NULL); // Fake readout
+    if (!pmReadoutFakeFromVectors(fakeRO, numCols, numRows, xAll, yAll, magAll,
+                                  NULL, NULL, psf, minFlux, radius, false, true)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to generate fake image");
+        psFree(fakeRO);
+        psFree(magAll);
+        psFree(xAll);
+        psFree(yAll);
+        return false;
+    }
+    psFree(magAll);
+    psFree(xAll);
+    psFree(yAll);
+
+    psBinaryOp(ro->image, ro->image, "+", fakeRO->image);
+    psFree(fakeRO);
+
+    return true;
+}
+
+
+// Determine detection efficiency
+bool psphotEfficiency(pmConfig *config, pmReadout *readout, const pmFPAview *view, const pmPSF *psf,
+                psMetadata *recipe, const psArray *realSources)
+{
+    PM_ASSERT_READOUT_NON_NULL(readout, false);
+    PM_ASSERT_READOUT_IMAGE(readout, false);
+    PS_ASSERT_PTR_NON_NULL(psf, false);
+    PS_ASSERT_METADATA_NON_NULL(recipe, false);
+    PS_ASSERT_ARRAY_NON_NULL(realSources, false);
+
+    psTimerStart("psphot.fake");
+
+    // Collect recipe information
+    float fwhmMajor = psMetadataLookupF32(NULL, recipe, "FWHM_MAJ"); // PSF size in x
+    float fwhmMinor = psMetadataLookupF32(NULL, recipe, "FWHM_MIN"); // PSF size in y
+    if (!isfinite(fwhmMajor) || !isfinite(fwhmMinor) || fwhmMajor == 0.0 || fwhmMinor == 0.0) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find FWHM_MAJ and FWHM_MIN in recipe");
+        return false;
+    }
+    float smoothNsigma = psMetadataLookupF32(NULL, recipe, "PEAKS_SMOOTH_NSIGMA"); // Smoothing limit
+    if (!isfinite(smoothNsigma)) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find PEAKS_SMOOTH_NSIGMA in recipe");
+        return false;
+    }
+    float thresh = psMetadataLookupF32(NULL, recipe, "PEAKS_NSIGMA_LIMIT_2");
+    if (!isfinite(thresh)) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find PEAKS_NSIGMA_LIMIT_2 in recipe");
+        return false;
+    }
+    psVector *magOffsets = psMetadataLookupVector(NULL, recipe, "EFF.MAG"); // Magnitude offsets
+    if (!magOffsets || magOffsets->type.type != PS_TYPE_F32) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find EFF.MAG F32 vector in recipe");
+        return NULL;
+    }
+    int numSources = psMetadataLookupS32(NULL, recipe, "EFF.NUM"); // Number of sources for each bin
+    if (numSources == 0) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find EFF.NUM in recipe");
+        return NULL;
+    }
+    float minGauss = psMetadataLookupF32(NULL, recipe, "PEAKS_MIN_GAUSS"); // Minimum valid fraction of kernel
+    if (!isfinite(minGauss)) {
+        psWarning("PEAKS_MIN_GAUSS is not set in recipe; using default value");
+        minGauss = 0.5;
+    }
+
+    float smoothSigma = 0.5*(fwhmMajor + fwhmMinor) / (2.0*sqrtf(2.0*log(2.0))); // Gaussian smoothing sigma
+    int numCols = readout->image->numCols, numRows = readout->image->numRows; // Size of image
+    int numBins = magOffsets->n;                          // Number of bins
+
+    psImageMaskType maskVal = psMetadataLookupImageMask(NULL, recipe, "MASK.PSPHOT"); // Value to mask
+
+    // remove all sources, adding noise for subtracted sources
+    psphotRemoveAllSources(realSources, recipe);
+    //    psphotAddNoise(readout, realSources, recipe);
+
+
+#if defined(TESTING) && 0
+    {
+        psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);
+        for (int y = 0; y < numRows; y++) {
+            for (int x = 0; x < numCols; x++) {
+                readout->image->data.F32[y][x] = psRandomGaussian(rng);
+                readout->variance->data.F32[y][x] = 1.0;
+                readout->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0;
+            }
+        }
+        psFree(readout->covariance);
+        readout->covariance = NULL;
+        psFree(rng);
+    }
+#endif
+
+
+
+    float magLim;                       // Guess at limiting magnitude
+    int radius;                         // Radius for fake sources
+    float minFlux;                      // Minimum flux for fake sources
+    float norm;                         // Normalisation of PSF
+    float covarFactor;                  // Covariance factor
+    if (!effLimit(&magLim, &radius, &minFlux, &norm, &covarFactor, readout,
+                  psf, thresh, smoothSigma, smoothNsigma, maskVal)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to determine limits for image");
+        return false;
+    }
+
+#ifdef TESTING
+    psphotSaveImage(NULL, readout->image, "orig_image.fits");
+    psphotSaveImage(NULL, readout->variance, "orig_variance.fits");
+    psphotSaveImage(NULL, readout->mask, "orig_mask.fits");
+#endif
+
+    psImage *xFake = NULL, *yFake = NULL; // Coordinates of sources, each bin in a row
+    if (!effGenerate(&xFake, &yFake, readout, psf, magOffsets,
+                     numSources, magLim, radius, minFlux)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to generate fake sources");
+        psFree(xFake);
+        psFree(yFake);
+        return false;
+    }
+
+#ifdef TESTING
+    psphotSaveImage(NULL, readout->image, "fake_image.fits");
+    psphotSaveImage(NULL, readout->variance, "fake_variance.fits");
+    psphotSaveImage(NULL, readout->mask, "fake_mask.fits");
+#endif
+
+    // XXX Could speed this up significantly by only convolving the central pixels of each fake source
+    psVector *significance = NULL;       // Significance image
+    {
+        int num = numSources * numBins; // Total number of sources
+        // Pixel coordinates of sources
+        psVector *xPix = psVectorAlloc(num, PS_TYPE_S32);
+        psVector *yPix = psVectorAlloc(num, PS_TYPE_S32);
+        for (int i = 0, index = 0; i < numBins; i++) {
+            for (int j = 0; j < numSources; j++, index++) {
+                float x = xFake->data.F32[i][j];
+                float y = yFake->data.F32[i][j];
+                xPix->data.S32[index] = PS_MIN(x + 0.5, numCols - 1);
+                yPix->data.S32[index] = PS_MIN(y + 0.5, numRows - 1);
+            }
+        }
+
+        psVector *convImage = psImageSmoothMaskPixels(readout->image, readout->mask, maskVal, xPix, yPix,
+                                                      smoothSigma, smoothNsigma, minGauss); // Convolved image
+        if (!convImage) {
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to smooth image pixels");
+            psFree(xPix);
+            psFree(yPix);
+            psFree(xFake);
+            psFree(yFake);
+            return false;
+        }
+        psVector *convVar = psImageSmoothMaskPixels(readout->variance, readout->mask, maskVal, xPix, yPix,
+                                                    smoothSigma, smoothNsigma, minGauss); // Convolved varianc
+        if (!convVar) {
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to smooth variance pixels");
+            psFree(xPix);
+            psFree(yPix);
+            psFree(xFake);
+            psFree(yFake);
+            return false;
+        }
+
+        float factor = 1.0 / covarFactor; // Correction for covariance
+
+        const psImage *mask = readout->mask;  // Mask for readout
+        for (int i = 0; i < num; i++) {
+            float imageVal = convImage->data.F32[i]; // Image value
+            float varVal = convVar->data.F32[i]; // Variance value
+            int x = xPix->data.S32[i], y = yPix->data.S32[i]; // Coordinates
+            if (imageVal < 0 || varVal <= 0 || (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal)) {
+                convImage->data.F32[i] = 0.0;
+            } else {
+                convImage->data.F32[i] = factor * PS_SQR(imageVal) / varVal;
+            }
+        }
+
+        psFree(xPix);
+        psFree(yPix);
+
+        significance = convImage;
+        psFree(convVar);
+    }
+
+    thresh *= thresh;                   // "Significance" is actually significance-squared
+
+    psVector *count = psVectorAlloc(numBins, PS_TYPE_S32); // Number of sources found in each bin
+    psArray *fakeSources = psArrayAlloc(numSources);            // Fake sources in each bin
+    psArray *fakeSourcesAll = psArrayAllocEmpty(numSources * numBins); // All fake sources
+    for (int i = 0, index = 0; i < numBins; i++) {
+        int numFound = 0;               // Number found
+
+        // Determine extraction size
+        float mag = magLim + magOffsets->data.F32[i]; // Magnitude for bin
+        float peak = powf(10.0, -0.4 * mag) / norm;   // Peak flux
+        pmModel *model = pmModelFromPSFforXY(psf, numCols / 2.0, numRows / 2.0, peak); // Model for source
+        if (!model || (model->flags & MODEL_MASK)) {
+            psError(PS_ERR_UNKNOWN, true, "Unable to generate model for bin %d", i);
+            psFree(model);
+            return false;
+        }
+        float sourceRadius = PS_MAX(radius, model->modelRadius(model->params, minFlux)); // Radius for source
+        psFree(model);
+
+        psArray *sources = psArrayAllocEmpty(numSources); // Sources in this bin
+        for (int j = 0; j < numSources; j++, index++) {
+            // Coordinates of interest
+            float sig = significance->data.F32[index]; // Significance of pixel
+            if (sig > thresh) {
+                pmSource *source = pmSourceAlloc(); // Fake source
+                float x = xFake->data.F32[i][j];
+                float y = yFake->data.F32[i][j];
+                source->peak = pmPeakAlloc(x, y, sig, PM_PEAK_LONE);
+                if (!pmSourceDefinePixels(source, readout, x, y, sourceRadius)) {
+                    psErrorClear();
+                    continue;
+                }
+                source->peak->xf = x;
+                source->peak->yf = y;
+                source->modelPSF = pmModelFromPSFforXY(psf, x, y, 2.0 * sqrtf(sig));
+                source->type = PM_SOURCE_TYPE_STAR;
+
+                numFound++;
+                psArrayAdd(sources, sources->n, source);
+                psArrayAdd(fakeSourcesAll, fakeSourcesAll->n, source);
+                psFree(source);
+            }
+        }
+        fakeSources->data[i] = sources;
+        count->data.S32[i] = numFound;
+    }
+    psFree(xFake);
+    psFree(yFake);
+    psFree(significance);
+
+    if (!psphotFitSourcesLinear(readout, fakeSourcesAll, recipe, psf, true)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to perform linear fit on fake sources.");
+        psFree(fakeSources);
+        psFree(count);
+        return false;
+    }
+
+    // Disable aperture corrections; casting away const!
+    pmTrend2D *apTrend = psf->ApTrend;  // Aperture trend
+    ((pmPSF*)psf)->ApTrend = NULL;
+
+    if (!psphotMagnitudes(config, readout, view, fakeSourcesAll, psf)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to measure magnitudes of fake sources.");
+        psFree(fakeSources);
+        psFree(count);
+        ((pmPSF*)psf)->ApTrend = apTrend; // Casting away const!
+        return false;
+    }
+    psFree(fakeSourcesAll);
+
+    // Re-enable aperture corrections; casting away const!
+    ((pmPSF*)psf)->ApTrend = apTrend;
+
+    psVector *magDiffMean = psVectorAlloc(numBins, PS_TYPE_F32); // Mean difference in magnitude for each bin
+    psVector *magDiffStdev = psVectorAlloc(numBins, PS_TYPE_F32); // Stdev of diff in magnitude for each bin
+    psVector *magErrMean = psVectorAlloc(numBins, PS_TYPE_F32); // Mean error in magnitude for each bin
+    psVector *magDiff = psVectorAlloc(numSources, PS_TYPE_F32);   // Magnitude differences
+    psVector *magErr = psVectorAlloc(numSources, PS_TYPE_F32);   // Magnitude errors
+    psVector *magMask = psVectorAlloc(numSources, PS_TYPE_VECTOR_MASK); // Mask for magnitude errors
+    psStats *magStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN | PS_STAT_SAMPLE_STDEV |
+                                     PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics
+    for (int i = 0; i < numBins; i++) {
+        psStatsInit(magStats);
+        psVectorInit(magMask, 0);
+
+#ifdef TESTING
+        psString name = NULL;
+        psStringAppend(&name, "fake_%d.dat", i);
+        FILE *file = fopen(name, "w");
+        psFree(name);
+#endif
+
+        float magRef = magLim + magOffsets->data.F32[i]; // Reference magnitude
+        psArray *sources = fakeSources->data[i];         // Sources in bin
+        for (int j = 0; j < sources->n; j++) {
+            pmSource *source = sources->data[j]; // Source of interest
+            if (!source || !isfinite(source->psfMag)) {
+                magMask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xFF;
+                continue;
+            }
+
+#ifdef TESTING
+            fprintf(file, "%f %f %f %f %f %f %f\n", source->peak->xf, source->peak->yf,
+                    source->modelPSF->params->data.F32[PM_PAR_XPOS],
+                    source->modelPSF->params->data.F32[PM_PAR_YPOS],
+                    magRef, source->psfMag, source->errMag);
+#endif
+            magDiff->data.F32[j] = source->psfMag - magRef;
+            magErr->data.F32[j] = source->errMag;
+        }
+        magDiff->n = sources->n;
+        magMask->n = sources->n;
+        magErr->n = sources->n;
+        if (!psVectorStats(magStats, magDiff, NULL, magMask, 0xFF)) {
+            // Probably because we don't have enough sources
+            psErrorClear();
+        }
+
+        if (isfinite(magStats->robustMedian) && isfinite(magStats->robustStdev)) {
+            magDiffMean->data.F32[i] = magStats->robustMedian;
+            magDiffStdev->data.F32[i] = magStats->robustStdev;
+        } else {
+            magDiffMean->data.F32[i] = magStats->sampleMean;
+            magDiffStdev->data.F32[i] = magStats->sampleStdev;
+        }
+
+        if (!psVectorStats(magStats, magErr, NULL, magMask, 0xFF)) {
+            // Probably because we don't have enough sources
+            psErrorClear();
+        }
+
+        if (isfinite(magStats->robustMedian)) {
+            magErrMean->data.F32[i] = magStats->robustMedian;
+        } else {
+            magErrMean->data.F32[i] = magStats->sampleMean;
+        }
+
+#ifdef TESTING
+        fclose(file);
+#endif
+    }
+
+    psFree(magStats);
+    psFree(magDiff);
+    psFree(magMask);
+    psFree(magErr);
+
+    psFree(fakeSources);
+
+    pmDetEff *de = pmDetEffAlloc(magLim, numSources, numBins); // Detection efficiency
+    de->magOffsets = psVectorCopy(NULL, magOffsets, PS_TYPE_F32);
+    de->counts = count;
+    de->magDiffMean = magDiffMean;
+    de->magDiffStdev = magDiffStdev;
+    de->magErrMean = magErrMean;
+
+    psMetadataAddPtr(readout->analysis, PS_LIST_TAIL, PM_DETEFF_ANALYSIS, PS_META_REPLACE | PS_DATA_UNKNOWN,
+                     "Detection efficiency", de);
+    psFree(de);
+
+    psLogMsg("psphot", PS_LOG_INFO, "Detection efficiency: %lf sec\n", psTimerClear("psphot.fake"));
+
+
+    return true;
+}
Index: branches/eam_branches/20090820/psphot/src/psphotEllipticalContour.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotEllipticalContour.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotEllipticalContour.c	(revision 25766)
@@ -0,0 +1,174 @@
+# include "psphotInternal.h"
+
+// model parameters
+enum {PAR_PHI, PAR_EPSILON, PAR_RMIN};
+psF32 psphotEllipticalContourFunc (psVector *deriv, const psVector *params, const psVector *coord);
+
+bool psphotEllipticalContour (pmSource *source) {
+
+    pmSourceRadialProfile *profile = source->extpars->profile;
+
+    // use LMM to fit theta vs radius to an ellipse
+    psVector *theta = profile->theta;
+    psVector *radius = profile->isophotalRadii;
+
+    // find Rmin and Rmax for the initial guess
+    float Rmin = radius->data.F32[0];
+    float Rmax = radius->data.F32[0];
+
+    // arrays to hold the data to be fitted
+    // we fit x and y vs theta in separate passes.
+    psArray *x = psArrayAllocEmpty(2*radius->n);
+    psVector *y = psVectorAllocEmpty(2*radius->n, PS_TYPE_F32);
+    psVector *yErr = psVectorAllocEmpty(2*radius->n, PS_TYPE_F32);
+
+    int n = 0;
+    for (int i = 0; i < radius->n; i++) {
+	if (!isfinite(radius->data.F32[i])) continue;
+
+	psVector *coord = NULL;
+
+	// Rx coordinate value
+	coord = psVectorAlloc (2, PS_TYPE_F32);
+	coord->data.F32[1] = 0.0;
+	coord->data.F32[0] = theta->data.F32[i];
+	x->data[n] = coord;
+	y->data.F32[n] = radius->data.F32[i]*cos(theta->data.F32[i]);
+	yErr->data.F32[n] = 1000.0;
+	n++;
+
+	// Ry coordinate value
+	coord = psVectorAlloc (2, PS_TYPE_F32);
+	coord->data.F32[1] = 1.0;
+	coord->data.F32[0] = theta->data.F32[i];
+	x->data[n] = coord;
+	y->data.F32[n] = radius->data.F32[i]*sin(theta->data.F32[i]);
+	yErr->data.F32[n] = 1000.0;
+	n++;
+
+	// check the radius range
+	Rmin = MIN (Rmin, radius->data.F32[i]);
+	Rmax = MAX (Rmax, radius->data.F32[i]);
+    }	
+    x->n = n;
+    y->n = n;
+    yErr->n = n;
+
+    if (n < 4) {
+	psFree (x);
+	psFree (y);
+	psFree (yErr);
+	return false;
+    }
+
+    psVector *params = psVectorAlloc (3, PS_TYPE_F32);
+    
+    // psTraceSetLevel ("psLib.math.psMinimizeLMChi2", 7);
+    
+    // create the minimization constraints
+    psMinConstraint *constraint = psMinConstraintAlloc();
+
+    // XXX for now, no parameter masks, skip checkLimits
+    // XXX might help to add a limit to the angle or re-parameterize the ellipse in terms of Rxx, Ryy, Rxy
+    // constraint->checkLimits = psastroModelBoresiteLimits;
+
+    params->data.F32[PAR_PHI]     = 0.0;
+    params->data.F32[PAR_EPSILON] = Rmin / Rmax;
+    params->data.F32[PAR_RMIN]    = Rmin;
+
+    psMinimization *myMin = psMinimizationAlloc (25, 0.001);
+    psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
+    
+    // XXX skip the weights for now
+    psMinimizeLMChi2(myMin, covar, params, constraint, x, y, yErr, psphotEllipticalContourFunc);
+
+    /// XXX rationalize? if epsilon > 1, flip major and minor axes (rotate by 90 degrees)
+    if (params->data.F32[PAR_EPSILON] < 1.0) {
+	profile->axes.major = params->data.F32[PAR_RMIN] / params->data.F32[PAR_EPSILON];
+	profile->axes.minor = params->data.F32[PAR_RMIN];
+	profile->axes.theta = params->data.F32[PAR_PHI];
+    } else {
+	profile->axes.major = params->data.F32[PAR_RMIN];
+	profile->axes.minor = params->data.F32[PAR_RMIN] / params->data.F32[PAR_EPSILON];
+	profile->axes.theta = params->data.F32[PAR_PHI] + 0.5*M_PI;
+    }
+
+    psTrace ("psphot", 4, "# fitted values:\n");
+    psTrace ("psphot", 4, "Phi:   %f\n", profile->axes.theta*PS_DEG_RAD);
+    psTrace ("psphot", 4, "Rmaj:  %f\n", profile->axes.major);
+    psTrace ("psphot", 4, "Rmin:  %f\n", profile->axes.minor);
+    
+    // show the results
+    // psphotPetrosianVisualEllipticalContour (petrosian);
+
+    psFree (x);
+    psFree (y);
+    psFree (yErr);
+    psFree (params);
+    psFree (covar);
+    psFree (myMin);
+    psFree (constraint);
+
+    return true;
+}
+
+/**
+ * the full chisq is built of two associated sums over coordinates:
+ * chisq = sum ((Rx_obs - Rx_fit(t))^2 + (Ry_obs - Ry_fit(t))^2)
+ * we use split this into a 2x long vector and use coord[1] to distinguish the X and Y terms:
+ * coord[0] = measured X or measured Y
+ * coord[1] =          0 or          1
+ */
+psF32 psphotEllipticalContourFunc (psVector *deriv, const psVector *params, const psVector *coord) {
+
+    static int pass = 0;
+
+    psF32 *par = params->data.F32;
+
+    float alpha = coord->data.F32[0];
+
+    float cs_alpha = cos(alpha);
+    float sn_alpha = sin(alpha);
+
+    float cs_phi = cos(alpha - par[PAR_PHI]);
+    float sn_phi = sin(alpha - par[PAR_PHI]);
+
+    float r     = 1.0 / sqrt(SQ(sn_phi) + SQ(par[PAR_EPSILON]*cs_phi));
+    float r3    = pow(r, 3.0);
+    float drdE  = -0.5 * r3 * SQ(cs_phi) * 2.0 * par[PAR_EPSILON];
+    float drdP  = -0.5 * r3 * (SQ(par[PAR_EPSILON]) - 1) * 2.0 * cs_phi * sn_phi;
+
+    // value is X
+    // if (coord->data.F32[1] == 0) {
+    if (pass == 0) {
+	pass = 1;
+
+	float value = par[PAR_RMIN]*cs_alpha*r;
+
+	if (deriv) {
+	    psF32 *dPAR = deriv->data.F32;
+	    dPAR[PAR_RMIN]    = r*cs_alpha;
+	    dPAR[PAR_EPSILON] = par[PAR_RMIN]*cs_alpha*drdE;
+	    dPAR[PAR_PHI]     = 4.0*par[PAR_RMIN]*cs_alpha*drdP;
+	}
+	return (value);
+    }  
+
+    // value is Y
+    // if (coord->data.F32[1] == 1) {
+    if (pass == 1) {
+	pass = 0;
+
+	float value = par[PAR_RMIN]*sn_alpha*r;
+
+	if (deriv) {
+	    psF32 *dPAR = deriv->data.F32;
+	    dPAR[PAR_RMIN]    = r*sn_alpha;
+	    dPAR[PAR_EPSILON] = par[PAR_RMIN]*sn_alpha*drdE;
+	    dPAR[PAR_PHI]     = 4.0*par[PAR_RMIN]*sn_alpha*drdP;
+	}
+	return (value);
+    }  
+
+    psAbort ("programming error: invalid coordinate");
+}
Index: branches/eam_branches/20090820/psphot/src/psphotEllipticalProfile.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotEllipticalProfile.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotEllipticalProfile.c	(revision 25766)
@@ -0,0 +1,75 @@
+# include "psphotInternal.h"
+
+bool psphotEllipticalProfile (pmSource *source) {
+
+    pmSourceRadialProfile *profile = source->extpars->profile;
+
+    profile->radiusElliptical = psVectorAllocEmpty(100, PS_TYPE_F32);
+    profile->fluxElliptical = psVectorAllocEmpty(100, PS_TYPE_F32);
+
+    psVector *radius = profile->radiusElliptical;
+    psVector *flux = profile->fluxElliptical;
+
+    // the psEllipse functions use z = 0.5(x/Sxx)^2 + 0.5(y/Syy)^2 + x y Sxy
+    // which are converted to z = 0.5(x/a)^2 + 0.5(y/b)^2
+    // we have major and minor axes of a specific ellipse with r^2 = (x/A)^2 + (y/B)^2
+    // a = A / sqrt(2)
+
+    // we have the shape parameters of the elliptical contour at the reference isophote.
+    // use the axis ratio (major/minor) to rescale the radial profile so that 1 pixel
+    // along the major axis is 1 pixel, and a smaller amount on the minor axis
+
+    psEllipseAxes axes;
+    axes.major = M_SQRT1_2;
+    axes.minor = M_SQRT1_2 * (profile->axes.minor / profile->axes.major);
+
+    // axes.major = 1.0;
+    // axes.minor = profile->axes.minor / profile->axes.major;
+
+    axes.theta = profile->axes.theta;
+    psEllipseShape shape = psEllipseAxesToShape (axes);
+
+    float Sxx = shape.sx;
+    float Sxy = shape.sxy;
+    float Syy = shape.sy;
+
+    // XXX drop these two vectors?
+    psVector *radiusRaw = psVectorAllocEmpty(100, PS_TYPE_F32);
+    psVector *fluxRaw = psVectorAllocEmpty(100, PS_TYPE_F32);
+
+    for (int iy = 0; iy < source->pixels->numRows; iy++) {
+	for (int ix = 0; ix < source->pixels->numCols; ix++) {
+
+	    // 0.5 PIX: get radius as a function of pixel coord
+	    float x = ix + 0.5 - source->peak->xf + source->pixels->col0;
+	    float y = iy + 0.5 - source->peak->yf + source->pixels->row0;
+
+	    float r2 = 0.5*PS_SQR(x/Sxx) + 0.5*PS_SQR(y/Syy) + x*y*Sxy;
+
+	    psVectorAppend(radius, sqrt(r2));
+	    psVectorAppend(flux, source->pixels->data.F32[iy][ix]);
+
+	    float Rraw = hypot(x, y);
+	    psVectorAppend(radiusRaw, Rraw);
+	    psVectorAppend(fluxRaw, source->pixels->data.F32[iy][ix]);
+	}
+    }
+
+    // psVector *radiusRaw = psVectorAllocEmpty(100, PS_TYPE_F32);
+    // psVector *fluxRaw = psVectorAllocEmpty(100, PS_TYPE_F32);
+    // for (int i = 0; i < profile->radii->n; i++) {
+    //   psVector *r = profile->radii->data[i];
+    //   psVector *f = profile->fluxes->data[i];
+    //   for (int j = 0; j < r->n; j++) {
+    // 	psVectorAppend(radiusRaw, r->data.F32[j]);
+    // 	psVectorAppend(fluxRaw, f->data.F32[j]);
+    //   }
+    // }
+
+    // psphotPetrosianVisualProfileRadii (radius, flux, radiusRaw, fluxRaw, 0.0);
+    // psphotPetrosianVisualProfileByAngle (radius, flux);
+
+    psFree (radiusRaw);
+    psFree (fluxRaw);
+    return true;
+}
Index: branches/eam_branches/20090820/psphot/src/psphotExtendedSourceAnalysis.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotExtendedSourceAnalysis.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotExtendedSourceAnalysis.c	(revision 25766)
@@ -21,8 +21,15 @@
     }
 
-    // option to limit analysis to a specific region
-    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
-    psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
-    if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
+    // XXX require petrosian analysis for non-linear fits? 
+
+    // XXX temporary user-supplied systematic sky noise measurement (derive from background model)
+    float skynoise = psMetadataLookupF32 (&status, recipe, "SKY.NOISE");
+
+# if (0)
+    // if backModel or backStdev are missing, the values of sky and/or skyErr will be set to NAN
+    // XXX use this to set skynoise
+    pmReadout *backModel = psphotSelectBackground (config, view);
+    pmReadout *backStdev = psphotSelectBackgroundStdev (config, view);
+# endif
 
     // S/N limit to perform full non-linear fits
@@ -38,5 +45,8 @@
     sources = psArraySort (sources, pmSourceSortBySN);
 
-    // XXX some init functions for the extended source recipe options?
+    // option to limit analysis to a specific region
+    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
+    psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
+    if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
 
     // choose the sources of interest
@@ -49,4 +59,7 @@
 	if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
 	if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
+	if (source->mode & PM_SOURCE_MODE_DEFECT) continue;
+	if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
+	if (!(source->mode & PM_SOURCE_MODE_EXT_LIMIT)) continue;
 
 	// limit selection to some SN limit
@@ -68,10 +81,9 @@
 	// if we request any of these measurements, we require the radial profile
 	if (doPetrosian || doIsophotal || doAnnuli || doKron) {
-	    if (!psphotRadialProfile (source, recipe, maskVal)) {
+	    if (!psphotRadialProfile (source, recipe, skynoise, maskVal)) {
 		// all measurements below require the radial profile; skip them all
 		// re-subtract the object, leave local sky
 		psTrace ("psphot", 5, "failed to extract radial profile for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
 		pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-		source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
 		continue;
 	    }
@@ -79,4 +91,16 @@
 	}
 
+	// Petrosian Mags
+	if (doPetrosian) {
+	    if (!psphotPetrosian (source, recipe, skynoise, maskVal)) {
+		psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
+	    } else {
+		psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
+		Npetro ++;
+		source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
+	    }
+	}
+
+# if (0)
 	// Isophotal Mags
 	if (doIsophotal) {
@@ -89,16 +113,4 @@
 	    }
 	}
-
-	// Petrosian Mags
-	if (doPetrosian) {
-	    if (!psphotPetrosian (source, recipe, maskVal)) {
-		psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
-	    } else {
-		psTrace ("psphot", 5, "measured petrosian flux & radius for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
-		Npetro ++;
-		source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
-	    }
-	}
-
 	// Kron Mags
 	if (doKron) {
@@ -111,19 +123,12 @@
 	    }
 	}
-
-	// Radial Annuli
-	if (doAnnuli) {
-	    if (!psphotAnnuli (source, recipe, maskVal)) {
-		psError(PSPHOT_ERR_UNKNOWN, false, "failure in Annuli analysis");
-		return false;
-	    } 
-	    psTrace ("psphot", 5, "measured annuli for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
-	    Nannuli ++;
-	    source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
-	}
+# endif
 
 	// re-subtract the object, leave local sky
 	pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-	source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
+
+	if (source->extpars) {
+	    pmSourceRadialProfileFreeVectors(source->extpars->profile);
+	}
     }
 
@@ -133,4 +138,11 @@
     psLogMsg ("psphot", PS_LOG_INFO, "  %d annuli\n", Nannuli);
     psLogMsg ("psphot", PS_LOG_INFO, "  %d kron\n", Nkron);
+
+    psphotVisualShowResidualImage (readout);
+
+    if (doPetrosian) {
+	psphotVisualShowPetrosians (sources);
+    }
+
     return true;
 }
Index: branches/eam_branches/20090820/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotExtendedSourceFits.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotExtendedSourceFits.c	(revision 25766)
@@ -226,5 +226,4 @@
 
           pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-          source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
 
           psFree (modelFluxes);
@@ -253,5 +252,4 @@
         // subtract the best fit from the object, leave local sky
         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-        source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
 
         // the initial model flux is no longer needed
Index: branches/eam_branches/20090820/psphot/src/psphotFake.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotFake.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotFake.c	(revision 25766)
@@ -0,0 +1,225 @@
+# include "psphotInternal.h"
+
+#define TESTING
+
+
+#ifdef TESTING
+#define MIN_FLUX 0.1                    // Minimum flux for faint sources
+#endif
+
+
+// Calculate the limiting magnitude for an image
+//
+// We limit ourselves to calculating the peak flux in the smoothed image, which should be close (modulo
+// non-Gaussian PSF) to the limiting flux in the un-smoothed original image.
+static bool fakeLimit(float *magLim,           // Limiting magntiude, to return
+                      float *minFlux,          // Minimum flux, to return
+                      const pmReadout *ro,     // Readout of interest
+                      float thresh,            // Threshold for source identification
+                      float xFWHM, float yFWHM, // Size of PSF
+                      float smoothNsigma,       // Smoothing limit
+                      psImageMaskType maskVal   // Value to mask
+                      );
+{
+    PM_ASSERT_READOUT_NON_NULL(ro, false);
+    PM_ASSERT_READOUT_VARIANCE(ro, false);
+    PS_ASSERT_METADATA_NON_NULL(recipe, false);
+
+    float smoothSigma  = 0.5*(FWHM_X + FWHM_Y) / (2.0*sqrtf(2.0*log(2.0)));
+    psKernel *kernel = psImageSmoothKernel(smoothSigma, smoothNsigma); // Kernel used for smoothing
+    psKernel *newCovar = psImageCovarianceCalculate(kernel, readout->covariance); // Covariance matrix
+    psFree(kernel);
+    float factor = psImageCovarianceFactor(newCovar); // Variance factor
+    psFree(newCovar);
+
+    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for variance
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);        // Random number generator
+    if (!psImageBackground(stats, NULL, ro->variance, ro->mask, maskVal, rng) ||
+        !isfinite(stats->robustMedian)) {
+        psError(PSPHOT_ERR_DATA, false, "Unable to determine mean variance");
+        psFree(stats);
+        psFree(rng);
+        return false;
+    }
+    psFree(rng);
+    float meanVar = stats->robustMedian; // Mean variance
+    psFree(stats);
+
+    if (magLim) {
+        *magLim = -2.5 * log10(thresh * sqrtf(meanVar * factor));
+    }
+    if (minFlux) {
+        int fudge = psMetadataLookupF32(NULL, recipe, "FAKE.MINFLUX"); // Fudge factor for minimum flux
+        *minFlux = sqrtf(meanVar) * fudge;
+    }
+
+    return true;
+}
+
+/// Generate a fake image and add it in to the existing readout
+static bool fakeGenerate(psImage **xSrc, psImage **ySrc, // Positions of sources
+                         const pmReadout *ro,            // Readout of interest
+                         const psVector *magOffsets,     // Magnitude offsets for fake sources
+                         int numSources,                 // Number of fake sources for each bin
+                         float refMag,                   // Reference magnitude
+                         float minFlux                   // Minimum flux level for fake image
+                         )
+{
+    PM_ASSERT_READOUT_NON_NULL(ro, false);
+    PM_ASSERT_READOUT_IMAGE(ro, false);
+    PS_ASSERT_METADATA_NON_NULL(recipe, false);
+    PS_ASSERT_VECTOR_NON_NULL(magOffsets, false);
+    PS_ASSERT_VECTOR_TYPE(magOffsets, PS_TYPE_F32, false);
+
+    int numBins = magOffset->n;                                     // Number of bins
+    int numCols = ro->image->numCols, numRows = ro->image->numRows; // Size of image
+
+    *xSrc = psImageRecycle(*xSrc, numSources, numBins, PS_TYPE_F32);
+    *ySrc = psImageRecycle(*ySrc, numSources, numBins, PS_TYPE_F32);
+
+    // Master list, for image creation
+    psVector *xAll = psVectorAlloc(numBins * numSources, PS_TYPE_F32);
+    psVector *yAll = psVectorAlloc(numBins * numSources, PS_TYPE_F32);
+    psVector *magAll = psVectorAlloc(numBins * numSources, PS_TYPE_F32);
+
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
+    for (int i = 0; i <= numBins; i++) {
+        psArray *data = psArrayAlloc(3); // Sources for bin
+
+        psVector *x = psVectorAlloc(numSources, PS_TYPE_F32);
+        psVector *y = psVectorAlloc(numSources, PS_TYPE_F32);
+
+        float mag = refMag + magOffset->data.F32[i]; // Instrumental magnitude of sources
+
+        for (int j = 0; j <= numSources; j++) {
+            x->data.F32[j] = psRandomUniform(rng) * numCols;
+            y->data.F32[j] = psRandomUniform(rng) * numRows;
+            magAll->data.F32[i * numSources + j] = mag;
+        }
+        memcpy(xSrc->data.F32[i], x->data.F32, numSources * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+        memcpy(ySrc->data.F32[i], y->data.F32, numSources * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+        memcpy(&xAll->data.F32[i * numSources], x->data.F32, numSources * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+        memcpy(&yAll->data.F32[i * numSources], y->data.F32, numSources * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+    }
+    psFree(rng);
+
+    pmReadout *fakeRO = pmReadoutAlloc(); // Fake readout
+    if (!pmReadoutFakeFromVectors(fakeRO, xAll, yAll, mag, NULL, NULL, psf, minFlux, NAN, false, false)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to generate fake image");
+        psFree(fakeRO);
+        psFree(xAll);
+        psFree(yAll);
+        psFree(magAll);
+        return false;
+    }
+    psFree(xAll);
+    psFree(yAll);
+    psFree(magAll);
+
+    psBinaryOp(ro->image, ro->image, "+", fakeRO->image);
+    psFree(fakeRO);
+
+    return true;
+}
+
+
+// *** in this section, perform the photometry for fake sources ***
+bool psphotFake(pmConfig *config, pmReadout *readout, const pmPSF *psf,
+                const psMetadata *recipe, const psArray *realSources)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PM_ASSERT_READOUT_NON_NULL(readout, false);
+    PM_ASSERT_READOUT_IMAGE(readout, false);
+    PS_ASSERT_PTR_NON_NULL(psf, false);
+    PS_ASSERT_METADATA_NON_NULL(recipe, false);
+    PS_ASSERT_ARRAY_NON_NULL(realSources, false);
+
+    psTimerStart("psphot.fake");
+
+    // Collect recipe information
+    float xFWHM = psMetadataLookupF32(NULL, recipe, "FWHM_X"); // PSF size in x
+    float yFWHM = psMetadataLookupF32(NULL, recipe, "FWHM_Y"); // PSF size in y
+    if (!isfinite(xFWHM) || !isfinite(yFWHM)) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find FWHM_X and FWHM_Y in recipe");
+        return false;
+    }
+    float smoothNsigma = psMetadataLookupF32(NULL, recipe, "PEAKS_SMOOTH_NSIGMA"); // Smoothing limit
+    if (!isfinite(smoothNsigma)) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find PEAKS_SMOOTH_NSIGMA in recipe");
+        return false;
+    }
+    float thresh = psMetadataLookupF32(NULL, recipe, "PEAKS_NSIGMA_LIMIT_2");
+    if (!isfinite(thresh)) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find PEAKS_NSIGMA_LIMIT_2 in recipe");
+        return false;
+    }
+    psVector *magOffsets = psMetadataLookupVector(NULL, recipe, "FAKE.MAG"); // Magnitude offsets
+    if (!magOffset || magOffset->type.type != PS_TYPE_F32) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find FAKE.MAG F32 vector in recipe");
+        return NULL;
+    }
+    int numSources = psMetadataLookupS32(NULL, recipe, "FAKE.NUM"); // Number of sources for each bin
+    if (numSources == 0) {
+        psError(PSPHOT_ERR_CONFIG, false, "Unable to find FAKE.NUM in recipe");
+        return NULL;
+    }
+    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Value to mask
+
+
+    // remove all sources, adding noise for subtracted sources
+    psphotRemoveAllSources(realSources, recipe);
+    psphotAddNoise(readout, realSources, recipe);
+
+    float magLim;                       // Guess at limiting magnitude
+    float minFlux;                      // Minimum flux for fake image
+    if (!fakeLimit(&magLim, &minFlux, readout, thresh, xFWHM, yFWHM, smoothNsigma, maskVal)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to determine limits for image");
+        return false;
+    }
+
+    psImage *xFake = NULL, *yFake = NULL; // Coordinates of sources, each bin in a row
+    if (!fakeGenerate(&xFake, &yFake, readout, magOffsets, numSources, magLim, minFlux)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to generate fake sources");
+        psFree(xFake);
+        psFree(yFake);
+        return false;
+    }
+
+    psImage *significance = psphotSignificanceImage(readout, recipe, 2, maskVal);
+    if (!significance) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate significance image");
+        psFree(xFake);
+        psFree(yFake);
+        return false;
+    }
+
+    int numBins = magOffsets->n;                          // Number of bins
+    psVector *frac = psVectorAlloc(numBins, PS_TYPE_S32); // Fraction of sources in each bin
+    for (int i = 0; i < numBins; i++) {
+        int numFound = 0;               // Number found
+        for (int j = 0; j < numSources; j++) {
+            float x = xFake->data.F32[i][j], y = yFake->data.F32[i][j]; // Coordinates of interest
+            int xPix = x, yPix = y;                                     // Pixel coordinates
+            if (significance->data.F32[yPix][xPix] > thresh) {
+                numFound++;
+            }
+        }
+        frac->data.S32[i] = (float)numFound / (float)numSources;
+    }
+
+    psFree(xFake);
+    psFree(yFake);
+    psFree(significance);
+
+    // Putting results on recipe because that appears to be the psphot standard, but it's not a good idea
+    psMetadataAddVector(recipe, PS_LIST_TAIL, "FAKE.EFF", PS_META_REPLACE,
+                        "Efficiency fractions", frac);
+    psMetadataAddVector(recipe, PS_LIST_TAIL, "FAKE.MAG", PS_META_REPLACE,
+                        "Efficiency magnitudes", magOffsets);
+    psMetadataAddF32(recipe, PS_LIST_TAIL, "FAKE.REF", PS_META_REPLACE,
+                     "Efficiency reference magnitude", magLim);
+
+    psFree(frac);
+
+    return true;
+}
Index: branches/eam_branches/20090820/psphot/src/psphotFindDetections.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotFindDetections.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotFindDetections.c	(revision 25766)
@@ -52,5 +52,5 @@
     // optionally merge peaks into footprints
     if (useFootprints) {
-        psphotFindFootprints (detections, significance, readout, recipe, pass, maskVal);
+        psphotFindFootprints (detections, significance, readout, recipe, threshold, pass, maskVal);
     }
 
Index: branches/eam_branches/20090820/psphot/src/psphotFindFootprints.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotFindFootprints.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotFindFootprints.c	(revision 25766)
@@ -1,5 +1,5 @@
 # include "psphotInternal.h"
 
-bool psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psImageMaskType maskVal) {
+bool psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const float threshold, const int pass, psImageMaskType maskVal) {
 
     bool status;
@@ -9,17 +9,4 @@
     int npixMin = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NPIXMIN");
     PS_ASSERT (status, false);
-
-    float FOOTPRINT_NSIGMA_LIMIT;
-    if (pass == 1) {
-        FOOTPRINT_NSIGMA_LIMIT = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NSIGMA_LIMIT");
-    } else {
-        FOOTPRINT_NSIGMA_LIMIT = psMetadataLookupS32(&status, recipe, "FOOTPRINT_NSIGMA_LIMIT_2");
-    }
-    PS_ASSERT (status, false);
-
-    // XXX do we need to use the same threshold here as for peaks?  does it make sense for
-    // these to be different?
-
-    float threshold = PS_SQR(FOOTPRINT_NSIGMA_LIMIT);
 
     int growRadius = 0;
Index: branches/eam_branches/20090820/psphot/src/psphotFindPeaks.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotFindPeaks.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotFindPeaks.c	(revision 25766)
@@ -31,4 +31,10 @@
         peak->SN = sqrt(peak->value);
         peak->flux = readout->image->data.F32[peak->y-row0][peak->x-col0];
+	// if (peak->flux / peak->value > 5.0/12.0) {
+	//     psWarning ("odd peak levels (1)");
+	// }
+	// if (peak->value / peak->flux > 5*12.0) {
+	//     psWarning ("odd peak levels (2)");
+	// }
 	if (readout->variance && isfinite (peak->dx)) {
 	    peak->dx *= sqrt(readout->variance->data.F32[peak->y-row0][peak->x-col0]);
Index: branches/eam_branches/20090820/psphot/src/psphotFitSourcesLinear.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotFitSourcesLinear.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotFitSourcesLinear.c	(revision 25766)
@@ -12,5 +12,5 @@
 static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, int SKY_FIT_ORDER, psImageMaskType markVal);
 
-bool psphotFitSourcesLinear (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, bool final) {
+bool psphotFitSourcesLinear (pmReadout *readout, psArray *sources, const psMetadata *recipe, const pmPSF *psf, bool final) {
 
     bool status;
@@ -76,5 +76,5 @@
             if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) continue;
         } else {
-            if (source->mode & PM_SOURCE_MODE_BLEND) continue;
+            // if (source->mode & PM_SOURCE_MODE_BLEND) continue;
         }
 
@@ -186,5 +186,5 @@
     if (SKY_FIT_LINEAR) {
         psSparseBorderSolve (&norm, &skyfit, constraint, border, 5);
-        fprintf (stderr, "skyfit: %f\n", skyfit->data.F32[0]);
+        psLogMsg ("psphot", PS_LOG_MINUTIA, "skyfit: %f\n", skyfit->data.F32[0]);
     } else {
         norm = psSparseSolve (NULL, constraint, sparse, 5);
@@ -215,5 +215,4 @@
         // subtract object
         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-        source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     }
     psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "sub models: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
@@ -239,5 +238,5 @@
 
     psphotVisualShowResidualImage (readout);
-    psphotVisualShowFlags (sources);
+    // psphotVisualShowFlags (sources);
 
     return true;
@@ -264,5 +263,5 @@
         float x = model->params->data.F32[PM_PAR_XPOS];
         float y = model->params->data.F32[PM_PAR_YPOS];
-        psImageMaskCircle (source->maskView, x, y, model->radiusFit, "AND", PS_NOT_IMAGE_MASK(markVal));
+        psImageMaskCircle (source->maskView, x, y, model->fitRadius, "AND", PS_NOT_IMAGE_MASK(markVal));
     }
 
Index: branches/eam_branches/20090820/psphot/src/psphotFitSourcesLinearStack.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotFitSourcesLinearStack.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotFitSourcesLinearStack.c	(revision 25766)
@@ -168,5 +168,4 @@
         // subtract object
         pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-        source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     }
     psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "sub models: %f sec (%d elements)\n", psTimerMark ("psphot.linear"), sparse->Nelem);
Index: branches/eam_branches/20090820/psphot/src/psphotGuessModels.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotGuessModels.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotGuessModels.c	(revision 25766)
@@ -177,9 +177,9 @@
 
 	// set the source PSF model
+	psAssert (source->modelPSF == NULL, "failed to free one of the models?");
 	source->modelPSF = modelPSF;
 	source->modelPSF->residuals = psf->residuals;
 
 	pmSourceCacheModel (source, maskVal);  // ALLOC x14 (!)
-
     }
 
Index: branches/eam_branches/20090820/psphot/src/psphotImageLoop.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotImageLoop.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotImageLoop.c	(revision 25766)
@@ -67,18 +67,19 @@
 
                 // Update the header
-                {
-                    pmHDU *hdu = pmHDUGetHighest(input->fpa, chip, cell);
-                    if (hdu && hdu != lastHDU) {
-                        psphotVersionHeaderFull(hdu->header);
-                        lastHDU = hdu;
-                    }
+		pmHDU *hdu = pmHDUGetHighest(input->fpa, chip, cell);
+		if (hdu && hdu != lastHDU) {
+		    psphotVersionHeaderFull(hdu->header);
+		    lastHDU = hdu;
                 }
 
-                psImageMaskType maskSat = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
-                if (!pmReadoutMaskNonfinite(readout, maskSat)) {
-                    psError(psErrorCodeLast(), false, "Unable to mask non-finite pixels.");
-                    psFree(view);
-                    return false;
-                }
+		// if an external mask is supplied, ensure that NAN pixels are also masked
+		if (readout->mask) {
+		    psImageMaskType maskSat = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
+		    if (!pmReadoutMaskNonfinite(readout, maskSat)) {
+			psError(psErrorCodeLast(), false, "Unable to mask non-finite pixels.");
+			psFree(view);
+			return false;
+		    }
+		}
 
                 // run the actual photometry analysis on this chip/cell/readout
Index: branches/eam_branches/20090820/psphot/src/psphotImageQuality.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotImageQuality.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotImageQuality.c	(revision 25766)
@@ -279,8 +279,8 @@
 #endif
 
-    psLogMsg ("psphot", PS_LOG_INFO, "Image Quality Stats from %ld psf stars : FWHM (major, minor) : %f, %f\n",
+    psLogMsg ("psphot", PS_LOG_INFO, "Image Quality Stats from %ld psf stars : FWHM (major, minor) [pixels]: %f, %f\n",
               M2->n, fwhm_major, fwhm_minor);
 
-    psLogMsg ("psphot", PS_LOG_INFO, "M_2 : %f +/- %f, M_3 : %f +/- %f, M_4 : %f +/- %f\n",
+    psLogMsg ("psphot", PS_LOG_INFO, "M_2 : %f +/- %f, M_3 : %f +/- %f, M_4 : %f +/- %f  [pixels^n]\n",
               vM2, dM2, vM3, dM3, vM4, dM4);
 
Index: branches/eam_branches/20090820/psphot/src/psphotMagnitudes.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotMagnitudes.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotMagnitudes.c	(revision 25766)
@@ -1,5 +1,5 @@
 # include "psphotInternal.h"
 
-bool psphotMagnitudes(pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources, pmPSF *psf) {
+bool psphotMagnitudes(pmConfig *config, pmReadout *readout, const pmFPAview *view, psArray *sources, const pmPSF *psf) {
 
     bool status = false;
@@ -64,5 +64,5 @@
 
             psArrayAdd(job->args, 1, cells->data[j]); // sources
-            psArrayAdd(job->args, 1, psf);
+            psArrayAdd(job->args, 1, (pmPSF*)psf);    // Casting away const
             psArrayAdd(job->args, 1, binning);
             psArrayAdd(job->args, 1, backModel);
@@ -71,4 +71,5 @@
             PS_ARRAY_ADD_SCALAR(job->args, photMode, PS_TYPE_S32);
             PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
+            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
             PS_ARRAY_ADD_SCALAR(job->args, 0,        PS_TYPE_S32); // this is used as a return value for nAp
 
@@ -102,5 +103,5 @@
                 fprintf (stderr, "error with job\n");
             } else {
-                psScalar *scalar = job->args->data[7];
+                psScalar *scalar = job->args->data[8];
                 Nap += scalar->data.S32;
             }
@@ -127,9 +128,26 @@
     pmSourcePhotometryMode photMode = PS_SCALAR_VALUE(job->args->data[5],S32);
     psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[7],PS_TYPE_IMAGE_MASK_DATA);
 
     for (int i = 0; i < sources->n; i++) {
         pmSource *source = (pmSource *) sources->data[i];
-        status = pmSourceMagnitudes (source, psf, photMode, maskVal);
+
+        // replace object in image
+        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
+            pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
+        }
+
+	// clear the mask bit and set the circular mask pixels
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
+	psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
+
+        status = pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
         if (status && isfinite(source->apMag)) Nap ++;
+
+	// clear the mask bit 
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
+
+        // re-subtract the object, leave local sky
+        pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
 
         if (backModel) {
@@ -155,5 +173,5 @@
 
     // change the value of a scalar on the array (wrap this and put it in psArray.h)
-    psScalar *scalar = job->args->data[7];
+    psScalar *scalar = job->args->data[8];
     scalar->data.S32 = Nap;
 
Index: branches/eam_branches/20090820/psphot/src/psphotMakeFluxScale.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotMakeFluxScale.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotMakeFluxScale.c	(revision 25766)
@@ -60,4 +60,9 @@
         goto DONE;
     }
+    if (trend->mode == PM_TREND_MAP) {
+	// p_psImagePrint (2, trend->map->map, "FluxScale Before"); // XXX TEST:
+	psImageMapRepair (trend->map->map);
+	// p_psImagePrint (2, trend->map->map, "FluxScale After"); // XXX TEST:
+    }
 
     // XXX do something useful to measure residual statistics
Index: branches/eam_branches/20090820/psphot/src/psphotMakeResiduals.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotMakeResiduals.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotMakeResiduals.c	(revision 25766)
@@ -1,3 +1,5 @@
 # include "psphotInternal.h"
+
+# define RESIDUAL_SOFTENING 0.005 
 
 bool psphotMakeResiduals (psArray *sources, psMetadata *recipe, pmPSF *psf, psImageMaskType maskVal) {
@@ -31,4 +33,7 @@
 
     float pixelSN = psMetadataLookupF32(&status, recipe, "PSF.RESIDUALS.PIX.SN");
+    PS_ASSERT (status, false);
+
+    float radiusMax = psMetadataLookupF32(&status, recipe, "PSF.RESIDUALS.RADIUS");
     PS_ASSERT (status, false);
 
@@ -171,5 +176,4 @@
                 bool offImage = false;
                 if (psImageInterpolate (&flux, &dflux, &mflux, ix, iy, interp) == PS_INTERPOLATE_STATUS_OFF) {
-                    // fprintf (stderr, "off image: %f %f : %f %f\n", ix, iy, flux, dflux);
                     // This pixel is off the image
                     offImage = true;
@@ -179,6 +183,9 @@
                 }
                 fluxes->data.F32[i] = flux;
-                dfluxes->data.F32[i] = dflux;
+                dfluxes->data.F32[i] = hypot(dflux, RESIDUAL_SOFTENING);
                 if (isnan(flux)) {
+                    fmasks->data.PS_TYPE_VECTOR_MASK_DATA[i] = badMask;
+                }
+                if (isnan(dflux)) {
                     fmasks->data.PS_TYPE_VECTOR_MASK_DATA[i] = badMask;
                 }
@@ -234,4 +241,10 @@
 		}
 
+		float radius = hypot((ox - 0.5*resid->Ro->numCols), (oy - 0.5*resid->Ro->numRows));
+		if (radius > radiusMax) {
+                  resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
+		  continue;
+                }
+
                 resid->Ro->data.F32[oy][ox] = psStatsGetValue(fluxStats, statOption);
                 resid->Rx->data.F32[oy][ox] = resid->Ry->data.F32[oy][ox] = 0.0;
@@ -248,9 +261,13 @@
                   resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
                 }
-
-                // fprintf (stderr, "res: %2d %2d : %6.4f  %6.4f  %6.4f   %3d  %1d\n", ox, oy, resid->Ro->data.F32[oy][ox], fluxStats->sampleStdev, fluxStats->sampleStdev/sqrt(nKeep), nKeep, resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox]);
-
             } else {
                 assert (SPATIAL_ORDER == 1);
+
+		float radius = hypot((ox - 0.5*resid->Ro->numCols), (oy - 0.5*resid->Ro->numRows));
+		if (radius > radiusMax) {
+                  resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
+		  continue;
+                }
+
                 psImageInit(A, 0.0);
                 psVectorInit(B, 0.0);
@@ -275,8 +292,7 @@
 
                 if (!psMatrixGJSolve(A, B)) {
-                    psError(PSPHOT_ERR_PSF, false, "Singular matrix solving for (y,x) = (%d,%d)'s residuals",
-                            oy, ox);
-                    psFree(resid); resid = NULL;
-                    break;
+		    resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
+                    psWarning("Singular matrix solving for (y,x) = (%d,%d)'s residuals, masking", oy, ox);
+		    continue;
                 }
 
@@ -286,11 +302,8 @@
 
                 float dRo = sqrt(A->data.F32[0][0]);
-                // fprintf (stderr, "res: %2d %2d : %6.4f  %6.4f  %6.4f   %3d  %1d\n",
-                // ox, oy, resid->Ro->data.F32[oy][ox], dRo, dRo/sqrt(nKeep), nKeep, resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox]);
 
                 if (fabs(resid->Ro->data.F32[oy][ox]) < pixelSN*dRo/sqrt(nKeep)) {
                   resid->mask->data.PM_TYPE_RESID_MASK_DATA[oy][ox] = 1;
                 }
-                //resid->variance->data.F32[oy][ox] = XXX;
             }
         }
Index: branches/eam_branches/20090820/psphot/src/psphotMaskReadout.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotMaskReadout.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotMaskReadout.c	(revision 25766)
@@ -33,13 +33,17 @@
     }
 
+    bool softenVariance = psMetadataLookupBool (&status, recipe, "SOFTEN.VARIANCE");
+    float softenFraction = psMetadataLookupF32 (&status, recipe, "SOFTEN.VARIANCE.FRACTION");
+
     // make this an option via the recipe
-    if (0) {
+    if (softenVariance) {
       psImage *im = readout->image;
       psImage *wt = readout->variance;
-      psImage *mk = readout->mask;
       for (int j = 0; j < im->numRows; j++) {
         for (int i = 0; i < im->numCols; i++) {
-          if (isfinite(im->data.F32[j][i]) && isfinite(wt->data.F32[j][i])) continue;
-          mk->data.PS_TYPE_IMAGE_MASK_DATA[j][i] |= maskBad;
+	    if (!isfinite(im->data.F32[j][i])) continue;
+	    if (!isfinite(wt->data.F32[j][i])) continue;
+	    float sysError = softenFraction * im->data.F32[j][i];
+	    wt->data.F32[j][i] += PS_SQR(sysError);
         }
       }
Index: branches/eam_branches/20090820/psphot/src/psphotModelGroupInit.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotModelGroupInit.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotModelGroupInit.c	(revision 25766)
@@ -1,5 +1,5 @@
 # include "psphotInternal.h"
 
-// Add locally-defined models here.  As these mature, they can be moved to 
+// Add locally-defined models here.  As these mature, they can be moved to
 // psModule/src/objects/models
 
@@ -8,10 +8,10 @@
 
 static pmModelClass userModels[] = {
-    {"PS_MODEL_TEST1", 7, pmModelFunc_TEST1,  pmModelFlux_TEST1,  pmModelRadius_TEST1,  pmModelLimits_TEST1,  pmModelGuess_TEST1, pmModelFromPSF_TEST1, pmModelParamsFromPSF_TEST1, pmModelFitStatus_TEST1},
-    {"PS_MODEL_STRAIL", 9, pmModelFunc_STRAIL,  pmModelFlux_STRAIL,  pmModelRadius_STRAIL,  pmModelLimits_STRAIL,  pmModelGuess_STRAIL, pmModelFromPSF_STRAIL, pmModelParamsFromPSF_STRAIL, pmModelFitStatus_STRAIL},
+    {"PS_MODEL_TEST1", 7, pmModelFunc_TEST1,  pmModelFlux_TEST1,  pmModelRadius_TEST1,  pmModelLimits_TEST1,  pmModelGuess_TEST1, pmModelFromPSF_TEST1, pmModelParamsFromPSF_TEST1, pmModelFitStatus_TEST1, NULL},
+    {"PS_MODEL_STRAIL", 9, pmModelFunc_STRAIL,  pmModelFlux_STRAIL,  pmModelRadius_STRAIL,  pmModelLimits_STRAIL,  pmModelGuess_STRAIL, pmModelFromPSF_STRAIL, pmModelParamsFromPSF_STRAIL, pmModelFitStatus_STRAIL, NULL},
 };
 
-void psphotModelClassInit (void) 
-{ 
+void psphotModelClassInit (void)
+{
 
     // if pmModelClassInit returns false, we have already init'ed
@@ -20,5 +20,5 @@
     int Nmodels = sizeof (userModels) / sizeof (pmModelClass);
     for (int i = 0; i < Nmodels; i++) {
-	pmModelClassAdd (&userModels[i]);
+        pmModelClassAdd (&userModels[i]);
     }
     return;
Index: branches/eam_branches/20090820/psphot/src/psphotOutput.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotOutput.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotOutput.c	(revision 25766)
@@ -31,4 +31,36 @@
     }
     return background;
+}
+
+// dump source stats for psf stars
+bool psphotDumpStats (psArray *sources, char *stage) {
+
+    char filename[64];
+    snprintf (filename, 64, "psf.%s.dat", stage);
+    FILE *f = fopen (filename, "w");
+    for (int i = 0; i < sources->n; i++) {
+	pmSource *source = sources->data[i];
+	if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
+
+	pmModel *model = source->modelPSF;
+	if (!model) continue;
+
+	// int xc = source->peak->x - source->pixels->col0;
+	// int yc = source->peak->y - source->pixels->row0;
+	// float mcore = source->modelFlux ? source->modelFlux->data.F32[yc][xc] : NAN;
+	// float mpeak = model ? model->params->data.F32[PM_PAR_I0] : NAN;
+	// bool subtracted = source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED;
+	// fprintf (stderr, "%d %d : %d : %f %f : %f %f\n", source->peak->x, source->peak->y, subtracted, source->peak->flux, source->pixels->data.F32[yc][xc], mcore, mpeak); 
+
+	fprintf (f, "%6.1f %6.1f : %6.1f %6.1f : %8.3f %8.3f %8.3f : %f : %f %f %f : %f\n",
+		 source->peak->xf, source->peak->yf, 
+		 model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS], 
+		 source->psfMag, source->apMag, source->errMag,
+		 model->params->data.F32[PM_PAR_I0], 
+		 model->params->data.F32[PM_PAR_SXX], model->params->data.F32[PM_PAR_SXY], model->params->data.F32[PM_PAR_SYY], 
+		 model->params->data.F32[PM_PAR_7]);
+    }
+    fclose (f);
+    return true;
 }
 
@@ -160,6 +192,4 @@
     psMetadataItemSupplement (header, recipe, "DAPMIFIT");
     psMetadataItemSupplement (header, recipe, "NAPMIFIT");
-    psMetadataItemSupplement (header, recipe, "SKYBIAS");
-    psMetadataItemSupplement (header, recipe, "SKYSAT");
 
     // PSF model parameters (shape values for image center)
@@ -256,5 +286,5 @@
         psImageKeepCircle (source->maskObj, x, y, radius, "OR", markVal);
         pmModelSub (source->pixels, source->maskObj, source->modelPSF, PM_MODEL_OP_FULL, maskVal);
-        psImageKeepCircle (source->maskObj, x, y, radius, "AND", PS_NOT_IMAGE_MASK(markVal));
+        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
     }
 
Index: branches/eam_branches/20090820/psphot/src/psphotPSFConvModel.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotPSFConvModel.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotPSFConvModel.c	(revision 25766)
@@ -37,4 +37,8 @@
     }
 
+    // adjust the pixels based on the footprint
+    float radius = psphotSetRadiusEXT (readout, source, markVal);
+    if (!pmSourceMoments (source, radius, 0.0, 0.0)) return false;
+
     // XXX test : modify the Io, SXX, SYY terms based on the psf SXX, SYY terms:
     psEllipseShape psfShape;
@@ -67,6 +71,4 @@
     psVector *params  = modelConv->params;
     psVector *dparams = modelConv->dparams;
-
-    psphotCheckRadiusEXT (readout, source, modelConv, markVal);
 
     // create the minimization constraints
Index: branches/eam_branches/20090820/psphot/src/psphotPetrosian.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotPetrosian.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotPetrosian.c	(revision 25766)
@@ -1,109 +1,32 @@
 # include "psphotInternal.h"
 
-bool psphotPetrosian (pmSource *source, psMetadata *recipe, psImageMaskType maskVal) {
+bool psphotPetrosian (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal) {
 
-  bool status;
+    // XXX these need to go into recipe values
+    float Rmax = 200;
 
-  assert (source->extpars);
-  assert (source->extpars->profile);
-  assert (source->extpars->profile->radius);
-  assert (source->extpars->profile->flux);
+    psAssert (source->extpars, "need to run psphotRadialProfile first");
+    psAssert (source->extpars->profile, "need to run psphotRadialProfile first");
 
-  psVector *radius = source->extpars->profile->radius;
-  psVector *flux = source->extpars->profile->flux;
+    // integrate the radial profile for radial bins defined for the petrosian measurement:
+    // SB_i (r_i) where \alpha r_i < r < \beta r_i
+    if (!psphotPetrosianRadialBins (source, Rmax, skynoise)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
+	return false;
+    }
+  
+    // use the SB_i from above to calculate the petrosian radius and the flux within that radius
+    if (!psphotPetrosianStats (source)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
+	return false;
+    }
+  
+    psTrace ("psphot", 3, "source at %f,%f: petrosian radius: %f, flux: %f, axis ratio: %f, angle: %f",
+	     source->peak->xf, source->peak->yf, 
+	     source->extpars->petrosian_80->radius, 
+	     source->extpars->petrosian_80->flux, 
+	     source->extpars->profile->axes.minor/source->extpars->profile->axes.major, 
+	     source->extpars->profile->axes.theta*PS_DEG_RAD);
 
-  // flux at which to measure isophotal parameters
-  float PETROSIAN_R0 = psMetadataLookupF32 (&status, recipe, "PETROSIAN_R0");
-  float PETROSIAN_RF = psMetadataLookupF32 (&status, recipe, "PETROSIAN_FLUX_RATIO");
-  assert (status);
-
-  // first find flux at R0
-  int firstAbove = -1;
-  int lastBelow = -1;
-  for (int i = 0; i < radius->n; i++) {
-    if (radius->data.F32[i] < PETROSIAN_R0) lastBelow = i;
-    if ((firstAbove < 0) && (radius->data.F32[i] > PETROSIAN_R0)) firstAbove = i;
-  }
-  // if we don't go out far enough, we have a problem...
-  if (lastBelow == radius->n - 1) {
-    psTrace ("psphot", 5, "did not go out far enough to reach petrosian reference radius...");
-    // XXX skip object? raise a flag ?
-    return false;
-  }
-  if (firstAbove < 0) {
-    psTrace ("psphot", 5, "did not go out far enough to bound petrosian reference radius");
-    // XXX raise a flag ?
-    return false;
-  }
-
-  // average flux in this range
-  float fluxR0 = 0.0;
-  int fluxRn = 0;
-  for (int i = PS_MIN(firstAbove, lastBelow); i <= PS_MAX(firstAbove, lastBelow); i++) {
-    fluxR0 += flux->data.F32[i];
-    fluxRn ++;
-  }
-  fluxR0 /= (float)(fluxRn);
-
-  // target flux for petrosian radius
-  float fluxRP = fluxR0 * PETROSIAN_RF;
-
-  // find the first bin below the flux level and the last above the level
-  // XXX can this be done faster with bisection?
-  // XXX do I need to worry about crazy outliers?
-  // XXX should i be smoothing or fitting the curve?
-  int firstBelow = -1;
-  int lastAbove = -1;
-  for (int i = 0; i < flux->n; i++) {
-    if (flux->data.F32[i] > fluxRP) lastAbove = i;
-    if ((firstBelow < 0) && (flux->data.F32[i] < fluxRP)) firstBelow = i;
-  }
-  // if we don't go out far enough, we have a problem...
-  if (lastAbove == radius->n - 1) {
-    psTrace ("psphot", 5, "did not go out far enough to reach petrosian radius...");
-    // XXX skip object? raise a flag ?
-    return false;
-  }
-  if (firstBelow < 0) {
-    psTrace ("psphot", 5, "did not go out far enough to bound petrosian radius");
-    // XXX raise a flag ?
-    return false;
-  }
-
-  // need to examine pixels in this vicinity
-  float fluxFirst = 0;
-  float fluxLast = 0;
-  for (int i = 0; i <= PS_MAX(firstBelow, lastAbove); i++) {
-    if (i <= firstBelow) {
-      fluxFirst += flux->data.F32[i];
-    }
-    if (i <= lastAbove) {
-      fluxLast += flux->data.F32[i];
-    }
-  }
-  float fluxRPSum    = 0.5*(fluxLast + fluxFirst);
-  float fluxRPSumErr = 0.5*fabs(fluxLast - fluxFirst);
-  // XXX need to use the weight appropriately here...
-
-  float rad     = 0.5*(radius->data.F32[firstBelow] + radius->data.F32[lastAbove]);
-  float radErr  = 0.5*fabs(radius->data.F32[firstBelow] - radius->data.F32[lastAbove]);
-
-  if (!source->extpars->petrosian) {
-    source->extpars->petrosian = pmSourcePetrosianValuesAlloc ();
-  }
-
-  // these are uncalibrated: instrumental mags and pixel units
-  source->extpars->petrosian->mag    = -2.5*log10(fluxRPSum);
-  source->extpars->petrosian->magErr = fluxRPSumErr / fluxRPSum;
-
-  source->extpars->petrosian->rad    = rad;
-  source->extpars->petrosian->radErr = radErr;
-
-  psTrace ("psphot", 5, "Petrosian flux:%f +/- %f @ %f +/- %f for %f, %f\n",
-           source->extpars->petrosian->mag, source->extpars->petrosian->magErr,
-           source->extpars->petrosian->rad, source->extpars->petrosian->radErr,
-           source->peak->xf, source->peak->yf);
-
-  return true;
-
+    return true;
 }
Index: branches/eam_branches/20090820/psphot/src/psphotPetrosianAnalysis.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotPetrosianAnalysis.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotPetrosianAnalysis.c	(revision 25766)
@@ -0,0 +1,68 @@
+# include "psphotInternal.h"
+
+// aperture-like measurements for extended sources
+bool psphotPetrosianAnalysis (pmReadout *readout, psArray *sources, psMetadata *recipe) {
+
+    bool status;
+
+    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
+    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    assert (maskVal);
+
+    // XXX temporary user-supplied systematic sky noise measurement (derive from background model)
+    float skynoise = psMetadataLookupF32 (&status, recipe, "SKY.NOISE");
+
+# if (0)
+    // if backModel or backStdev are missing, the values of sky and/or skyErr will be set to NAN
+    // XXX use this to set skynoise
+    pmReadout *backModel = psphotSelectBackground (config, view);
+    pmReadout *backStdev = psphotSelectBackgroundStdev (config, view);
+# endif
+
+    // S/N limit to perform full non-linear fits
+    float SN_LIM = psMetadataLookupF32 (&status, recipe, "EXTENDED_SOURCE_SN_LIM");
+
+    // option to limit analysis to a specific region
+    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
+    psRegion AnalysisRegion = psRegionForImage (readout->image, psRegionFromString (region));
+    if (psRegionIsNaN (AnalysisRegion)) psAbort("analysis region mis-defined");
+
+    // source analysis is done in S/N order (brightest first)
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    // choose the sources of interest
+    for (int i = 0; i < sources->n; i++) {
+
+	pmSource *source = sources->data[i];
+
+	// skip PSF-like and non-astronomical objects
+	if (source->type == PM_SOURCE_TYPE_STAR) continue;
+	if (source->type == PM_SOURCE_TYPE_DEFECT) continue;
+	if (source->type == PM_SOURCE_TYPE_SATURATED) continue;
+	if (source->mode & PM_SOURCE_MODE_DEFECT) continue;
+	if (source->mode & PM_SOURCE_MODE_SATSTAR) continue;
+	if (!(source->mode & PM_SOURCE_MODE_EXT_LIMIT)) continue;
+
+	// limit selection to some SN limit
+	assert (source->peak); // how can a source not have a peak?
+	if (source->peak->SN < SN_LIM) continue;
+
+	// limit selection by analysis region
+	if (source->peak->x < AnalysisRegion.x0) continue;
+	if (source->peak->y < AnalysisRegion.y0) continue;
+	if (source->peak->x > AnalysisRegion.x1) continue;
+	if (source->peak->y > AnalysisRegion.y1) continue;
+
+	// replace object in image
+	if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
+	    pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
+	}
+
+	psphotPetrosianProfile (readout, source, skynoise);
+
+	pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+    }
+
+    psphotVisualShowResidualImage (readout);
+    return true;
+}
Index: branches/eam_branches/20090820/psphot/src/psphotPetrosianProfile.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotPetrosianProfile.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotPetrosianProfile.c	(revision 25766)
@@ -0,0 +1,80 @@
+# include "psphotInternal.h"
+
+// generate the Petrosian radius and flux using elliptical contours
+
+// XXX much of this function is focused on generating the clean contours, which can be used by 
+// any number of aperture-like measurements.  probably will want to rename the pmPetrosian
+// structure to something the pmRadialProfile
+
+bool psphotPetrosianProfile (pmReadout *readout, pmSource *source, float skynoise) {
+
+    // container to hold results from the radial profile analysis
+    pmPetrosian *petrosian = pmPetrosianAlloc();
+
+    // XXX these need to go into recipe values
+    int Nsec = 24;
+    float Rmax = 200;
+    float fluxMin = 0.0;
+    float fluxMax = source->peak->flux;
+
+    // generate a series of radial profiles at Nsec evenly spaced angles.  the profile flux
+    // is measured by interpolation for small radii; for large radii, the pixels in a box
+    // are averaged to increase the S/N (XXX not yet done)
+    if (!psphotRadialProfilesByAngles (source, petrosian, Nsec, Rmax)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to measure radial profile for petrosian");
+	psFree (petrosian);
+	return false;
+    }
+
+    // use the radial profiles to determine the radius of a given isophote.  this isophote
+    // is used to determine the elliptical shape of the object, so it has a relatively high
+    // value (nominally 50% of the peak)
+    if (!psphotRadiiFromProfiles (source, petrosian, fluxMin, fluxMax)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to measure isophotal radii from profiles");
+	psFree (petrosian);
+	return false;
+    }
+
+    // convert the isophotal radius vs angle measurements to an elliptical contour
+    if (!psphotEllipticalContour (source, petrosian)) {
+	psLogMsg ("psphot", 3, "failed to measure elliptical contour");
+	psFree (petrosian);
+	return false;
+    }
+  
+    // generate a single, normalized radial profile following the elliptical contours.
+    // the radius is normalized by the axis ratio so that on the major axis, 1 pixel = 1 pixel
+    if (!psphotEllipticalProfile (source, petrosian)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
+	psFree (petrosian);
+	return false;
+    }
+  
+    // integrate the radial profile for radial bins defined for the petrosian measurement:
+    // SB_i (r_i) where \alpha r_i < r < \beta r_i
+    if (!psphotPetrosianRadialBins (source, petrosian, Rmax, skynoise)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
+	psFree (petrosian);
+	return false;
+    }
+  
+    // use the SB_i from above to calculate the petrosian radius and the flux within that radius
+    if (!psphotPetrosianStats (source, petrosian)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
+	psFree (petrosian);
+	return false;
+    }
+  
+    // XXX this will only work in the psphot context, not the psphotPetrosianStudy...
+    // XXX add the petrosian to the pmSource structure...
+    // psphotVisualShowResidualImage (readout);
+    psphotVisualShowPetrosian (source, petrosian);
+
+    psphotPetrosianFreeVectors(petrosian);
+
+    psTrace ("psphot", 3, "source at %f,%f: petrosian radius: %f, flux: %f, axis ratio: %f, angle: %f",
+	     source->peak->xf, source->peak->yf, petrosian->petrosianRadius, petrosian->petrosianFlux, petrosian->axes.minor/petrosian->axes.major, PS_DEG_RAD*petrosian->axes.theta);
+
+    psFree (petrosian);
+    return true;
+}
Index: branches/eam_branches/20090820/psphot/src/psphotPetrosianRadialBins.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotPetrosianRadialBins.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotPetrosianRadialBins.c	(revision 25766)
@@ -0,0 +1,189 @@
+# include "psphotInternal.h"
+
+// convert the flux vs elliptical radius to annular bins
+
+// we are guaranteed to be limited by either the seeing (1 - few pixels) or by the pixels
+// themselves.  this function does not attempt to measure the radial profiles accurately
+// for radii that are smaller than a minimum (currently 1.0 pixels).  
+
+// for small radii, we are measuring the mean surface brightness in non-overlapping radial
+// bins.  for large radii (r > 2 pixels), we are measuring the surface brightness for a
+// radius range \alpha r_i < i < \beta r_i, but performing this measurement for radii more
+// finely spaced than r_{i+1} = r_i * \beta / \alpha.  for the integration, we need to
+// track the non-overlapping radius values.
+
+// XXX move the resulting elements from profile to extpars->petrosian?
+bool psphotPetrosianRadialBins (pmSource *source, float radiusMax, float skynoise) {
+
+    pmSourceRadialProfile *profile = source->extpars->profile;
+
+    float skyModelErrorSQ = PS_SQR(skynoise);
+
+    psVector *radius = profile->radiusElliptical;
+    psVector *flux = profile->fluxElliptical;
+
+    // sort incoming vectors by radius
+    pmSourceRadialProfileSortPair (radius, flux);
+
+    int nMax = radiusMax;
+
+    // radBin stores the centers of the radial bins, 
+    // radMin, radMax store the bounds
+    psVector *radMin  = psVectorAllocEmpty(nMax, PS_TYPE_F32);
+    psVector *radMax  = psVectorAllocEmpty(nMax, PS_TYPE_F32);
+    psVector *radAlp  = psVectorAllocEmpty(nMax, PS_TYPE_F32);
+    psVector *radBet  = psVectorAllocEmpty(nMax, PS_TYPE_F32);
+
+    psVector *binSB      = psVectorAllocEmpty(nMax, PS_TYPE_F32); // surface brightness of radial bin
+    psVector *binSBstdev = psVectorAllocEmpty(nMax, PS_TYPE_F32); // surface brightness of radial bin
+    psVector *binRad  	 = psVectorAllocEmpty(nMax, PS_TYPE_F32); // mean radius of radial bin
+    psVector *binArea 	 = psVectorAllocEmpty(nMax, PS_TYPE_F32); // area of radial bin (contiguous, non-overlapping)
+
+    psVectorInit (binSB, 0.0);
+    psVectorInit (binSBstdev, 0.0);
+    psVectorInit (binRad, 0.0);
+
+    // generate radial bin bounds
+    radMin->data.F32[0] = 0.0;
+    radMax->data.F32[0] = 1.0;
+    radAlp->data.F32[0] = 0.0;
+    radBet->data.F32[0] = 1.0;
+    
+    radMin->data.F32[1] = 1.0;
+    radMax->data.F32[1] = 1.5;
+    radAlp->data.F32[1] = 1.0;
+    radBet->data.F32[1] = 1.5;
+    
+    radMin->data.F32[2] = 1.5;
+    radMax->data.F32[2] = 2.0;
+    radAlp->data.F32[2] = 1.5;
+    radBet->data.F32[2] = 2.0;
+    
+# define PETROSIAN_ALPHA 0.8
+# define PETROSIAN_BETA 1.25
+# define POWER_LAW_SPACING true
+    
+    // power-law spacing with overlapping boundaries at the geometric mid-points
+    float rBeta = sqrt(PETROSIAN_BETA);
+    for (int i = 3; radBet->data.F32[i-1] < radiusMax; i++) {
+	if (POWER_LAW_SPACING) {
+	    radMin->data.F32[i] = radMax->data.F32[i-1];
+	    radMax->data.F32[i] = radMin->data.F32[i] * PETROSIAN_BETA;
+	    radAlp->data.F32[i] = radMin->data.F32[i] / rBeta;
+	    radBet->data.F32[i] = radMax->data.F32[i] * rBeta;
+	} else {
+	    radMin->data.F32[i] = radMax->data.F32[i-1];
+	    radMax->data.F32[i] = radMin->data.F32[i] + 1;
+	    float rMid = 0.5*(radMin->data.F32[i] + radMax->data.F32[i]);
+	    radAlp->data.F32[i] = rMid * PETROSIAN_ALPHA;
+	    radBet->data.F32[i] = rMid * PETROSIAN_BETA;
+	}
+	radMin->n = radMax->n = radAlp->n = radBet->n = i + 1;
+    }
+
+    // generate radial area-weighted mean radius & non-overlapping areas
+    for (int i = 0; i < radMin->n; i++) {
+	float rMin = radMin->data.F32[i];
+	float rMax = radMax->data.F32[i];
+	
+	float rMin2 = rMin*rMin;
+	float rMin3 = rMin2*rMin;
+
+	float rMax2 = rMax*rMax;
+	float rMax3 = rMax2*rMax;
+
+	float rBin = 2.0 * (rMax3 - rMin3) / (rMax2 - rMin2) / 3.0;
+	
+	// XXX calculate area-weighted radius rather than asserting?
+	binRad->data.F32[i] = rBin;
+	binArea->data.F32[i] = M_PI * (rMax2 - rMin2);
+
+	psTrace ("psphot", 6, "%3d  %5.1f %5.1f : %5.1f : %5.1f %5.1f\n", 
+		 i, radAlp->data.F32[i], radMin->data.F32[i], binRad->data.F32[i],
+		 radMax->data.F32[i], radBet->data.F32[i]);
+    }
+
+    // storage vector for stats
+    psVector *values = psVectorAllocEmpty (flux->n, PS_TYPE_F32);
+    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);
+    // psStats *stats = psStatsAlloc(PS_STAT_FITTED_MEAN_V4 | PS_STAT_FITTED_STDEV_V4);
+
+    // integrate flux, radius for each of these bins.  since flux is sorted by radius, 
+    // we can do this fairly quickly
+
+    bool done = false;
+    int nOut = 0;
+    float Rmin = radAlp->data.F32[nOut];
+    float Rmax = radBet->data.F32[nOut];
+    float Rnxt = radAlp->data.F32[nOut+1];  // minimum radius for next range
+    int iNext = 0;
+    for (int i = 0; !done && (i < radius->n); i++) {
+	if (radius->data.F32[i] < Rnxt) {
+	  iNext = i;
+	}
+	if (radius->data.F32[i] > Rmax) {
+	    // calculate the value for the nOut bin
+	    float value, dvalue;
+	    if (values->n > 0) {
+		psVectorStats (stats, values, NULL, NULL, 0);
+		value = stats->robustMedian;
+		dvalue = stats->robustStdev;
+	    } else {
+		value = NAN;
+		dvalue = NAN;
+	    }
+	    // binSB->data.F32[nOut] = stats->sampleMedian;
+	    binSB->data.F32[nOut] = value;
+	    binSBstdev->data.F32[nOut] = sqrt(PS_SQR(dvalue) / values->n + skyModelErrorSQ);
+	    // binSB->data.F32[nOut] = stats->fittedMean;
+	    // binSBstdev->data.F32[nOut] = sqrt(PS_SQR(stats->fittedStdev) / values->n + skyModelErrorSQ);
+
+	    // error in the SB is the stdev per bin / sqrt (number of pixels) 
+	    // added in quadrature to a fraction of the local sky (not the 
+	    // residual flux, but the sky from the sky model)
+
+	    psTrace ("psphot", 5, "%3d  %5.1f %5.1f : %5.1f  %5.2f\n", 
+		     nOut, radAlp->data.F32[nOut], radBet->data.F32[nOut], binSB->data.F32[nOut], binSBstdev->data.F32[nOut]);
+
+	    nOut ++;
+	    if (nOut >= radAlp->n) break;
+	    Rmin = radAlp->data.F32[nOut];
+	    Rmax = radBet->data.F32[nOut];
+	    Rnxt = (nOut < nMax - 1) ? radAlp->data.F32[nOut+1] : Rmax;  // minimum radius for next range
+	    values->n = 0;
+	    psStatsInit(stats);
+	    i = iNext;
+	}
+	if (radius->data.F32[i] < Rmin) {
+	    continue;
+	}
+	psVectorAppend (values, flux->data.F32[i]);
+    }
+    binSB->n = binSBstdev->n = binRad->n = binArea->n = nOut;
+    // XXX I think this misses the last radial bin -- do we care?
+
+    // save the vectors
+    profile->radialBins = binRad;
+    profile->area       = binArea;
+    profile->binSB      = binSB;
+    profile->binSBstdev = binSBstdev;
+
+    // psphotPetrosianVisualProfileRadii (radius, flux, binRad, binSB, source->peak->flux, 0.0);
+
+    psFree(radMin);
+    psFree(radMax);
+    psFree(radAlp);
+    psFree(radBet);
+    psFree(values);
+    psFree(stats);
+
+    return true;
+}
+
+// the area-weighted mean radius is given by:
+
+// integral r * 2 pi r dr / integral 2 pi r dr
+
+// = 2/3 pi (r_max^3 - r_min^3)  / pi (r_max^2 - r_min^2) 
+// = 2/3 (r_max^3 - r_min^3) / (r_max^2 - r_min^2)
+
Index: branches/eam_branches/20090820/psphot/src/psphotPetrosianStats.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotPetrosianStats.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotPetrosianStats.c	(revision 25766)
@@ -0,0 +1,170 @@
+# include "psphotInternal.h"
+
+# define PETROSIAN_RATIO 0.2
+# define PETROSIAN_RADII 2.0
+
+// generate the Petrosian radius and flux from the mean surface brightness (r_i)
+
+float InterpolateValues (float X0, float Y0, float X1, float Y1, float X);
+
+bool psphotPetrosianStats (pmSource *source) {
+
+    pmSourceRadialProfile *profile = source->extpars->profile;
+
+    float petRadius = NAN;
+    float petFlux = NAN;
+
+    psVector *binSB      = profile->binSB;
+    psVector *binSBstdev = profile->binSBstdev;
+    psVector *binRad     = profile->radialBins;
+    psVector *area       = profile->area;
+
+    psVector *fluxSum     = psVectorAllocEmpty(binSB->n, PS_TYPE_F32);
+    psVector *fluxSumErr2 = psVectorAllocEmpty(binSB->n, PS_TYPE_F32);
+    psVector *refRadius   = psVectorAllocEmpty(binSB->n, PS_TYPE_F32);
+    psVector *petRatio    = psVectorAllocEmpty(binSB->n, PS_TYPE_F32);
+    psVector *petRatioErr = psVectorAllocEmpty(binSB->n, PS_TYPE_F32);
+    psVector *meanSB      = psVectorAllocEmpty(binSB->n, PS_TYPE_F32);
+    psVector *areaSum     = psVectorAllocEmpty(binSB->n, PS_TYPE_F32);
+
+    bool anyPetro = false;
+    bool manyPetro = false;
+    bool above = true;
+    float Asum = 0.0;
+    float Fsum = 0.0;
+    float dFsum2 = 0.0;
+
+    float nSigma = 3.0;
+    int lowestSignificantRadius = 0;
+    float lowestSignificantRatio = 1.0;
+
+    int nOut = 0;
+    for (int i = 0; i < binSB->n; i++) {
+	// skip nan bins (do not contribute to flux or area)
+	if (!isfinite(binSB->data.F32[i])) continue;
+
+	float Area = area->data.F32[i];
+	Asum += Area;
+	Fsum += binSB->data.F32[i] * Area;
+	dFsum2 += PS_SQR(binSBstdev->data.F32[i] * Area);
+
+	float areaInner = 0.5 * Area;
+	float fluxInner = 0.5 * Area * binSB->data.F32[i];
+	float fluxInnerErr2 = PS_SQR(binSBstdev->data.F32[i] * 0.5 * Area);
+	if (nOut > 0) {
+	    areaInner += areaSum->data.F32[nOut-1];
+	    fluxInner += fluxSum->data.F32[nOut-1];
+	    fluxInnerErr2 += fluxSumErr2->data.F32[nOut-1];
+	}
+
+	// ratio = binSB / meanSB
+	// meanSB = flux / area
+	// flux = sum(binSB(i) * area(i)
+	// fluxErr^2 = sum(binSBerr(i)^2 area(i)^2)
+	// meanSBerr^2 = fluxErr^2 / area^2
+	// (ratioErr/ratio)^2 = (binSBerr/binSB)^2 + (meanSBerr/meanSB)^2
+
+	psVectorAppend(meanSB, (fluxInner / areaInner));
+
+	float ratio = binSB->data.F32[i] / meanSB->data.F32[nOut];
+	psVectorAppend(petRatio, ratio);
+
+	float meanSBerr = sqrt(fluxInnerErr2) / areaInner;
+	float ratioErr = fabs(ratio) * sqrt(PS_SQR(binSBstdev->data.F32[i]/binSB->data.F32[i]) + PS_SQR(meanSBerr/meanSB->data.F32[nOut]));
+
+	psVectorAppend(petRatioErr, ratioErr);
+
+	psVectorAppend(areaSum, Asum);
+	psVectorAppend(fluxSum, Fsum);
+	psVectorAppend(fluxSumErr2, dFsum2);
+	psVectorAppend(refRadius, binRad->data.F32[i]);
+
+	psTrace ("psphot", 4, "%3d : %5.2f : %5.3f %5.3f : %5.3f %5.3f : %5.3f %5.3f : %5.3f %5.3f : %5.1f %5.1f\n", 
+		 i, refRadius->data.F32[nOut], 
+		 binSB->data.F32[i], binSBstdev->data.F32[i], 
+		 meanSB->data.F32[nOut], meanSBerr, 
+		 petRatio->data.F32[nOut], petRatioErr->data.F32[nOut], 
+		 fluxSum->data.F32[nOut], sqrt(fluxSumErr2->data.F32[nOut]), areaSum->data.F32[nOut], areaInner);
+    
+	// anytime we transition below the PETROSIAN_RATIO, calculate the radius and flux
+	// we will keep and report the last (largest radius) value
+	if (above && (petRatio->data.F32[nOut] < PETROSIAN_RATIO) && (petRatio->data.F32[nOut] > nSigma*petRatioErr->data.F32[nOut])) {
+	    // interpolate Rvec between i-1 and i to PETROSIAN_RATIO to get flux (Fvec) and radius (rvec)
+	    if (i == 0) { 
+		// assume Fmax @ R = 0.0
+		petRadius = InterpolateValues (1.0, 0.0, petRatio->data.F32[nOut], refRadius->data.F32[nOut], PETROSIAN_RATIO);
+	    } else {
+		petRadius = InterpolateValues (petRatio->data.F32[nOut-1], refRadius->data.F32[nOut-1], petRatio->data.F32[nOut], refRadius->data.F32[nOut], PETROSIAN_RATIO);
+	    }
+	    above = false;
+	    if (anyPetro) manyPetro = true;
+	    anyPetro = true;
+	}
+    
+	// anytime we transition below the PETROSIAN_RATIO, calculate the radius and flux
+	// we will keep and report the last (largest radius) value
+	// find the last signficant measurement of the petrosian ratio
+	if (above && (petRatio->data.F32[nOut] < lowestSignificantRatio) && (petRatio->data.F32[nOut] > nSigma*petRatioErr->data.F32[nOut])) {
+	    lowestSignificantRadius = nOut;
+	    lowestSignificantRatio = petRatio->data.F32[nOut];
+	}
+    
+	// reset on transitions up, but do not re-calculate rad_90, flux_90
+	if (!above && (petRatio->data.F32[nOut] >= PETROSIAN_RATIO)) {
+	    above = true;
+	}
+	nOut ++;
+    }
+
+    if (!anyPetro) {
+	// interpolate Rvec between i-1 and i to PETROSIAN_RATIO to get flux (Fvec) and radius (rvec)
+	if (lowestSignificantRadius == 0) { 
+	    // assume Fmax @ R = 0.0
+	    petRadius = InterpolateValues (1.0, 0.0, petRatio->data.F32[lowestSignificantRadius], refRadius->data.F32[lowestSignificantRadius], PETROSIAN_RATIO);
+	} else {
+	    petRadius = InterpolateValues (petRatio->data.F32[lowestSignificantRadius-1], refRadius->data.F32[lowestSignificantRadius-1], petRatio->data.F32[lowestSignificantRadius], refRadius->data.F32[lowestSignificantRadius], PETROSIAN_RATIO);
+	}
+    }
+
+    // now measure the flux within PETROSIAN_RADII * petRadius 
+    float apRadius = PETROSIAN_RADII * petRadius;
+    for (int i = 0; i < refRadius->n; i++) {
+	// XXX use bisection to do this faster:
+	if (refRadius->data.F32[i] > apRadius) {
+	    if (i == 0) {
+		psWarning ("does this case make any sense? (refRadius[0] > apRadius)");
+		continue;
+	    } else {
+		petFlux = InterpolateValues (refRadius->data.F32[i-1], fluxSum->data.F32[i-1], refRadius->data.F32[i], fluxSum->data.F32[i], apRadius);
+		break;
+	    }
+	}
+    }
+
+    if (!source->extpars->petrosian_80) {
+        source->extpars->petrosian_80 = pmSourceExtendedFluxAlloc ();
+    }
+    pmSourceExtendedFlux *petrosian = source->extpars->petrosian_80;
+
+    // XXX save flags (anyPetro, manyPetro)
+    petrosian->radius = petRadius;
+    petrosian->flux   = petFlux;
+
+    // psphotPetrosianVisualStats (binRad, binSB, refRadius, meanSB, petRatio, petRatioErr, fluxSum, petRadius, PETROSIAN_RATIO, petFlux, apRadius);
+
+    psFree(fluxSum);
+    psFree(fluxSumErr2);
+    psFree(refRadius);
+    psFree(petRatio);
+    psFree(petRatioErr);
+    psFree(meanSB);
+    psFree(areaSum);
+
+    return true;
+}
+
+float InterpolateValues (float X0, float Y0, float X1, float Y1, float X) {
+    float Y = Y0 + (Y1 - Y0) * (X - X0) / (X1 - X0);
+    return Y;
+}
+
Index: branches/eam_branches/20090820/psphot/src/psphotPetrosianStudy.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotPetrosianStudy.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotPetrosianStudy.c	(revision 25766)
@@ -0,0 +1,184 @@
+# include "psphotInternal.h"
+
+# define DX 512
+# define DY 512
+
+// XXX add noise and seeing.
+// XXX double check on sersic functional form
+// XXX modify ratio if ratio > 1.0 (swap major and minor)
+
+pmPeak *psphotLocalPeak(pmReadout *readout, int Xo, int Yo);
+
+int main (int argc, char **argv) {
+
+  pmErrorRegister();                  // register psModule's error codes/messages
+  pmModelClassInit();
+
+  int N;
+  float Xo = 0.5*DX;
+  float Yo = 0.5*DY;
+  char *image = NULL;
+  pmSource *source = NULL;
+
+  float peak = 1000.0;
+  float sigma = 2.0;	      // major axis size 
+  float ARatio = 1.0;
+  float angle = 0.0;
+  float sersic = 0.5;
+  float skynoise = 0.0;
+  
+  if ((N = psArgumentGet (argc, argv, "-peak"))) {
+    psArgumentRemove (N, &argc, argv);
+    peak = atof(argv[N]);
+    psArgumentRemove (N, &argc, argv);
+  }
+  if ((N = psArgumentGet (argc, argv, "-sigma"))) {
+    psArgumentRemove (N, &argc, argv);
+    sigma = atof(argv[N]);
+    psArgumentRemove (N, &argc, argv);
+  }
+  if ((N = psArgumentGet (argc, argv, "-aratio"))) {
+    psArgumentRemove (N, &argc, argv);
+    ARatio = atof(argv[N]);
+    psArgumentRemove (N, &argc, argv);
+  }
+  if ((N = psArgumentGet (argc, argv, "-angle"))) {
+    psArgumentRemove (N, &argc, argv);
+    angle = PS_RAD_DEG*atof(argv[N]);
+    psArgumentRemove (N, &argc, argv);
+  }
+  if ((N = psArgumentGet (argc, argv, "-sersic"))) {
+    psArgumentRemove (N, &argc, argv);
+    sersic = atof(argv[N]);
+    psArgumentRemove (N, &argc, argv);
+  }
+  if ((N = psArgumentGet (argc, argv, "-skynoise"))) {
+    psArgumentRemove (N, &argc, argv);
+    skynoise = atof(argv[N]);
+    psArgumentRemove (N, &argc, argv);
+  }
+  if ((N = psArgumentGet (argc, argv, "-visual"))) {
+    psArgumentRemove (N, &argc, argv);
+    pmVisualSetVisual(true);
+  }
+  if ((N = psArgumentGet (argc, argv, "-coords"))) {
+    psArgumentRemove (N, &argc, argv);
+    Xo = atof(argv[N]);
+    psArgumentRemove (N, &argc, argv);
+    Yo = atof(argv[N]);
+    psArgumentRemove (N, &argc, argv);
+  }
+  if ((N = psArgumentGet (argc, argv, "-image"))) {
+    psArgumentRemove (N, &argc, argv);
+    image = psStringCopy (argv[N]);
+    psArgumentRemove (N, &argc, argv);
+  }
+
+  if (argc != 1) {
+    fprintf (stderr, "USAGE: psphotPetrosianStudy\n");
+    exit (2);
+  }
+
+  // create a containing image & associated readout
+  pmReadout *readout = pmReadoutAlloc(NULL);
+  if (!image) {
+      readout->image = psImageAlloc(DX, DY, PS_TYPE_F32);
+
+      // create a dummy variance, but don't populate -- it is not used by pmSourceMoments if the sigma parameters is set to 0.0
+      readout->variance = psImageAlloc(DX, DY, PS_TYPE_F32);
+
+      // create a model & associated source
+      pmModelType type = pmModelClassGetType("PS_MODEL_SERSIC");
+      pmModel *model = pmModelAlloc(type);
+
+      // set the model parameters
+      model->params->data.F32[PM_PAR_SKY]  = 0.0;
+      model->params->data.F32[PM_PAR_I0]   = peak;
+      model->params->data.F32[PM_PAR_XPOS] = Xo;
+      model->params->data.F32[PM_PAR_YPOS] = Yo;
+
+      psEllipseAxes axes;
+      axes.major = sigma;
+      axes.minor = sigma*ARatio;
+      axes.theta = angle;
+
+      psEllipseShape shape = psEllipseAxesToShape (axes);
+
+      // XXX set the sigma with user input
+      model->params->data.F32[PM_PAR_SXX]  = shape.sx * M_SQRT2;
+      model->params->data.F32[PM_PAR_SYY]  = shape.sy * M_SQRT2;
+      model->params->data.F32[PM_PAR_SXY]  = shape.sxy;
+
+      if (model->params->n > 7) {
+	  model->params->data.F32[PM_PAR_7]  = sersic;
+      }
+
+      // generate source container & populate image
+      source = pmSourceFromModel(model, readout, Xo, PM_SOURCE_TYPE_STAR);
+
+      // generate the modelFlux 
+      pmSourceCacheModel(source, 0);
+
+      // instantiate the source
+      pmSourceAdd(source, PM_MODEL_OP_FUNC, 0); 
+
+      // XXX add noise here...
+      psphotSaveImage(NULL, readout->image, "sersic.fits");
+
+  } else {
+      psRegion full = psRegionSet(0,0,0,0);
+      psFits *fits = psFitsOpen(image, "r");
+      readout->image = psFitsReadImage(fits, full, 0);
+
+      source = pmSourceAlloc();
+      source->peak = psphotLocalPeak(readout, Xo, Yo);
+      pmSourceDefinePixels (source, readout, Xo, Yo, 128);
+  }
+
+  psphotPetrosianProfile (readout, source, skynoise);
+
+  psFree (source);
+
+  exit (0);
+}
+
+// Xo, Yo are in parent coords
+pmPeak *psphotLocalPeak(pmReadout *readout, int Xo, int Yo) {
+
+    int Xp = Xo;
+    int Yp = Yo;
+    float peakFlux = readout->image->data.F32[Yp][Xp];
+
+    // find local peak within +/- 3 pix of the given coordinate
+    for (int iy = Yo - 3; iy <= Yo + 3; iy++) {
+	for (int ix = Xo - 3; ix <= Xo + 3; ix++) {
+	    if (peakFlux < readout->image->data.F32[iy][ix]) {
+		Xp = ix;
+		Yp = iy;
+		peakFlux = readout->image->data.F32[Yp][Xp];
+	    }
+	}
+    }
+
+    pmPeak *peak = pmPeakAlloc(Xp, Yp, peakFlux, PM_PEAK_LONE);
+
+    // calculate fractional peak position relative to Xp,Yp
+    psPolynomial2D *bicube = psImageBicubeFit (readout->image, Xp, Yp);
+    psPlane min = psImageBicubeMin (bicube);
+    psFree (bicube);
+
+    // if min point is too deviant, use the peak value
+    if ((fabs(min.x) < 1.5) && (fabs(min.y) < 1.5)) {
+        peak->xf = min.x + Xp;
+        peak->yf = min.y + Yp;
+
+	// xf,yf must land on image with 0 pixel border
+	peak->xf = PS_MAX (PS_MIN (peak->xf, readout->image->numCols - 1), readout->image->col0);
+	peak->yf = PS_MAX (PS_MIN (peak->yf, readout->image->numRows - 1), readout->image->row0);
+    } else {
+        peak->xf = Xp;
+        peak->yf = Yp;
+    }
+
+    return peak;
+}
Index: branches/eam_branches/20090820/psphot/src/psphotPetrosianVisual.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotPetrosianVisual.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotPetrosianVisual.c	(revision 25766)
@@ -0,0 +1,405 @@
+# include "psphotInternal.h"
+
+// this function displays representative images as the psphot analysis progresses:
+// 0 : image, 1 : variance
+// 0 : backsub, 1 : variance, 2 : backgnd
+// 0 : backsub, 1 : variance, 2 : signif
+// (overlay peaks on images)
+// (overlay footprints on images)
+// (overlay moments on images)
+// (overlay rough class on images)
+// 0 : backsub, 1 : psfpos, 2: psfsub
+// 0 : backsub, 1 : lin_resid, 2: psfsub
+
+# if (HAVE_KAPA)
+# include <kapa.h>
+
+// functions used to visualize the analysis as it goes
+// these are invoked by the -visual options
+
+static int kapa = -1;
+static int kapa2 = -1;
+
+// if no valid data is supplied (NULL or n <- 0), leave limits as they were
+bool pmVisualLimitsFromVectors (Graphdata *graphdata, psVector *xVec, psVector *yVec) {
+
+    if (xVec && xVec->n > 0) {
+	graphdata->xmin = graphdata->xmax = xVec->data.F32[0];
+	for (int i = 1; i < xVec->n; i++) {
+	    if (!isfinite(xVec->data.F32[i])) continue;
+	    graphdata->xmin = PS_MIN (graphdata->xmin, xVec->data.F32[i]);
+	    graphdata->xmax = PS_MAX (graphdata->xmax, xVec->data.F32[i]);
+	}
+	float range = graphdata->xmax - graphdata->xmin;
+	graphdata->xmax += 0.05*range;
+	graphdata->xmin -= 0.05*range;
+    }
+    if (yVec && yVec->n > 0) {
+	graphdata->ymin = graphdata->ymax = yVec->data.F32[0];
+	for (int i = 1; i < yVec->n; i++) {
+	    if (!isfinite(yVec->data.F32[i])) continue;
+	    graphdata->ymin = PS_MIN (graphdata->ymin, yVec->data.F32[i]);
+	    graphdata->ymax = PS_MAX (graphdata->ymax, yVec->data.F32[i]);
+	}
+	float range = graphdata->ymax - graphdata->ymin;
+	graphdata->ymax += 0.05*range;
+	graphdata->ymin -= 0.05*range;
+    }
+    return true;
+}
+
+bool psphotPetrosianVisualProfileByAngle (psVector *radius, psVector *flux) {
+
+    Graphdata graphdata;
+
+    // return true;
+    if (!pmVisualIsVisual()) return true;
+
+    if (kapa2 == -1) {
+        kapa2 = KapaOpenNamedSocket ("kapa", "psphot:plots");
+        if (kapa2 == -1) {
+            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+            pmVisualSetVisual(false);
+            return false;
+        }
+    }
+
+    KapaClearPlots (kapa2);
+    KapaInitGraph (&graphdata);
+    KapaSetFont (kapa2, "courier", 14);
+
+    pmVisualLimitsFromVectors (&graphdata, radius, flux);
+    KapaSetLimits (kapa2, &graphdata);
+
+    KapaBox (kapa2, &graphdata);
+    KapaSendLabel (kapa2, "radius", KAPA_LABEL_XM);
+    KapaSendLabel (kapa2, "flux", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.style = 2;
+    graphdata.ptype = 0;
+    graphdata.size = 1.0;
+    KapaPrepPlot (kapa2, radius->n, &graphdata);
+    KapaPlotVector (kapa2, radius->n, radius->data.F32, "x");
+    KapaPlotVector (kapa2, radius->n, flux->data.F32, "y");
+
+    // pause and wait for user input:
+    // continue, save (provide name), ??
+    char key[10];
+    fprintf (stdout, "[c]ontinue? ");
+    if (!fgets(key, 8, stdin)) {
+        psWarning("Unable to read option");
+    }
+    return true;
+}
+
+bool psphotPetrosianVisualProfileRadii (psVector *radius, psVector *flux, psVector *radiusBin, psVector *fluxBin, float peakFlux, float RadiusRef) {
+
+    float FluxRef = 500.0;
+
+    Graphdata graphdata;
+
+    // return true;
+    if (!pmVisualIsVisual()) return true;
+
+    if (kapa == -1) {
+        kapa = KapaOpenNamedSocket ("kapa", "psphot:plots");
+        if (kapa == -1) {
+            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+            pmVisualSetVisual(false);
+            return false;
+        }
+    }
+
+    KapaClearPlots (kapa);
+    KapaInitGraph (&graphdata);
+    KapaSetFont (kapa, "courier", 14);
+
+    graphdata.ymax = +1.05*peakFlux;
+    graphdata.ymin = -0.05*peakFlux;
+    pmVisualLimitsFromVectors (&graphdata, radius, NULL);
+    KapaSetLimits (kapa, &graphdata);
+
+    KapaBox (kapa, &graphdata);
+    KapaSendLabel (kapa, "radius", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "flux", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.style = 2;
+    graphdata.ptype = 0;
+    graphdata.size = 1.0;
+    KapaPrepPlot (kapa, radius->n, &graphdata);
+    KapaPlotVector (kapa, radius->n, radius->data.F32, "x");
+    KapaPlotVector (kapa, radius->n, flux->data.F32, "y");
+
+    // do this with log-r, log-flux?
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.style = 2;
+    graphdata.ptype = 2;
+    graphdata.size = 2.0;
+    KapaPrepPlot   (kapa, radiusBin->n, &graphdata);
+    KapaPlotVector (kapa, radiusBin->n, radiusBin->data.F32, "x");
+    KapaPlotVector (kapa, radiusBin->n, fluxBin->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.style = 2;
+    graphdata.ptype = 7;
+    graphdata.size = 3.0;
+    KapaPrepPlot (kapa, 1, &graphdata);
+    KapaPlotVector (kapa, 1, &RadiusRef, "x");
+    KapaPlotVector (kapa, 1, &FluxRef, "y");
+
+    fprintf (stderr, "radius: %f\n", RadiusRef);
+
+    // pause and wait for user input:
+    // continue, save (provide name), ??
+    char key[10];
+    fprintf (stdout, "[c]ontinue? ");
+    if (!fgets(key, 8, stdin)) {
+        psWarning("Unable to read option");
+    }
+    return true;
+}
+
+bool psphotPetrosianVisualStats (psVector *radBin, psVector *fluxBin, 
+				 psVector *refRadius, psVector *meanSB, 
+				 psVector *petRatio, psVector *petRatioErr,
+				 psVector *fluxSum, 
+				 float petRadius, float ratioForRadius,
+				 float petFlux, float radiusForFlux)
+{
+    Graphdata graphdata;
+    KapaSection section;
+
+    if (!pmVisualIsVisual()) return true;
+
+    if (kapa == -1) {
+        kapa = KapaOpenNamedSocket ("kapa", "psphot:plots");
+        if (kapa == -1) {
+            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+            pmVisualSetVisual(false);
+            return false;
+        }
+    }
+
+    KapaClearPlots (kapa);
+    KapaInitGraph (&graphdata);
+    KapaSetFont (kapa, "courier", 14);
+
+    // radius vs flux
+    // radius vs mean SB
+    // radius vs petRatio
+
+    // *** section 1: radius vs mean SB
+    section.dx = 1.00;
+    section.dy = 0.33;
+    section.x  = 0.00;
+    section.y  = 0.00;
+    section.name = psStringCopy ("meanSB");
+    KapaSetSection (kapa, &section);
+    psFree (section.name);
+
+    graphdata.color = KapaColorByName ("black");
+    pmVisualLimitsFromVectors (&graphdata, radBin, fluxBin);
+    KapaSetLimits (kapa, &graphdata);
+
+    KapaBox (kapa, &graphdata);
+    KapaSendLabel (kapa, "radius", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "mean SB", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.style = 2;
+    graphdata.ptype = 0;
+    graphdata.size = 1.0;
+    KapaPrepPlot (kapa, radBin->n, &graphdata);
+    KapaPlotVector (kapa, radBin->n, radBin->data.F32, "x");
+    KapaPlotVector (kapa, radBin->n, fluxBin->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.style = 2;
+    graphdata.ptype = 1;
+    graphdata.size = 2.0;
+    KapaPrepPlot (kapa, refRadius->n, &graphdata);
+    KapaPlotVector (kapa, refRadius->n, refRadius->data.F32, "x");
+    KapaPlotVector (kapa, refRadius->n, meanSB->data.F32, "y");
+
+    // *** section 2: radius vs petrosian ratio
+    section.dx = 1.00;
+    section.dy = 0.33;
+    section.x  = 0.00;
+    section.y  = 0.33;
+    section.name = psStringCopy ("ratio");
+    KapaSetSection (kapa, &section);
+    psFree (section.name);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ymax = +1.05;
+    graphdata.ymin = -0.05;
+    pmVisualLimitsFromVectors (&graphdata, radBin, NULL);
+    KapaSetLimits (kapa, &graphdata);
+
+    KapaBox (kapa, &graphdata);
+    KapaSendLabel (kapa, "radius", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "ratio", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.style = 2;
+    graphdata.ptype = 0;
+    graphdata.size = 1.0;
+    graphdata.etype = 0x01;
+    KapaPrepPlot (kapa, refRadius->n, &graphdata);
+    KapaPlotVector (kapa, refRadius->n, refRadius->data.F32, "x");
+    KapaPlotVector (kapa, refRadius->n, petRatio->data.F32, "y");
+    KapaPlotVector (kapa, refRadius->n, petRatioErr->data.F32, "dym");
+    KapaPlotVector (kapa, refRadius->n, petRatioErr->data.F32, "dyp");
+    graphdata.etype = 0;
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.style = 2;
+    graphdata.ptype = 2;
+    graphdata.size = 2.0;
+    KapaPrepPlot   (kapa, 1, &graphdata);
+    KapaPlotVector (kapa, 1, &petRadius, "x");
+    KapaPlotVector (kapa, 1, &ratioForRadius, "y");
+
+    // *** section 3: radius vs integrated flux
+    section.dx = 1.00;
+    section.dy = 0.33;
+    section.x  = 0.00;
+    section.y  = 0.66;
+    section.name = psStringCopy ("flux");
+    KapaSetSection (kapa, &section);
+    psFree (section.name);
+
+    graphdata.color = KapaColorByName ("black");
+    pmVisualLimitsFromVectors (&graphdata, radBin, fluxSum);
+    KapaSetLimits (kapa, &graphdata);
+
+    KapaBox (kapa, &graphdata);
+    KapaSendLabel (kapa, "radius", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "integrated flux", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.style = 2;
+    graphdata.ptype = 0;
+    graphdata.size = 1.0;
+    KapaPrepPlot   (kapa, refRadius->n, &graphdata);
+    KapaPlotVector (kapa, refRadius->n, refRadius->data.F32, "x");
+    KapaPlotVector (kapa, refRadius->n, fluxSum->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 2;
+    graphdata.style = 2;
+    graphdata.size = 2.0;
+    KapaPrepPlot   (kapa, 1, &graphdata);
+    KapaPlotVector (kapa, 1, &radiusForFlux, "x");
+    KapaPlotVector (kapa, 1, &petFlux, "y");
+
+    // pause and wait for user input:
+    // continue, save (provide name), ??
+    char key[10];
+    fprintf (stdout, "[c]ontinue? ");
+    if (!fgets(key, 8, stdin)) {
+        psWarning("Unable to read option");
+    }
+    return true;
+}
+
+bool psphotPetrosianVisualEllipticalContour (pmPetrosian *petrosian) {
+
+    Graphdata graphdata;
+
+    if (!pmVisualIsVisual()) return true;
+
+    if (kapa == -1) {
+        kapa = KapaOpenNamedSocket ("kapa", "psphot:plots");
+        if (kapa == -1) {
+            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+            pmVisualSetVisual(false);
+            return false;
+        }
+    }
+
+    KapaClearPlots (kapa);
+    KapaInitGraph (&graphdata);
+    KapaSetFont (kapa, "courier", 14);
+
+    psVector *theta = petrosian->theta;
+    psVector *radius = petrosian->isophotalRadii;
+
+    // find Rmin and Rmax for the initial guess
+    float Rmin = radius->data.F32[0];
+    float Rmax = radius->data.F32[0];
+
+    psVector *Rx = psVectorAlloc(radius->n, PS_TYPE_F32);
+    psVector *Ry = psVectorAlloc(radius->n, PS_TYPE_F32);
+
+    for (int i = 0; i < theta->n; i++) {
+	Rx->data.F32[i] = radius->data.F32[i]*cos(theta->data.F32[i]);
+	Ry->data.F32[i] = radius->data.F32[i]*sin(theta->data.F32[i]);
+
+	// check the radius range
+	Rmin = MIN (Rmin, radius->data.F32[i]);
+	Rmax = MAX (Rmax, radius->data.F32[i]);
+    }	
+
+    psVector *rx = psVectorAlloc(361, PS_TYPE_F32);
+    psVector *ry = psVectorAlloc(361, PS_TYPE_F32);
+
+    float epsilon = petrosian->axes.minor / petrosian->axes.major;
+
+    for (int i = 0; i < 361; i++) {
+
+	float alpha = PS_RAD_DEG * i;
+
+	float cs_alpha = cos(alpha);
+	float sn_alpha = sin(alpha);
+
+	float cs_phi = cos(alpha - petrosian->axes.theta);
+	float sn_phi = sin(alpha - petrosian->axes.theta);
+
+	float r = 1.0 / sqrt(SQ(sn_phi) + SQ(epsilon*cs_phi));
+
+	// generate the model fit here
+	rx->data.F32[i] = petrosian->axes.minor * cs_alpha * r;
+	ry->data.F32[i] = petrosian->axes.minor * sn_alpha * r;
+    }	
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.xmin = -1.1*Rmax;
+    graphdata.ymin = -1.1*Rmax;
+    graphdata.xmax = +1.1*Rmax;
+    graphdata.ymax = +1.1*Rmax;
+    KapaSetLimits (kapa, &graphdata);
+
+    KapaBox (kapa, &graphdata);
+    KapaSendLabel (kapa, "R_x", KAPA_LABEL_XM);
+    KapaSendLabel (kapa, "R_y", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.style = 2;
+    graphdata.ptype = 2;
+    graphdata.size = 1.0;
+    KapaPrepPlot (kapa, Rx->n, &graphdata);
+    KapaPlotVector (kapa, Rx->n, Rx->data.F32, "x");
+    KapaPlotVector (kapa, Rx->n, Ry->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.style = 0;
+    graphdata.ptype = 0;
+    graphdata.size = 1.0;
+    KapaPrepPlot (kapa, rx->n, &graphdata);
+    KapaPlotVector (kapa, rx->n, rx->data.F32, "x");
+    KapaPlotVector (kapa, rx->n, ry->data.F32, "y");
+
+    // pause and wait for user input:
+    // continue, save (provide name), ??
+    char key[10];
+    fprintf (stdout, "[c]ontinue? ");
+    if (!fgets(key, 8, stdin)) {
+        psWarning("Unable to read option");
+    }
+    return true;
+}
+
+# endif
Index: branches/eam_branches/20090820/psphot/src/psphotRadialProfile.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotRadialProfile.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotRadialProfile.c	(revision 25766)
@@ -1,21 +1,5 @@
 # include "psphotInternal.h"
 
-# define COMPARE_RADIUS(A,B) (radius->data.F32[A] < radius->data.F32[B])
-# define SWAP_RADIUS(TYPE,A,B) { \
-  float tmp; \
-  if (A != B) { \
-    tmp = radius->data.F32[A]; \
-    radius->data.F32[A] = radius->data.F32[B]; \
-    radius->data.F32[B] = tmp; \
-    tmp = flux->data.F32[A]; \
-    flux->data.F32[A] = flux->data.F32[B]; \
-    flux->data.F32[B] = tmp; \
-    tmp = variance->data.F32[A]; \
-    variance->data.F32[A] = variance->data.F32[B]; \
-    variance->data.F32[B] = tmp; \
-  } \
-}
-
-bool psphotRadialProfile (pmSource *source, psMetadata *recipe, psImageMaskType maskVal) {
+bool psphotRadialProfile (pmSource *source, psMetadata *recipe, float skynoise, psImageMaskType maskVal) {
 
     // allocate pmSourceExtendedParameters, if not already defined
@@ -28,44 +12,39 @@
     }
 
-    int nPts = source->pixels->numRows * source->pixels->numCols;
-    source->extpars->profile->radius = psVectorAllocEmpty (nPts, PS_TYPE_F32);
-    source->extpars->profile->flux   = psVectorAllocEmpty (nPts, PS_TYPE_F32);
-    source->extpars->profile->variance = psVectorAllocEmpty (nPts, PS_TYPE_F32);
+    // XXX these need to go into recipe values
+    int Nsec = 24;
+    float Rmax = 200;
+    float fluxMin = 0.0;
+    float fluxMax = source->peak->flux;
 
-    psVector *radius = source->extpars->profile->radius;
-    psVector *flux   = source->extpars->profile->flux;
-    psVector *variance = source->extpars->profile->variance;
+    // generate a series of radial profiles at Nsec evenly spaced angles.  the profile flux
+    // is measured by interpolation for small radii; for large radii, the pixels in a box
+    // are averaged to increase the S/N
+    if (!psphotRadialProfilesByAngles (source, Nsec, Rmax)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to measure radial profile for petrosian");
+	return false;
+    }
 
-    // XXX use the extended source model here for Xo, Yo?
-    // XXX define a radius scaled to the elliptical contour?
+    // use the radial profiles to determine the radius of a given isophote.  this isophote
+    // is used to determine the elliptical shape of the object, so it has a relatively high
+    // value (nominally 50% of the peak)
+    if (!psphotRadiiFromProfiles (source, fluxMin, fluxMax)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to measure isophotal radii from profiles");
+	return false;
+    }
 
-    int n = 0;
-
-    float Xo = 0.0;
-    float Yo = 0.0;
-
-    if (source->modelEXT) {
-      Xo = source->modelEXT->params->data.F32[PM_PAR_XPOS] - source->pixels->col0;
-      Yo = source->modelEXT->params->data.F32[PM_PAR_YPOS] - source->pixels->row0;
-    } else {
-      Xo = source->peak->xf - source->pixels->col0;
-      Yo = source->peak->yf - source->pixels->row0;
+    // convert the isophotal radius vs angle measurements to an elliptical contour
+    if (!psphotEllipticalContour (source)) {
+	psLogMsg ("psphot", 3, "failed to measure elliptical contour");
+	return false;
     }
-    for (int iy = 0; iy < source->pixels->numRows; iy++) {
-        for (int ix = 0; ix < source->pixels->numCols; ix++) {
-            if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) continue;
-            radius->data.F32[n] = hypot (ix - Xo, iy - Yo) ;
-            flux->data.F32[n]   = source->pixels->data.F32[iy][ix];
-            variance->data.F32[n] = source->variance->data.F32[iy][ix];
-            n++;
-        }
+  
+    // generate a single, normalized radial profile following the elliptical contours.
+    // the radius is normalized by the axis ratio so that on the major axis, 1 pixel = 1 pixel
+    if (!psphotEllipticalProfile (source)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to generate elliptical profile");
+	return false;
     }
-    radius->n = n;
-    variance->n = n;
-    flux->n = n;
-
-    // sort the vector set by the radius
-    PSSORT (radius->n, COMPARE_RADIUS, SWAP_RADIUS, NONE);
-
+  
     return true;
 }
Index: branches/eam_branches/20090820/psphot/src/psphotRadialProfileByAngles.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotRadialProfileByAngles.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotRadialProfileByAngles.c	(revision 25766)
@@ -0,0 +1,239 @@
+# include "psphotInternal.h"
+
+// Given a source at (x,y), generate a collection of radial profiles at even angular separations
+
+// These functions are used to calculate the stats in a rectangle at arbitrary orientation.
+// XXX Move these elsewhere (psLib?)
+float psphotMeanSectorValue (psImage *image, float x, float y, float dL, float dW, float theta);
+psVector *psphotBoxValues (psImage *image, float x0, float y0, float dL, float dW, float theta);
+psVector *psphotLineValues (psImage *image, double x1, double y1, double x2, double y2, int dW);
+psVector *psphotLineValuesBresen (psImage *image, int X1, int Y1, int X2, int Y2, int dW, int swapcoords);
+
+bool psphotRadialProfilesByAngles (pmSource *source, int Nsec, float Rmax) {
+
+    // we want to have an even number of sectors so we can do 180 deg symmetrizing
+    Nsec = (Nsec % 2) ? Nsec + 1 : Nsec;
+    float dtheta = 2.0*M_PI / Nsec;
+
+    pmSourceRadialProfile *profile = source->extpars->profile;
+    psFree(profile->radii);
+    psFree(profile->fluxes);
+    psFree(profile->theta);
+
+    profile->radii = psArrayAllocEmpty(Nsec);
+    profile->fluxes = psArrayAllocEmpty(Nsec);
+    profile->theta = psVectorAllocEmpty(Nsec, PS_TYPE_F32);
+
+
+    for (int i = 0; i < Nsec; i++) {
+
+	float theta = i*dtheta;
+
+	psVector *radius = psVectorAllocEmpty(Rmax, PS_TYPE_F32);
+	psVector *flux   = psVectorAllocEmpty(Rmax, PS_TYPE_F32);
+
+	// Start at Xo,Yo and find the x,y locations for r_i, theta where r_i initially
+	// increments by 1 pixel.  At large radii (r*dtheta > 2) use stats in a box rather than
+	// sub-pixel interpolation
+
+	int dR = 1.0;
+	for (float r = 0; r < Rmax; r += dR) {
+
+	    float Xo = source->peak->xf;
+	    float Yo = source->peak->yf;
+
+	    // Xo,Yo are referenced to pixels with bounds i+0.0, i+1.0
+	    float x = r * cos (theta) + Xo;
+	    float y = r * sin (theta) + Yo;
+	    dR = 2*(int)(0.5*r*sin(dtheta)) + 1;
+
+	    if (x < 0) goto badvalue;
+	    if (y < 0) goto badvalue;
+	    if (x >= source->pixels->parent->numCols) goto badvalue;
+	    if (y >= source->pixels->parent->numRows) goto badvalue;
+
+	    float value = NAN;
+	    if (dR < 2) {
+		// value is NAN if we run off the image
+		// 0.5 PIX: this function takes pixel coords; source peak is in pixel coords
+		value = psImageInterpolatePixelBilinear(x, y, source->pixels);
+	    } else {
+		// 0.5 PIX: this function takes pixel coords; source peak is in pixel coords
+		value = psphotMeanSectorValue(source->pixels, x, y, dR, dR, theta);
+	    }
+
+	    // keep the all values (even NAN) so all vectors are matched in length
+	    psVectorAppend (radius, r);
+	    psVectorAppend (flux, value);
+	    continue;
+	    
+	badvalue:
+	    psVectorAppend (radius, r);
+	    psVectorAppend (flux, NAN);
+	}
+
+	psArrayAdd (profile->radii, 100, radius);
+	psArrayAdd (profile->fluxes, 100, flux);
+	psVectorAppend (profile->theta, theta);
+
+	// psphotPetrosianVisualProfileByAngle (radius, flux);
+
+	psFree(radius);
+	psFree(flux);
+    }
+
+    for (int i = 0; i < Nsec / 2; i++) {
+
+	psVector *r1 = profile->radii->data[i];
+	psVector *r2 = profile->radii->data[i+Nsec/2];
+
+	psVector *f1 = profile->fluxes->data[i];
+	psVector *f2 = profile->fluxes->data[i+Nsec/2];
+
+	psAssert (r1->n == r2->n, "mis-matched vectors");
+	psAssert (f1->n == f2->n, "mis-matched vectors");
+
+	// we have a pair of vectors i, i+Nsec/2; replace them with the finite minimum of the pair
+	for (int j = 0; j < r1->n; j++) {
+	    
+	    float flux;
+
+	    if (!isfinite(f1->data.F32[j]) && !isfinite(f2->data.F32[j])) {
+		flux = NAN;
+		goto setflux;
+	    }
+
+	    if (!isfinite(f1->data.F32[j])) {
+		flux = f2->data.F32[j];
+		goto setflux;
+	    }
+	    if (!isfinite(f2->data.F32[j])) {
+		flux = f1->data.F32[j];
+		goto setflux;
+	    }
+
+	    flux = PS_MIN(f1->data.F32[j], f2->data.F32[j]);
+
+	setflux:
+	    f1->data.F32[j] = flux;
+	    f2->data.F32[j] = flux;
+	}
+    }    
+    return true;
+}
+
+float psphotMeanSectorValue (psImage *image, float x, float y, float dL, float dW, float theta) {
+
+    psVector *values = psphotBoxValues (image, x, y, dL, dW, theta);
+    if (!values) goto escape;
+    if (!values->n) goto escape;
+    
+    psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
+    psVectorStats (stats, values, NULL, NULL, 0);
+
+    float value = stats->sampleMedian;
+
+    psFree (stats);
+    psFree (values);
+    
+    return value;
+
+escape:
+    psFree(values);
+    return NAN;    
+}
+
+psVector *psphotBoxValues (psImage *image, float x0, float y0, float dL, float dW, float theta) {
+
+    // extract pixels from a series of lines (from -0.5*dW to +0.5*dW) of length dL, 
+    // centered on x0, y0 in parent pixel coordinates (not pixel indicies)
+
+    float xs = x0 - image->col0 - 0.5*dL*cos(theta);
+    float ys = y0 - image->row0 - 0.5*dL*sin(theta);
+
+    float xe = xs + 0.5*dL*cos(theta);
+    float ye = ys + 0.5*dL*sin(theta);
+
+    psVector *values = psphotLineValues (image, xs, ys, xe, ye, (int) dW);
+    return values;
+}
+
+/**
+ * identify the quadrant and draw the correct line
+ */
+psVector *psphotLineValues (psImage *image, double x1, double y1, double x2, double y2, int dW) {
+
+  int FlipDirect, FlipCoords;
+  int X1, Y1, X2, Y2, dX, dY;
+
+  /* rather than draw the line from float positions, we find the closest
+     integer end-points and draw the line between those pixels */
+
+  X1 = ROUND(x1);
+  Y1 = ROUND(y1);
+  X2 = ROUND(x2);
+  Y2 = ROUND(y2);
+
+  dX = X2 - X1;
+  dY = Y2 - Y1;
+
+  FlipCoords = (abs(dX) < abs(dY));
+  FlipDirect = FlipCoords ? (y1 > y2) : (x1 > x2);
+
+  psVector *values = NULL;
+  if (!FlipDirect && !FlipCoords) values = psphotLineValuesBresen (image, X1, Y1, X2, Y2, dW, FALSE);
+  if ( FlipDirect && !FlipCoords) values = psphotLineValuesBresen (image, X2, Y2, X1, Y1, dW, FALSE);
+  if (!FlipDirect &&  FlipCoords) values = psphotLineValuesBresen (image, Y1, X1, Y2, X2, dW, TRUE);
+  if ( FlipDirect &&  FlipCoords) values = psphotLineValuesBresen (image, Y2, X2, Y1, X1, dW, TRUE);
+
+  return values;
+}
+
+/**
+ * use the Bresenham line drawing technique
+ * integer-only Bresenham line-draw version which is fast
+ */
+psVector *psphotLineValuesBresen (psImage *image, int X1, int Y1, int X2, int Y2, int dW, int swapcoords) {
+
+    int X, Y, dX, dY;
+    int e, e2;
+
+    psVector *values = psVectorAllocEmpty(100, PS_TYPE_F32);
+
+    dX = X2 - X1;
+    dY = Y2 - Y1;
+
+    Y = Y1;
+    e = 0;
+    for (X = X1; X <= X2; X++) {
+        if (X > 0) {
+            if (swapcoords) {
+                if (X >= image->numRows) continue;
+                for (int y = Y - dW; y <= Y + dW; y++) {
+                    if (y < 0) continue;
+                    if (y >= image->numCols) continue;
+                    psVectorAppend(values, image->data.F32[X][y]);
+                }
+            } else {
+                if (X >= image->numCols) continue;
+                for (int y = Y - dW; y <= Y + dW; y++) {
+                    if (y < 0) continue;
+                    if (y >= image->numRows) continue;
+                    psVectorAppend(values, image->data.F32[y][X]);
+                }
+            }
+        }
+        e += dY;
+        e2 = 2 * e;
+        if (e2 > dX) {
+            Y++;
+            e -= dX;
+        }
+        if (e2 < -dX) {
+            Y--;
+            e += dX;
+        }
+    }
+    return values;
+}
+
Index: branches/eam_branches/20090820/psphot/src/psphotRadiiFromProfiles.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotRadiiFromProfiles.c	(revision 25766)
+++ branches/eam_branches/20090820/psphot/src/psphotRadiiFromProfiles.c	(revision 25766)
@@ -0,0 +1,153 @@
+# include "psphotInternal.h"
+
+// Given the Radial Profiles (radii, fluxes) determine the radius for each profile at the desired isophote
+
+bool psphotRadiiFromProfiles (pmSource *source, float fluxMin, float fluxMax) {
+
+    pmSourceRadialProfile *profile = source->extpars->profile;
+
+    psFree(profile->isophotalRadii);
+    profile->isophotalRadii = psVectorAlloc(profile->theta->n, PS_TYPE_F32);
+
+    for (int i = 0; i < profile->theta->n; i++) {
+	psVector *radii = profile->radii->data[i];
+	psVector *fluxes = profile->fluxes->data[i];
+	float radius = psphotRadiusFromProfile (source, radii, fluxes, fluxMin, fluxMax);
+
+	// psphotPetrosianVisualProfileByAngle (radii, fluxes, radius);
+
+	// warn on NAN?
+	profile->isophotalRadii->data.F32[i] = radius;
+    }
+    return true;
+}
+
+float psphotRadiusFromProfile (pmSource *source, psVector *radius, psVector *flux, float fluxMin, float fluxMax) {
+
+    // 'flux' is a noisy sample of the galaxy radial profile at points 'radius'
+    // rebin flux into samples defined by the isophote Fo = 0.5*(fluxMax + fluxMin).  the noisy
+    // sample is cleaned by rebinning to a well-matched radial binning
+
+    // base selections on fluxes defined by the flux range dF
+    float fluxRange = fluxMax - fluxMin;
+
+    // examine data in the two ranges Fm - Fo and Fo - Fp to define the bin size
+    // XXX reconsider the fractional isophote value
+    float Fm = fluxMin + 0.10*fluxRange;
+    float Fo = fluxMin + 0.25*fluxRange;
+    float Fp = fluxMin + 0.50*fluxRange;
+    int Rbin = 1;
+      
+    // find the median radius of the points in the flux range Fm - Fp:
+    { 
+	// storage vector for stats
+	psVector *values = psVectorAllocEmpty (flux->n, PS_TYPE_F32);
+	psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
+
+	for (int i = 0; i < flux->n; i++) {
+	    if (!isfinite(flux->data.F32[i])) continue;
+	    if (flux->data.F32[i] < Fm) continue;
+	    if (flux->data.F32[i] > Fp) continue;
+	    
+	    psVectorAppend (values, radius->data.F32[i]);
+	}
+	if (values->n > 1) {
+	    psVectorStats (stats, values, NULL, NULL, 0);
+
+	    // if we have a valid range, rebin with bin size 1/2 of median radius
+	    if (isfinite(stats->sampleMedian)) {
+		Rbin = MAX(1, 0.5*stats->sampleMedian);
+	    }
+	}
+	psFree (values);
+	psFree (stats);
+    }
+    Rbin = 3;
+
+    psVector *fluxBinned = NULL;
+    psVector *radiusBinned = NULL;
+
+    // do not bother rebinning if the bin size is only 2 or less
+    if (Rbin <= 2) {
+	fluxBinned = psMemIncrRefCounter (flux);
+	radiusBinned = psMemIncrRefCounter (radius);
+    } else {
+	// storage vector for stats
+	psVector *values = psVectorAllocEmpty (flux->n, PS_TYPE_F32);
+	psStats *stats = psStatsAlloc(PS_STAT_SAMPLE_MEDIAN);
+  
+	// rebinned vectors
+	fluxBinned = psVectorAllocEmpty (flux->n, PS_TYPE_F32);
+	radiusBinned = psVectorAllocEmpty (flux->n, PS_TYPE_F32);
+
+	// sort the flux by the radius
+	pmSourceRadialProfileSortPair (radius, flux);
+
+	int nOut = 0;
+	radiusBinned->data.F32[nOut] = (nOut + 0.5)*Rbin;
+	float Rmin = radiusBinned->data.F32[nOut] - 0.5*Rbin;
+	float Rmax = radiusBinned->data.F32[nOut] + 0.5*Rbin;
+
+	for (int i = 0; i < flux->n; i++) {
+	    if (radius->data.F32[i] < Rmin) {
+		// XXX not sure how we can hit this, if there is full coverage of radiusBinned
+		continue;
+	    }
+	    if (radius->data.F32[i] > Rmax) {
+		// calculate the value for the nOut bin
+		// XXX need to fix this as well psStats (stats, values);
+		float value;
+		if (values->n > 0) {
+		    psVectorStats (stats, values, NULL, NULL, 0);
+		    value = stats->sampleMedian;
+		} else {
+		    value = NAN;
+		}
+		fluxBinned->data.F32[nOut] = value;
+		nOut ++;
+		radiusBinned->data.F32[nOut] = (nOut + 0.5)*Rbin;
+		Rmin = radiusBinned->data.F32[nOut] - 0.5*Rbin;
+		Rmax = radiusBinned->data.F32[nOut] + 0.5*Rbin;
+		values->n = 0;
+		psStatsInit(stats);
+	    }
+	    if (!isfinite(flux->data.F32[i])) continue;
+	    psVectorAppend (values, flux->data.F32[i]);
+	}
+	fluxBinned->n = nOut;
+	radiusBinned->n = nOut;
+	psFree (values);
+	psFree(stats);
+    }
+
+    float Ro = NAN;
+    bool above = true;
+    for (int i = 0; i < fluxBinned->n; i++) {
+
+	if (!isfinite(fluxBinned->data.F32[i])) continue;
+
+	// find the largest radius that matches the flux transition
+	if (above && (fluxBinned->data.F32[i] < Fo)) {
+	    // XXX is there a macro in psLib that does this interpolation?
+	    if (i == 0) { 
+		psTrace ("psphot", 4, "bogus radial profile for source at %f, %f, skipping", source->peak->xf, source->peak->yf);
+		psFree (fluxBinned);
+		psFree (radiusBinned);
+		return NAN;
+	    } 
+	    Ro = radiusBinned->data.F32[i-1] + (radiusBinned->data.F32[i] - radiusBinned->data.F32[i-1]) * (Fo - fluxBinned->data.F32[i-1]) / (fluxBinned->data.F32[i] - fluxBinned->data.F32[i-1]);
+	    above = FALSE;
+	}
+  
+	if (!above && (fluxBinned->data.F32[i] >= Fo)) {
+	    above = TRUE;
+	}
+    }
+
+    // show the results
+    // psphotPetrosianVisualProfileRadii (radius, flux, radiusBinned, fluxBinned, Ro);
+
+    psFree(fluxBinned);
+    psFree(radiusBinned);
+    return Ro;
+}
Index: branches/eam_branches/20090820/psphot/src/psphotRadiusChecks.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotRadiusChecks.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotRadiusChecks.c	(revision 25766)
@@ -7,4 +7,7 @@
 					// and a per-object radius is calculated)
 
+static float PSF_APERTURE = 0;	// radius to use in PSF aperture mags
+
+
 bool psphotInitRadiusPSF(const psMetadata *recipe, const pmModelType type) {
 
@@ -13,5 +16,6 @@
     PSF_FIT_NSIGMA  = psMetadataLookupF32(&status, recipe, "PSF_FIT_NSIGMA");
     PSF_FIT_PADDING = psMetadataLookupF32(&status, recipe, "PSF_FIT_PADDING");
-    PSF_FIT_RADIUS =  psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
+    PSF_FIT_RADIUS  =  psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
+    PSF_APERTURE    =  psMetadataLookupF32(&status, recipe, "PSF_APERTURE");
 
     return true;
@@ -34,17 +38,21 @@
 	    radiusFit = model->modelRadius(model->params, 1.0);
 	}
+	model->fitRadius = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
+    } else {
+	model->fitRadius = radiusFit;
     }
-    model->radiusFit = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
-
-    if (isnan(model->radiusFit)) psAbort("error in radius");
+    if (isnan(model->fitRadius)) psAbort("error in radius");
 	
     if (source->mode & PM_SOURCE_MODE_SATSTAR) {
-	model->radiusFit *= 2;
+	model->fitRadius *= 2;
     }
 
-    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
+    // radius used to measure aperture photometry
+    source->apRadius = PSF_APERTURE;
+
+    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
 
     // set the mask to flag the excluded pixels
-    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
+    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
     return status;
 }
@@ -58,15 +66,31 @@
 
     // set the fit radius based on the object flux limit and the model
-    model->radiusFit = (RADIUS_TYPE) (model->modelRadius (model->params, PSF_FIT_NSIGMA*moments->dSky) + dR + PSF_FIT_PADDING);
-    if (isnan(model->radiusFit)) psAbort("error in radius");
-	
+    float radiusFit = PSF_FIT_RADIUS;
+    if (radiusFit <= 0) {		// use fixed radius
+	if (moments == NULL) {
+	    radiusFit = model->modelRadius(model->params, PSF_FIT_NSIGMA*moments->dSky);
+	} else {
+	    radiusFit = model->modelRadius(model->params, 1.0);
+	}
+	model->fitRadius = (RADIUS_TYPE)(radiusFit + PSF_FIT_PADDING);
+    } else {
+	model->fitRadius = radiusFit;
+    }
+    if (isnan(model->fitRadius)) psAbort("error in radius");
+
+    // above sets a radius for a single star, bump by blend separation
+    model->fitRadius += dR;
+
     if (source->mode &  PM_SOURCE_MODE_SATSTAR) {
-	model->radiusFit *= 2;
+	model->fitRadius *= 2;
     }
 
-    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
+    // radius used to measure aperture photometry
+    source->apRadius = PSF_APERTURE;
+
+    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
 
     // set the mask to flag the excluded pixels
-    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
+    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
     return status;
 }
@@ -74,4 +98,5 @@
 static float EXT_FIT_NSIGMA;
 static float EXT_FIT_PADDING;
+static float EXT_FIT_MAX_RADIUS;
 
 bool psphotInitRadiusEXT (psMetadata *recipe, pmModelType type) {
@@ -79,6 +104,7 @@
     bool status;
 
-    EXT_FIT_NSIGMA   = psMetadataLookupF32 (&status, recipe, "EXT_FIT_NSIGMA");
-    EXT_FIT_PADDING  = psMetadataLookupF32 (&status, recipe, "EXT_FIT_PADDING");
+    EXT_FIT_NSIGMA     = psMetadataLookupF32 (&status, recipe, "EXT_FIT_NSIGMA");
+    EXT_FIT_PADDING    = psMetadataLookupF32 (&status, recipe, "EXT_FIT_PADDING");
+    EXT_FIT_MAX_RADIUS = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_RADIUS");
 
     return true;
@@ -86,5 +112,52 @@
 
 // call this function whenever you (re)-define the EXT model
+float psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal) {
+
+    psAssert (source, "source not defined??");
+    psAssert (source->peak, "peak not defined??");
+
+    pmPeak *peak = source->peak;
+
+    // set the radius based on the footprint:
+    if (!peak->footprint) goto escape;
+    pmFootprint *footprint = peak->footprint;
+    if (!footprint->spans) goto escape;
+    if (footprint->spans->n < 1) goto escape;
+
+    // find the max radius
+    float radius = 0.0;
+    for (int j = 0; j < footprint->spans->n; j++) {
+	pmSpan *span = footprint->spans->data[j];
+
+	float dY  = span->y  - peak->yf;
+	float dX0 = span->x0 - peak->xf;
+	float dX1 = span->x1 - peak->xf;
+
+	radius = PS_MAX (radius, hypot(dY, dX0));
+	radius = PS_MAX (radius, hypot(dY, dX1));
+    }
+
+    radius += EXT_FIT_PADDING;
+    if (isnan(radius)) psAbort("error in radius");
+
+    radius = PS_MIN (radius, EXT_FIT_MAX_RADIUS);
+
+    // redefine the pixels if needed
+    pmSourceRedefinePixels (source, readout, peak->xf, peak->yf, radius);
+
+    // set the mask to flag the excluded pixels
+    psImageKeepCircle (source->maskObj, peak->xf, peak->yf, radius, "OR", markVal);
+    return radius;
+
+escape:
+    return NAN;
+    // bool result = psphotCheckRadiusEXT (readout, source, model, markVal);
+    // return result;
+}
+
+// alternative EXT radius based on model guess (for use without footprints)
 bool psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal) {
+
+    psAbort ("do not use this function");
 
     psF32 *PAR = model->params->data.F32;
@@ -96,12 +169,12 @@
     float rawRadius = model->modelRadius (model->params, EXT_FIT_NSIGMA*moments->dSky);
 
-    model->radiusFit = rawRadius + EXT_FIT_PADDING;
-    if (isnan(model->radiusFit)) psAbort("error in radius");
+    model->fitRadius = rawRadius + EXT_FIT_PADDING;
+    if (isnan(model->fitRadius)) psAbort("error in radius");
 
     // redefine the pixels if needed
-    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit);
+    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
 
     // set the mask to flag the excluded pixels
-    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
+    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius, "OR", markVal);
     return status;
 }
Index: branches/eam_branches/20090820/psphot/src/psphotReadout.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotReadout.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotReadout.c	(revision 25766)
@@ -18,4 +18,6 @@
     psTimerStart ("psphotReadout");
 
+    pmModelClassSetLimits(PM_MODEL_LIMITS_LAX);
+
     // select the current recipe
     psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
@@ -61,5 +63,5 @@
     // display the backsub and backgnd images
     psphotVisualShowBackground (config, view, readout);
-    
+
     // run a single-model test if desired (exits from here if test is run)
     psphotModelTest (config, view, recipe);
@@ -79,5 +81,5 @@
 
     // construct sources and measure basic stats
-    psArray *sources = psphotSourceStats (config, readout, detections);
+    psArray *sources = psphotSourceStats (config, readout, detections, true);
     if (!sources) return false;
     if (!strcasecmp (breakPt, "PEAKS")) {
@@ -124,5 +126,4 @@
         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     }
-
     psphotVisualShowPSFModel (readout, psf);
 
@@ -130,11 +131,8 @@
     psphotLoadExtSources (config, view, sources);
 
-    // construct an initial model for each object
+    // construct an initial model for each object, set the radius to fitRadius, set circular fit mask
     psphotGuessModels (config, readout, sources, psf);
 
-    // XXX test output of models
-    // psphotTestSourceOutput (readout, sources, recipe, psf);
-
-    // linear PSF fit to source peaks
+    // linear PSF fit to source peaks, subtract the models from the image (in PSF mask)
     psphotFitSourcesLinear (readout, sources, recipe, psf, FALSE);
 
@@ -142,13 +140,14 @@
     // psphotGuessModels or fitted until psphotFitSourcesLinear.
     psphotVisualShowPSFStars (recipe, psf, sources);
-    psphotVisualShowSatStars (recipe, psf, sources);
 
     // identify CRs and extended sources
-    psphotSourceSize (config, readout, sources, recipe, 0);
+    psphotSourceSize (config, readout, sources, recipe, psf, 0);
     if (!strcasecmp (breakPt, "ENSEMBLE")) {
         goto finish;
     }
+    psphotVisualShowSatStars (recipe, psf, sources);
 
     // non-linear PSF and EXT fit to brighter sources
+    // replace model flux, adjust mask as needed, fit, subtract the models (full stamp)
     psphotBlendFit (config, readout, sources, psf);
 
@@ -156,5 +155,5 @@
     psphotReplaceAllSources (sources, recipe);
 
-    // linear fit to include all sources
+    // linear fit to include all sources (subtract again)
     psphotFitSourcesLinear (readout, sources, recipe, psf, TRUE);
 
@@ -163,10 +162,5 @@
         goto pass1finish;
     }
-
-    // XXX for the moment, drop the re-calc of the background (prove this works)
-    // replace background in residual image
-    // psphotSkyReplace (config, view);
-    // re-measure background model (median, smoothed image)
-    // psphotImageMedian (config, view);
+    // NOTE: possibly re-measure background model here with objects subtracted
 
     // add noise for subtracted objects
@@ -180,5 +174,5 @@
 
     // define new sources based on only the new peaks
-    psArray *newSources = psphotSourceStats (config, readout, detections);
+    psArray *newSources = psphotSourceStats (config, readout, detections, false);
 
     // set source type
@@ -188,5 +182,5 @@
     }
 
-    // create full input models
+    // create full input models, set the radius to fitRadius, set circular fit mask
     psphotGuessModels (config, readout, newSources, psf);
 
@@ -204,5 +198,5 @@
 
     // measure source size for the remaining sources
-    psphotSourceSize (config, readout, sources, recipe, 0);
+    psphotSourceSize (config, readout, sources, recipe, psf, 0);
 
     psphotExtendedSourceAnalysis (readout, sources, recipe);
@@ -224,4 +218,9 @@
     psphotMagnitudes(config, readout, view, sources, psf);
 
+    if (!psphotEfficiency(config, readout, view, psf, recipe, sources)) {
+        psErrorStackPrint(stderr, "Unable to determine detection efficiencies from fake sources");
+        psErrorClear();
+    }
+
     // replace failed sources?
     // psphotReplaceUnfitSources (sources);
Index: branches/eam_branches/20090820/psphot/src/psphotReadoutFindPSF.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotReadoutFindPSF.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotReadoutFindPSF.c	(revision 25766)
@@ -41,5 +41,5 @@
 
     // construct sources and measure basic stats (moments, local sky)
-    psArray *sources = psphotSourceStats(config, readout, detections);
+    psArray *sources = psphotSourceStats(config, readout, detections, true);
     if (!sources) return false;
 
Index: branches/eam_branches/20090820/psphot/src/psphotReadoutKnownSources.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotReadoutKnownSources.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotReadoutKnownSources.c	(revision 25766)
@@ -41,5 +41,5 @@
 
     // construct sources and measure basic stats
-    psArray *sources = psphotSourceStats (config, readout, detections);
+    psArray *sources = psphotSourceStats (config, readout, detections, true);
     if (!sources) return false;
 
Index: branches/eam_branches/20090820/psphot/src/psphotReadoutMinimal.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotReadoutMinimal.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotReadoutMinimal.c	(revision 25766)
@@ -14,4 +14,6 @@
     // jointly by the multiple threads, not the total time used by all threads.
     psTimerStart ("psphotReadout");
+
+    pmModelClassSetLimits(PM_MODEL_LIMITS_LAX);
 
     // select the current recipe
@@ -54,5 +56,5 @@
 
     // construct sources and measure basic stats
-    psArray *sources = psphotSourceStats (config, readout, detections);
+    psArray *sources = psphotSourceStats (config, readout, detections, true);
     if (!sources) return false;
 
@@ -97,4 +99,9 @@
     psphotMagnitudes(config, readout, view, sources, psf);
 
+    if (!psphotEfficiency(config, readout, view, psf, recipe, sources)) {
+        psErrorStackPrint(stderr, "Unable to determine detection efficiencies from fake sources");
+        psErrorClear();
+    }
+
     // drop the references to the image pixels held by each source
     psphotSourceFreePixels (sources);
Index: branches/eam_branches/20090820/psphot/src/psphotReplaceUnfit.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotReplaceUnfit.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotReplaceUnfit.c	(revision 25766)
@@ -17,5 +17,4 @@
     replace:
         pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
-        source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
     }
     psLogMsg ("psphot.replace", 3, "replace unfitted models: %f sec (%ld objects)\n", psTimerMark ("psphot.replace"), sources->n);
@@ -41,5 +40,4 @@
 
       pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
-      source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
     }
     psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.replace"));
@@ -47,5 +45,5 @@
 }
 
-bool psphotRemoveAllSources (psArray *sources, psMetadata *recipe) {
+bool psphotRemoveAllSources (const psArray *sources, const psMetadata *recipe) {
 
     bool status;
@@ -64,6 +62,5 @@
       if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) continue;
 
-      pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
-      source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
+      pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
     }
     psLogMsg ("psphot.replace", PS_LOG_INFO, "replaced models for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.replace"));
@@ -71,4 +68,5 @@
 }
 
+# if (0)
 // add source, if the source has been subtracted; do not modify state
 bool psphotAddWithTest (pmSource *source, bool useState, psImageMaskType maskVal) {
@@ -108,2 +106,3 @@
     return true;
 }
+# endif
Index: branches/eam_branches/20090820/psphot/src/psphotRoughClass.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotRoughClass.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotRoughClass.c	(revision 25766)
@@ -26,11 +26,12 @@
 	for (int iy = 0; iy < NY; iy ++) {
 
-	    psRegion region = psRegionSet (ix*dX, (ix + 1)*dX, iy*dY, (iy + 1)*dY);
-	    if (!psphotRoughClassRegion (nRegion, &region, sources, recipe, havePSF)) {
+	    psRegion *region = psRegionAlloc (ix*dX, (ix + 1)*dX, iy*dY, (iy + 1)*dY);
+	    if (!psphotRoughClassRegion (nRegion, region, sources, recipe, havePSF)) {
 		psLogMsg ("psphot", 4, "Failed to determine rough classification for region %f,%f - %f,%f\n", 
-			 region.x0, region.y0, region.x1, region.y1);
+			 region->x0, region->y0, region->x1, region->y1);
+		psFree (region);
 		continue;
 	    }
-	    
+	    psFree (region);
 	    nRegion ++;
 	}
@@ -45,5 +46,5 @@
     psphotVisualPlotMoments (recipe, sources);
     psphotVisualShowRoughClass (sources);
-    psphotVisualShowFlags (sources);
+    // XXX better visualization: psphotVisualShowFlags (sources);
 
     return true;
@@ -63,11 +64,14 @@
     psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
     if (!regionMD) {
+	// allocate the region metadata folder and add this region to it.
 	regionMD = psMetadataAlloc();
 	psMetadataAddMetadata (recipe, PS_LIST_TAIL, regionName, PS_META_REPLACE, "psf clump region", regionMD);
 	psFree (regionMD);
     }
+    psMetadataAddPtr (regionMD, PS_LIST_TAIL, "REGION", PS_DATA_REGION | PS_META_REPLACE, "psf clump region", region);
 
     if (!havePSF) {
 	// determine the PSF parameters from the source moment values
+	// XXX why not save the psfClump as a PTR?
 	psfClump = pmSourcePSFClump (region, sources, recipe);
 	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
Index: branches/eam_branches/20090820/psphot/src/psphotSetThreads.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotSetThreads.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotSetThreads.c	(revision 25766)
@@ -10,5 +10,5 @@
     psFree(task);
 
-    task = psThreadTaskAlloc("PSPHOT_MAGNITUDES", 8);
+    task = psThreadTaskAlloc("PSPHOT_MAGNITUDES", 9);
     task->function = &psphotMagnitudes_Threaded;
     psThreadTaskAdd(task);
@@ -20,5 +20,5 @@
     psFree(task);
 
-    task = psThreadTaskAlloc("PSPHOT_APRESID_MAGS", 6);
+    task = psThreadTaskAlloc("PSPHOT_APRESID_MAGS", 7);
     task->function = &psphotApResidMags_Threaded;
     psThreadTaskAdd(task);
Index: branches/eam_branches/20090820/psphot/src/psphotSignificanceImage.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotSignificanceImage.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotSignificanceImage.c	(revision 25766)
@@ -22,20 +22,23 @@
     }
 
-    bool status_x, status_y;
-    float FWHM_X = psMetadataLookupF32 (&status_x, recipe, "FWHM_X");
-    float FWHM_Y = psMetadataLookupF32 (&status_y, recipe, "FWHM_Y");
-    if (status_x && status_y) {
-      // if we know the FHWM, use that to set the smoothing kernel (XXX allow an optional override?)
-      SIGMA_SMTH  = 0.5*(FWHM_X + FWHM_Y) / (2.0*sqrt(2.0*log(2.0)));
-      NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
-      guess = false;
+    bool statusMajor, statusMinor;
+    float fwhmMajor = psMetadataLookupF32(&statusMajor, recipe, "FWHM_MAJ");
+    float fwhmMinor = psMetadataLookupF32(&statusMinor, recipe, "FWHM_MIN");
+    if (statusMajor && statusMinor) {
+        // if we know the FHWM, use that to set the smoothing kernel (XXX allow an optional override?)
+        if (!isfinite(fwhmMajor) || !isfinite(fwhmMinor) || fwhmMajor == 0.0 || fwhmMinor == 0.0) {
+            psWarning("fwhmMajor (%f) or fwhmMinor (%f) is bad!", fwhmMajor, fwhmMinor);
+        }
+        SIGMA_SMTH  = 0.5*(fwhmMajor + fwhmMinor) / (2.0*sqrt(2.0*log(2.0)));
+        NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
+        guess = false;
     } else {
-      // if we do not know the FWHM, use the guess smoothing kernel supplied.
-      // it is a configuration error if these are not supplied
-      SIGMA_SMTH  = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_SIGMA");
-      PS_ASSERT (status, NULL);
-      NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
-      PS_ASSERT (status, NULL);
-      guess = true;
+        // if we do not know the FWHM, use the guess smoothing kernel supplied.
+        // it is a configuration error if these are not supplied
+        SIGMA_SMTH  = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_SIGMA");
+        PS_ASSERT (status, NULL);
+        NSIGMA_SMTH = psMetadataLookupF32 (&status, recipe, "PEAKS_SMOOTH_NSIGMA");
+        PS_ASSERT (status, NULL);
+        guess = true;
     }
     // record the actual smoothing sigma
Index: branches/eam_branches/20090820/psphot/src/psphotSourceFits.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotSourceFits.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotSourceFits.c	(revision 25766)
@@ -90,6 +90,11 @@
     psphotCheckRadiusPSFBlend (readout, source, PSF, markVal, dR);
 
-    // fit PSF model (set/unset the pixel mask)
+    // fit PSF model
     pmSourceFitSet (source, modelSet, PM_SOURCE_FIT_PSF, maskVal);
+
+    // clear the circular mask
+    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); 
+
+    if (!isfinite(PSF->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
 
     // correct model chisq for flux trend
@@ -101,4 +106,6 @@
         pmSource *blend = sourceSet->data[i];
         pmModel *model  = modelSet->data[i];
+
+	if (!isfinite(model->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
 
         // correct model chisq for flux trend
@@ -120,5 +127,4 @@
         pmSourceCacheModel (blend, maskVal);
         pmSourceSub (blend, PM_MODEL_OP_FULL, maskVal);
-        blend->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
         blend->mode |=  PM_SOURCE_MODE_BLEND_FIT;
     }
@@ -144,5 +150,4 @@
     pmSourceCacheModel (source, maskVal);
     pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-    source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
     source->mode |=  PM_SOURCE_MODE_BLEND_FIT;
     return true;
@@ -167,4 +172,9 @@
     // fit PSF model (set/unset the pixel mask)
     pmSourceFitModel (source, PSF, PM_SOURCE_FIT_PSF, maskVal);
+
+    if (!isfinite(PSF->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
+
+    // clear the circular mask
+    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); 
 
     // correct model chisq for flux trend
@@ -186,10 +196,7 @@
     pmSourceCacheModel (source, maskVal);
     pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-    source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
-    return true;
-}
-
-static float EXT_MIN_SN;
-static float EXT_MOMENTS_RAD;
+    return true;
+}
+
 static pmModelType modelTypeEXT;
 
@@ -197,8 +204,4 @@
 
     bool status;
-
-    // extended source model parameters
-    EXT_MIN_SN       = psMetadataLookupF32 (&status, recipe, "EXT_MIN_SN");
-    EXT_MOMENTS_RAD  = psMetadataLookupF32 (&status, recipe, "EXT_MOMENTS_RADIUS");
 
     // extended source model descriptions
@@ -221,9 +224,13 @@
     if (source->type == PM_SOURCE_TYPE_DEFECT) return false;
     if (source->type == PM_SOURCE_TYPE_SATURATED) return false;
-    if (source->peak->SN < EXT_MIN_SN) return false;
-
+
+    // set the radius based on the footprint (also sets the mask pixels)
+    float radius = psphotSetRadiusEXT (readout, source, markVal);
+
+    // XXX note that this changes the source moments that are published...
     // recalculate the source moments using the larger extended-source moments radius
     // at this stage, skip Gaussian windowing, and do not clip pixels by S/N
-    if (!pmSourceMoments (source, EXT_MOMENTS_RAD, 0.0, 0.0)) return false;
+    // this uses the footprint to judge both radius and aperture?
+    if (!pmSourceMoments (source, radius, 0.0, 0.0)) return false;
 
     psTrace ("psphot", 5, "trying blob...\n");
@@ -237,4 +244,6 @@
     // XXX need to handle failures better here
     pmModel *EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal, markVal);
+    if (!isfinite(EXT->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
+
     okEXT = psphotEvalEXT (tmpSrc, EXT);
     chiEXT = EXT ? EXT->chisq / EXT->nDOF : NAN;
@@ -246,8 +255,12 @@
     // XXX should I keep / save the flags set in the eval functions?
 
+    // clear the circular mask
+    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); 
+
     // correct first model chisqs for flux trend
     chiDBL = NAN;
     ONE = DBL->data[0];
     if (ONE) {
+	if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
       chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
       ONE->chisqNorm = ONE->chisq / chiTrend;
@@ -258,4 +271,5 @@
     ONE = DBL->data[1];
     if (ONE) {
+	if (!isfinite(ONE->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
       chiTrend = psPolynomial1DEval (psf->ChiTrend, ONE->params->data.F32[1]);
       ONE->chisqNorm = ONE->chisq / chiTrend;
@@ -277,4 +291,5 @@
 
     // both models failed; reject them both
+    // XXX -- change type flags to psf in this case and keep original moments?
     psFree (EXT);
     psFree (DBL);
@@ -287,4 +302,5 @@
     // save new model
     source->modelEXT = EXT;
+    source->modelEXT->fitRadius = radius;
     source->type = PM_SOURCE_TYPE_EXTENDED;
     source->mode |= PM_SOURCE_MODE_EXTMODEL;
@@ -293,6 +309,15 @@
     pmSourceCacheModel (source, maskVal);
     pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-    source->tmpFlags |=  PM_SOURCE_TMPF_SUBTRACTED;
+
+# if (PS_TRACE_ON)   
     psTrace ("psphot", 5, "blob as EXT: %f %f\n", EXT->params->data.F32[PM_PAR_XPOS], EXT->params->data.F32[PM_PAR_YPOS]);
+    if (psTraceGetLevel("psphot") >= 6) {
+	psLogMsg ("psphot", 1, "source 2:\n");
+	for (int i = 0; i < source->modelEXT->params->n; i++) {
+	    psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, source->modelEXT->params->data.F32[i], source->modelEXT->dparams->data.F32[i]);
+	}
+    }
+# endif
+
     return true;
 
@@ -304,11 +329,11 @@
     psFree (source->modelPSF);
     source->modelPSF = psMemIncrRefCounter (DBL->data[0]);
-    source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
     source->mode     |= PM_SOURCE_MODE_PAIR;
+    source->modelPSF->fitRadius = radius;
 
     // copy most data from the primary source (modelEXT, blends stay NULL)
-    // XXX use pmSourceCopy?
     pmSource *newSrc = pmSourceCopy (source);
     newSrc->modelPSF = psMemIncrRefCounter (DBL->data[1]);
+    newSrc->modelPSF->fitRadius = radius;
 
     // build cached models and subtract
@@ -317,5 +342,19 @@
     pmSourceCacheModel (newSrc, maskVal);
     pmSourceSub (newSrc, PM_MODEL_OP_FULL, maskVal);
+
+# if (PS_TRACE_ON)   
     psTrace ("psphot", 5, "blob as DBL: %f %f\n", ONE->params->data.F32[PM_PAR_XPOS], ONE->params->data.F32[PM_PAR_YPOS]);
+    if (psTraceGetLevel("psphot") >= 6) {
+	psLogMsg ("psphot", 1, "source 1:\n");
+	for (int i = 0; i < newSrc->modelPSF->params->n; i++) {
+	    psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, newSrc->modelPSF->params->data.F32[i], newSrc->modelPSF->dparams->data.F32[i]);
+	}
+	psLogMsg ("psphot", 1, "source 2:\n");
+	for (int i = 0; i < source->modelPSF->params->n; i++) {
+	    psLogMsg ("psphot", 1, "PAR %d : %f +/- %f\n", i, source->modelPSF->params->data.F32[i], source->modelPSF->dparams->data.F32[i]);
+	}
+	psphotVisualShowResidualImage (readout);
+    }
+# endif
 
     psArrayAdd (newSources, 100, newSrc);
@@ -356,5 +395,4 @@
     // save the PSF model from the Ensemble fit
     PSF = source->modelPSF;
-    psphotCheckRadiusPSFBlend (readout, source, PSF, markVal, 8.0);
     if (isnan(PSF->params->data.F32[1])) psAbort("nan in dbl fit");
 
@@ -389,8 +427,4 @@
     PS_ASSERT (EXT, NULL);
 
-    // if (isnan(EXT->params->data.F32[1])) psAbort("nan in ext fit");
-
-    psphotCheckRadiusEXT (readout, source, EXT, markVal);
-
     if ((source->moments->Mxx < 1e-3) || (source->moments->Myy < 1e-3)) {
         psTrace ("psphot", 5, "problem source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
@@ -401,3 +435,2 @@
     return (EXT);
 }
-
Index: branches/eam_branches/20090820/psphot/src/psphotSourcePlots.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotSourcePlots.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotSourcePlots.c	(revision 25766)
@@ -111,12 +111,14 @@
             if (Xo == 0) {
                 // place source alone on this row
-                psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+		bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+		if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
                 psphotRadialPlot (&kapa, "radial.plots.ps", source);
                 psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
 
-                psphotSubWithTest (source, false, maskVal); // remove source (force)
+		pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
                 psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
 
-                psphotSetState (source, false, maskVal); // replace source (has been subtracted)
+		if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
+
                 Yo += DY;
                 Xo = 0;
@@ -126,11 +128,13 @@
                 Yo += dY;
                 Xo = 0;
-                psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+
+		bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+		if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
                 psphotRadialPlot (&kapa, "radial.plots.ps", source);
                 psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
 
-                psphotSubWithTest (source, false, maskVal); // remove source (force)
+		pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
                 psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
-                psphotSetState (source, false, maskVal); // replace source (has been subtracted)
+		if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
 
                 Xo = DX;
@@ -139,11 +143,12 @@
         } else {
             // extend this row
-            psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+	    bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+	    if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
             psphotRadialPlot (&kapa, "radial.plots.ps", source);
             psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
 
-            psphotSubWithTest (source, false, maskVal); // remove source (force)
+	    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
             psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
-            psphotSetState (source, false, maskVal); // replace source (has been subtracted)
+	    if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
 
             Xo += DX;
Index: branches/eam_branches/20090820/psphot/src/psphotSourceSize.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotSourceSize.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotSourceSize.c	(revision 25766)
@@ -2,9 +2,23 @@
 # include <gsl/gsl_sf_gamma.h>
 
-static float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
-                                psImageMaskType maskVal, const pmModel *model, float Ro);
-
-bool psphotMaskCosmicRay_Old (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
-bool psphotMaskCosmicRay_New (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
+typedef struct {
+    psImageMaskType maskVal;
+    psImageMaskType markVal;
+    psImageMaskType crMask;
+    float ApResid;
+    float ApSysErr;
+    float nSigmaApResid;
+    float nSigmaMoments;
+    float nSigmaCR;
+    float soft;
+    int grow;
+} psphotSourceSizeOptions;
+
+bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf);
+bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
+bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options);
+bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options);
+bool psphotMaskCosmicRay (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
+bool psphotMaskCosmicRayIsophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask);
 
 // we need to call this function after sources have been fitted to the PSF model and
@@ -14,178 +28,384 @@
 // deviation from the psf model at the r = FWHM/2 position
 
-bool psphotSourceSize(pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, long first)
+// XXX use an internal flag to mark sources which have already been measured
+bool psphotSourceSize(pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, long first)
 {
     bool status;
+    psphotSourceSizeOptions options;
 
     psTimerStart ("psphot.size");
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
-    assert (maskVal);
+    options.maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    assert (options.maskVal);
+
+    options.markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
+    assert (options.markVal);
 
     // bit to mask the cosmic-ray pixels
-    psImageMaskType crMask  = pmConfigMaskGet("CR", config); // Mask value for cosmic rays
-
-    float CR_NSIGMA_LIMIT = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.NSIGMA.LIMIT");
+    options.crMask  = pmConfigMaskGet("CR", config); // Mask value for cosmic rays
+
+    options.nSigmaCR = psMetadataLookupF32 (&status, recipe, "PSPHOT.CR.NSIGMA.LIMIT");
     assert (status);
 
-    float EXT_NSIGMA_LIMIT = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.LIMIT");
+    // XXX recipe name is not great
+    options.nSigmaApResid = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.LIMIT");
     assert (status);
 
-    int grow = psMetadataLookupS32(&status, recipe, "PSPHOT.CR.GROW"); // Growth size for CRs
-    if (!status || grow < 0) {
+    // XXX recipe name is not great
+    options.nSigmaMoments = psMetadataLookupF32 (&status, recipe, "PSPHOT.EXT.NSIGMA.MOMENTS");
+    assert (status);
+
+    options.grow = psMetadataLookupS32(&status, recipe, "PSPHOT.CR.GROW"); // Growth size for CRs
+    if (!status || options.grow < 0) {
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSPHOT.CR.GROW is not positive.");
         return false;
     }
 
-    float soft = psMetadataLookupF32(&status, recipe, "PSPHOT.CR.NSIGMA.SOFTEN"); // Softening parameter
-    if (!status || !isfinite(soft) || soft < 0.0) {
+    options.soft = psMetadataLookupF32(&status, recipe, "PSPHOT.CR.NSIGMA.SOFTEN"); // Softening parameter
+    if (!status || !isfinite(options.soft) || options.soft < 0.0) {
         psWarning("PSPHOT.CR.NSIGMA.SOFTEN not set; defaulting to zero.");
-        soft = 0.0;
-    }
-
-    // loop over all source
-    for (int i = first; i < sources->n; i++) {
-        pmSource *source = sources->data[i];
-
-        // skip source if it was already measured
-        if (isfinite(source->crNsigma)) {
-            psTrace("psphot", 7, "Not calculating extNsigma,crNsigma since already measured\n");
-            continue;
+        options.soft = 0.0;
+    }
+
+    // We are using the value psfMag - 2.5*log10(moment.Sum) as a measure of the extendedness
+    // of and object.  We need to model this distribution for the PSF stars before we can test
+    // the significance for a specific object
+    // XXX move this to the code that generates the PSF?
+    // XXX store the results on pmPSF?
+    psphotSourceSizePSF (&options, sources, psf);
+
+    // classify the sources based on ApResid and Moments (extended sources)
+    psphotSourceClass(readout, sources, recipe, psf, &options);
+
+    psphotSourceSizeCR (readout, sources, &options);
+
+    psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n", sources->n - first, psTimerMark ("psphot.size"));
+
+    psphotVisualPlotSourceSize (recipe, sources);
+    psphotVisualShowSourceSize (readout, sources);
+    psphotVisualPlotApResid (sources, options.ApResid, options.ApSysErr);
+
+    return true;
+}
+
+bool psphotMaskCosmicRay (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
+
+    // replace the source flux
+    pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
+
+    // flag this as a CR
+    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
+    pmPeak *peak = source->peak;
+    psAssert (peak, "NULL peak");
+
+    // grab the matching footprint
+    pmFootprint *footprint = peak->footprint;
+    if (!footprint) {
+	// if we have not footprint, use the old code to mask by isophot
+	psphotMaskCosmicRayIsophot (source, maskVal, crMask);
+	return true;
+    }
+
+    if (!footprint->spans) {
+	// if we have no footprint, use the old code to mask by isophot
+	psphotMaskCosmicRayIsophot (source, maskVal, crMask);
+	return true;
+    }
+
+    // mask all of the pixels covered by the spans of the footprint
+    for (int j = 1; j < footprint->spans->n; j++) {
+	pmSpan *span1 = footprint->spans->data[j];
+
+	int iy = span1->y;
+	int xs = span1->x0;
+	int xe = span1->x1;
+
+	for (int ix = xs; ix < xe; ix++) {
+	    mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
+	}
+    }
+    return true;
+}
+
+bool psphotMaskCosmicRayIsophot (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
+
+    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
+    pmPeak *peak = source->peak;
+    psAssert (peak, "NULL peak");
+
+    psImage *mask   = source->maskView;
+    psImage *pixels = source->pixels;
+    psImage *variance = source->variance;
+
+    // XXX This should be a recipe variable
+# define SN_LIMIT 5.0
+
+    int xo = peak->x - pixels->col0;
+    int yo = peak->y - pixels->row0;
+
+    // mark the pixels in this row to the left, then the right
+    for (int ix = xo; ix >= 0; ix--) {
+	float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
+	if (SN > SN_LIMIT) {
+	    mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
+	}
+    }
+    for (int ix = xo + 1; ix < pixels->numCols; ix++) {
+	float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
+	if (SN > SN_LIMIT) {
+	    mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
+	}
+    }
+
+    // for each of the neighboring rows, mark the high pixels if they have a marked neighbor
+    // first go up:
+    for (int iy = PS_MIN(yo, mask->numRows-2); iy >= 0; iy--) {
+	// mark the pixels in this row to the left, then the right
+	for (int ix = 0; ix < pixels->numCols; ix++) {
+	    float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
+	    if (SN < SN_LIMIT) continue;
+
+	    bool valid = false;
+	    valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix] & crMask);
+	    valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix-1] & crMask) : 0;
+	    valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix+1] & crMask) : 0;
+
+	    if (!valid) continue;
+	    mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
+	}
+    }
+    // next go down:
+    for (int iy = PS_MIN(yo+1, mask->numRows-1); iy < pixels->numRows; iy++) {
+	// mark the pixels in this row to the left, then the right
+	for (int ix = 0; ix < pixels->numCols; ix++) {
+	    float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
+	    if (SN < SN_LIMIT) continue;
+
+	    bool valid = false;
+	    valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix] & crMask);
+	    valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix-1] & crMask) : 0;
+	    valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix+1] & crMask) : 0;
+
+	    if (!valid) continue;
+	    mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
+	}
+    }
+    return true;
+}
+
+// model the apmifit distribution for the psf stars:
+bool psphotSourceSizePSF (psphotSourceSizeOptions *options, psArray *sources, pmPSF *psf) {
+
+    // select stats from the psf stars
+    psVector *Ap = psVectorAllocEmpty (100, PS_TYPE_F32);
+    psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);
+    
+    psImageMaskType maskVal = options->maskVal | options->markVal;
+
+    // XXX  why PHOT_WEIGHT??
+    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
+
+    for (int i = 0; i < sources->n; i++) {
+	pmSource *source = sources->data[i];
+	if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
+
+        // replace object in image
+        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
+            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
         }
 
-        // source must have been subtracted
-        if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
+	// clear the mask bit and set the circular mask pixels
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
+	psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
+
+	// XXX can we test if psfMag is set and calculate only if needed?
+	pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
+	
+	// clear the mask bit 
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
+
+        // re-subtract the object, leave local sky
+        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
+
+	float apMag = -2.5*log10(source->moments->Sum);
+	float dMag = source->psfMag - apMag;
+	
+	psVectorAppend (Ap, 100, dMag);
+	psVectorAppend (ApErr, 100, source->errMag);
+    }
+
+    // model the distribution as a mean or median value and a systematic error from that value:
+    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
+    psVectorStats (stats, Ap, NULL, NULL, 0);
+
+    psVector *dAp = psVectorAlloc (Ap->n, PS_TYPE_F32);
+    for (int i = 0; i < Ap->n; i++) {
+	dAp->data.F32[i] = Ap->data.F32[i] - stats->robustMedian;
+    }
+
+    options->ApResid = stats->robustMedian;
+    options->ApSysErr = psVectorSystematicError(dAp, ApErr, 0.05);
+    psLogMsg ("psphot", PS_LOG_DETAIL, "psf - Sum: %f +/- %f\n", options->ApResid, options->ApSysErr);
+
+    psFree (Ap);
+    psFree (ApErr);
+    psFree (stats);
+    psFree (dAp);
+
+    return true;
+}
+
+// classify sources based on the combination of psf-mag, Mxx, Myy
+bool psphotSourceClass (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
+
+    bool status;
+    pmPSFClump psfClump;
+    char regionName[64];
+
+    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4s %4s %4s %4s %4s %4s", "Npsf", "Next", "Nsat", "Ncr", "Nmiss", "Nskip");
+
+    int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
+    for (int i = 0; i < nRegions; i ++) {
+	snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", i);
+	psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
+	psAssert (regionMD, "regions must be defined by earlier call to psphotRoughClassRegion");
+
+	psRegion *region = psMetadataLookupPtr (&status, regionMD, "REGION");
+	psAssert (region, "regions must be defined by earlier call to psphotRoughClassRegion");
+
+	// pull FWHM_X,Y from the recipe, use to define psfClump.X,Y
+	psfClump.X  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");   psAssert (status, "missing PSF.CLUMP.X");
+	psfClump.Y  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");   psAssert (status, "missing PSF.CLUMP.Y");
+	psfClump.dX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");  psAssert (status, "missing PSF.CLUMP.DX");
+	psfClump.dY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");  psAssert (status, "missing PSF.CLUMP.DY");
+
+	if ((psfClump.X < 0) || (psfClump.Y < 0) || !psfClump.X || !psfClump.Y || isnan(psfClump.X) || isnan(psfClump.Y)) {
+	    psLogMsg ("psphot", 4, "Failed to find a valid PSF clump for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
+	    continue;
+	}
+	
+	if (!psphotSourceClassRegion (region, &psfClump, sources, recipe, psf, options)) {
+	    psLogMsg ("psphot", 4, "Failed to determine source classification for region %f,%f - %f,%f\n", region->x0, region->y0, region->x1, region->y1);
+	    continue;
+	}
+    }	
+
+    return true;
+}
+
+bool psphotSourceClassRegion (psRegion *region, pmPSFClump *psfClump, psArray *sources, psMetadata *recipe, pmPSF *psf, psphotSourceSizeOptions *options) {
+
+    PS_ASSERT_PTR_NON_NULL(sources, false);
+    PS_ASSERT_PTR_NON_NULL(recipe, false);
+
+    int Nsat  = 0;
+    int Next  = 0;
+    int Npsf  = 0;
+    int Ncr   = 0;
+    int Nmiss = 0;
+    int Nskip = 0;
+
+    pmSourceMode noMoments = PM_SOURCE_MODE_MOMENTS_FAILURE | PM_SOURCE_MODE_SKYVAR_FAILURE | PM_SOURCE_MODE_SKY_FAILURE | PM_SOURCE_MODE_BELOW_MOMENTS_SN;
+    pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
+
+    psImageMaskType maskVal = options->maskVal | options->markVal;
+
+    for (psS32 i = 0 ; i < sources->n ; i++) {
+
+	pmSource *source = (pmSource *) sources->data[i];
+
+	// psfClumps are found for image subregions:
+	// skip sources not in this region
+	if (source->peak->x <  region->x0) continue;
+	if (source->peak->x >= region->x1) continue;
+	if (source->peak->y <  region->y0) continue;
+	if (source->peak->y >= region->y1) continue;
+
+	// skip source if it was already measured
+	if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
+	    psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
+	    continue;
+	}
+
+	// source must have been subtracted
+	if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
 	    source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
-            psTrace("psphot", 7, "Not calculating extNsigma,crNsigma since source is not subtracted\n");
-            continue;
+	    psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
+	    continue;
+	}
+
+	// we are basically classifying by moments; use the default if not found
+	psAssert (source->moments, "why is this source missing moments?");
+	if (source->mode & noMoments) { 
+	    Nskip ++;
+	    continue;
+	}
+
+	psF32 Mxx = source->moments->Mxx;
+	psF32 Myy = source->moments->Myy;
+
+        // replace object in image
+        if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
+            pmSourceAdd (source, PM_MODEL_OP_FULL, options->maskVal);
         }
 
-        psF32 **resid  = source->pixels->data.F32;
-        psF32 **variance = source->variance->data.F32;
-        psImageMaskType **mask = source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
-
-        // check for extendedness: measure the delta flux significance at the 1 sigma contour
-        source->extNsigma = psphotModelContour(source->pixels, source->variance, source->maskObj, maskVal,
-                                               source->modelPSF, 1.0);
-
-        // XXX prevent a source from being both CR and EXT?
-        if (source->extNsigma > EXT_NSIGMA_LIMIT) {
-            source->mode |= PM_SOURCE_MODE_EXT_LIMIT;
-        }
-
-        // Integer position of peak
-        int xPeak = source->peak->xf - source->pixels->col0 + 0.5;
-        int yPeak = source->peak->yf - source->pixels->row0 + 0.5;
-
-        // XXX for now, skip sources which are too close to a boundary
-        // XXX raise a flag?
-        if (xPeak < 1 || xPeak > source->pixels->numCols - 2 ||
-            yPeak < 1 || yPeak > source->pixels->numRows - 2) {
-	    source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
-            psTrace("psphot", 7, "Not calculating crNsigma due to edge\n");
-            continue;
-        }
-
-        // XXX for now, just skip any sources with masked pixels
-        // XXX raise a flag?
-        bool keep = true;
-        for (int iy = -1; (iy <= +1) && keep; iy++) {
-            for (int ix = -1; (ix <= +1) && keep; ix++) {
-                if (mask[yPeak+iy][xPeak+ix] & maskVal) {
-                    keep = false;
-                }
-            }
-        }
-        if (!keep) {
-            psTrace("psphot", 7, "Not calculating crNsigma due to masked pixels\n");
-	    source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
-            continue;
-        }
-
-        // Compare the central pixel with those on either side, for the four possible lines through it.
-
-        // Soften variances (add systematic error)
-        float softening = soft * PS_SQR(source->peak->flux); // Softening for variances
-
-        // Across the middle: y = 0
-        float cX = 2*resid[yPeak][xPeak]   - resid[yPeak+0][xPeak-1]  - resid[yPeak+0][xPeak+1];
-        float dcX = 4*variance[yPeak][xPeak] + variance[yPeak+0][xPeak-1] + variance[yPeak+0][xPeak+1];
-        float nX = cX / sqrtf(dcX + softening);
-
-        // Up the centre: x = 0
-        float cY = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak+0]  - resid[yPeak+1][xPeak+0];
-        float dcY = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak+0] + variance[yPeak+1][xPeak+0];
-        float nY = cY / sqrtf(dcY + softening);
-
-        // Diagonal: x = y
-        float cL = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak-1]  - resid[yPeak+1][xPeak+1];
-        float dcL = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak-1] + variance[yPeak+1][xPeak+1];
-        float nL = cL / sqrtf(dcL + softening);
-
-        // Diagonal: x = - y
-        float cR = 2*resid[yPeak][xPeak]   - resid[yPeak+1][xPeak-1]  - resid[yPeak-1][xPeak+1];
-        float dcR = 4*variance[yPeak][xPeak] + variance[yPeak+1][xPeak-1] + variance[yPeak-1][xPeak+1];
-        float nR = cR / sqrtf(dcR + softening);
-
-        // P(chisq > chisq_obs; Ndof) = gamma_Q (Ndof/2, chisq/2)
-        // Ndof = 4 ? (four measurements, no free parameters)
-        // XXX this value is going to be biased low because of systematic errors.
-        // we need to calibrate it somehow
-        // source->psfProb = gsl_sf_gamma_inc_Q (2, 0.5*chisq);
-
-        // not strictly accurate: overcounts the chisq contribution from the center pixel (by
-        // factor of 4); also biases a bit low if any pixels are masked
-        // XXX I am not sure I want to keep this value...
-        source->psfChisq = PS_SQR(nX) + PS_SQR(nY) + PS_SQR(nL) + PS_SQR(nR);
-
-        float fCR = 0.0;
-        int nCR = 0;
-        if (nX > 0.0) {
-            fCR += nX;
-            nCR ++;
-        }
-        if (nY > 0.0) {
-            fCR += nY;
-            nCR ++;
-        }
-        if (nL > 0.0) {
-            fCR += nL;
-            nCR ++;
-        }
-        if (nR > 0.0) {
-            fCR += nR;
-            nCR ++;
-        }
-        source->crNsigma  = (nCR > 0)  ? fCR / nCR : 0.0;
-        if (!isfinite(source->crNsigma)) {
-	    continue;
-	}
-
-        // this source is thought to be a cosmic ray.  flag the detection and mask the pixels
-        if (source->crNsigma > CR_NSIGMA_LIMIT) {
-            // XXX still testing... : psphotMaskCosmicRay_New (readout->mask, source, maskVal, crMask);
-            psphotMaskCosmicRay_Old (source, maskVal, crMask);
-        }
-    }
-
-    // now that we have masked pixels associated with CRs, we can grow the mask
-    if (grow > 0) {
-        bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolveMask
-        psImage *newMask = psImageConvolveMask(NULL, readout->mask, crMask, crMask, -grow, grow, -grow, grow);
-        psImageConvolveSetThreads(oldThreads);
-        if (!newMask) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to grow CR mask");
-            return false;
-        }
-        psFree(readout->mask);
-        readout->mask = newMask;
-    }
-
-    psLogMsg ("psphot.size", PS_LOG_INFO, "measure source sizes for %ld sources: %f sec\n",
-              sources->n - first, psTimerMark ("psphot.size"));
-
-    psphotVisualPlotSourceSize (sources);
-    psphotVisualShowSourceSize (readout, sources);
+	// clear the mask bit and set the circular mask pixels
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
+	psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", options->markVal);
+
+	// XXX can we test if psfMag is set and calculate only if needed?
+	pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
+
+	// clear the mask bit 
+	psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(options->markVal));
+
+        // re-subtract the object, leave local sky
+        pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
+
+	float apMag = -2.5*log10(source->moments->Sum);
+	float dMag = source->psfMag - apMag;
+	float nSigma = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr);
+
+	source->extNsigma = nSigma;
+	source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
+
+	// Anything within this region is a probably PSF-like object. Saturated stars may land
+	// in this region, but are detected elsewhere on the basis of their peak value.
+	bool isPSF = (fabs(nSigma) < options->nSigmaApResid) && (fabs(Mxx - psfClump->X) < options->nSigmaMoments*psfClump->dX) && (fabs(Myy - psfClump->Y) < options->nSigmaMoments*psfClump->dY);
+	if (isPSF) {
+	    Npsf ++;
+	    continue;
+	}
+
+	// Defects may not always match CRs from peak curvature analysis
+	// Defects may also be marked as SATSTAR -- XXX deactivate this flag?
+	// XXX this rule is not great
+	if ((Mxx < psfClump->X) || (Myy < psfClump->Y)) {
+	    source->mode |= PM_SOURCE_MODE_DEFECT;
+	    Ncr ++;
+	    continue;
+	}
+
+	// saturated star (determined in PSF fit).  These may also be saturated galaxies, or
+	// just large saturated regions.
+	if (source->mode & PM_SOURCE_MODE_SATSTAR) { 
+	    Nsat ++;
+	    continue;
+	}
+
+	// XXX allow the Mxx, Myy to be less than psfClump->X,Y (by some nSigma)?
+	bool isEXT = (nSigma > options->nSigmaApResid) || ((Mxx > psfClump->X) && (Myy > psfClump->Y));
+	if (isEXT) {
+	    source->mode |= PM_SOURCE_MODE_EXT_LIMIT;
+	    Next ++;
+	    continue;
+	}
+
+	psWarning ("sourse size was missed for %f,%f : %f %f -- %f\n", source->peak->xf, source->peak->yf, Mxx, Myy, nSigma);
+	Nmiss ++;
+    }
+
+    psLogMsg("psModules.objects", PS_LOG_INFO, "Source Size classifications: %4d %4d %4d %4d %4d %4d", Npsf, Next, Nsat, Ncr, Nmiss, Nskip);
 
     return true;
@@ -194,7 +414,8 @@
 // given the PSF ellipse parameters, navigate around the 1sigma contour, return the total
 // deviation in sigmas.  This is measured on the residual image - should we ignore negative
-// deviations?
-static float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
-                                psImageMaskType maskVal, const pmModel *model, float Ro)
+// deviations?  NOTE: This function was an early attempt to classify extended objects, and is
+// no longer used by psphot.
+float psphotModelContour(const psImage *image, const psImage *variance, const psImage *mask,
+			 psImageMaskType maskVal, const pmModel *model, float Ro)
 {
     psF32 *PAR = model->params->data.F32; // Model parameters
@@ -211,6 +432,6 @@
     float Q = Ro * PS_SQR(sxx) / (1.0 - PS_SQR(sxx * syy * sxy) / 4.0);
     if (Q < 0.0) {
-        // ellipse is imaginary
-        return NAN;
+	// ellipse is imaginary
+	return NAN;
     }
 
@@ -220,44 +441,44 @@
 
     for (int x = -radius; x <= radius; x++) {
-        // Polynomial coefficients
-        // XXX Should we be using the centre of the pixel as x or x+0.5?
-        float A = PS_SQR (1.0 / syy);
-        float B = x * sxy;
-        float C = PS_SQR (x / sxx) - Ro;
-        float T = PS_SQR(B) - 4*A*C;
-        if (T < 0.0) {
-            continue;
-        }
-
-        // y position in source frame
-        float yP = (-B + sqrt (T)) / (2.0 * A);
-        float yM = (-B - sqrt (T)) / (2.0 * A);
-
-        // Get the closest pixel positions (image frame)
-        int xPix  = x  + PAR[PM_PAR_XPOS] - image->col0 + 0.5;
-        int yPixM = yM + PAR[PM_PAR_YPOS] - image->row0 + 0.5;
-        int yPixP = yP + PAR[PM_PAR_YPOS] - image->row0 + 0.5;
-
-        if (xPix < 0 || xPix >= image->numCols) {
-            continue;
-        }
-
-        if (yPixM >= 0 && yPixM < image->numRows &&
-            !(mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[yPixM][xPix] & maskVal))) {
-            float dSigma = image->data.F32[yPixM][xPix] / sqrtf(variance->data.F32[yPixM][xPix]);
-            nSigma += dSigma;
-            nPts++;
-        }
-
-        if (yPixM == yPixP) {
-            continue;
-        }
-
-        if (yPixP >= 0 && yPixP < image->numRows &&
-            !(mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[yPixP][xPix] & maskVal))) {
-            float dSigma = image->data.F32[yPixP][xPix] / sqrtf(variance->data.F32[yPixP][xPix]);
-            nSigma += dSigma;
-            nPts++;
-        }
+	// Polynomial coefficients
+	// XXX Should we be using the centre of the pixel as x or x+0.5?
+	float A = PS_SQR (1.0 / syy);
+	float B = x * sxy;
+	float C = PS_SQR (x / sxx) - Ro;
+	float T = PS_SQR(B) - 4*A*C;
+	if (T < 0.0) {
+	    continue;
+	}
+
+	// y position in source frame
+	float yP = (-B + sqrt (T)) / (2.0 * A);
+	float yM = (-B - sqrt (T)) / (2.0 * A);
+
+	// Get the closest pixel positions (image frame)
+	int xPix  = x  + PAR[PM_PAR_XPOS] - image->col0 + 0.5;
+	int yPixM = yM + PAR[PM_PAR_YPOS] - image->row0 + 0.5;
+	int yPixP = yP + PAR[PM_PAR_YPOS] - image->row0 + 0.5;
+
+	if (xPix < 0 || xPix >= image->numCols) {
+	    continue;
+	}
+
+	if (yPixM >= 0 && yPixM < image->numRows &&
+	    !(mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[yPixM][xPix] & maskVal))) {
+	    float dSigma = image->data.F32[yPixM][xPix] / sqrtf(variance->data.F32[yPixM][xPix]);
+	    nSigma += dSigma;
+	    nPts++;
+	}
+
+	if (yPixM == yPixP) {
+	    continue;
+	}
+
+	if (yPixP >= 0 && yPixP < image->numRows &&
+	    !(mask && (mask->data.PS_TYPE_IMAGE_MASK_DATA[yPixP][xPix] & maskVal))) {
+	    float dSigma = image->data.F32[yPixP][xPix] / sqrtf(variance->data.F32[yPixP][xPix]);
+	    nSigma += dSigma;
+	    nPts++;
+	}
     }
     nSigma /= nPts;
@@ -265,107 +486,134 @@
 }
 
-bool psphotMaskCosmicRay_New (psImage *mask, pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
-
-    // replace the source flux
-    pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
-    source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
-
-    // flag this as a CR
-    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
-    pmPeak *peak = source->peak;
-    psAssert (peak, "NULL peak");
-
-    // grab the matching footprint
-    pmFootprint *footprint = peak->footprint;
-    if (!footprint) {
-        // if we have not footprint, use the old code to mask by isophot
-        psphotMaskCosmicRay_Old (source, maskVal, crMask);
-        return true;
-    }
-
-    if (!footprint->spans) {
-        // if we have not footprint, use the old code to mask by isophot
-        psphotMaskCosmicRay_Old (source, maskVal, crMask);
-        return true;
-    }
-
-    // mask all of the pixels covered by the spans of the footprint
-    for (int j = 1; j < footprint->spans->n; j++) {
-        pmSpan *span1 = footprint->spans->data[j];
-
-        int iy = span1->y;
-        int xs = span1->x0;
-        int xe = span1->x1;
-
-        for (int ix = xs; ix < xe; ix++) {
-            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
-        }
+bool psphotSourceSizeCR (pmReadout *readout, psArray *sources, psphotSourceSizeOptions *options) {
+
+    // classify the sources based on the CR test (place this in a function?)
+    // XXX use an internal flag to mark sources which have already been measured
+    for (int i = 0; i < sources->n; i++) {
+	pmSource *source = sources->data[i];
+
+	// skip source if it was already measured
+	if (source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED) {
+	    psTrace("psphot", 7, "Not calculating source size since it has already been measured\n");
+	    continue;
+	}
+
+	// source must have been subtracted
+	if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) {
+	    source->mode |= PM_SOURCE_MODE_SIZE_SKIPPED;
+	    psTrace("psphot", 7, "Not calculating source size since source is not subtracted\n");
+	    continue;
+	}
+
+	psF32 **resid  = source->pixels->data.F32;
+	psF32 **variance = source->variance->data.F32;
+	psImageMaskType **mask = source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA;
+
+	// Integer position of peak
+	int xPeak = source->peak->xf - source->pixels->col0 + 0.5;
+	int yPeak = source->peak->yf - source->pixels->row0 + 0.5;
+
+	// Skip sources which are too close to a boundary.  These are mostly caught as DEFECT
+	if (xPeak < 1 || xPeak > source->pixels->numCols - 2 ||
+	    yPeak < 1 || yPeak > source->pixels->numRows - 2) {
+	    psTrace("psphot", 7, "Not calculating crNsigma due to edge\n");
+	    continue;
+	}
+
+	// Skip sources with masked pixels.  These are mostly caught as DEFECT
+	bool keep = true;
+	for (int iy = -1; (iy <= +1) && keep; iy++) {
+	    for (int ix = -1; (ix <= +1) && keep; ix++) {
+		if (mask[yPeak+iy][xPeak+ix] & options->maskVal) {
+		    keep = false;
+		}
+	    }
+	}
+	if (!keep) {
+	    psTrace("psphot", 7, "Not calculating crNsigma due to masked pixels\n");
+	    continue;
+	}
+
+	// Compare the central pixel with those on either side, for the four possible lines through it.
+
+	// Soften variances (add systematic error)
+	float softening = options->soft * PS_SQR(source->peak->flux); // Softening for variances
+
+	// Across the middle: y = 0
+	float cX = 2*resid[yPeak][xPeak]   - resid[yPeak+0][xPeak-1]  - resid[yPeak+0][xPeak+1];
+	float dcX = 4*variance[yPeak][xPeak] + variance[yPeak+0][xPeak-1] + variance[yPeak+0][xPeak+1];
+	float nX = cX / sqrtf(dcX + softening);
+
+	// Up the centre: x = 0
+	float cY = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak+0]  - resid[yPeak+1][xPeak+0];
+	float dcY = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak+0] + variance[yPeak+1][xPeak+0];
+	float nY = cY / sqrtf(dcY + softening);
+
+	// Diagonal: x = y
+	float cL = 2*resid[yPeak][xPeak]   - resid[yPeak-1][xPeak-1]  - resid[yPeak+1][xPeak+1];
+	float dcL = 4*variance[yPeak][xPeak] + variance[yPeak-1][xPeak-1] + variance[yPeak+1][xPeak+1];
+	float nL = cL / sqrtf(dcL + softening);
+
+	// Diagonal: x = - y
+	float cR = 2*resid[yPeak][xPeak]   - resid[yPeak+1][xPeak-1]  - resid[yPeak-1][xPeak+1];
+	float dcR = 4*variance[yPeak][xPeak] + variance[yPeak+1][xPeak-1] + variance[yPeak-1][xPeak+1];
+	float nR = cR / sqrtf(dcR + softening);
+
+	// P(chisq > chisq_obs; Ndof) = gamma_Q (Ndof/2, chisq/2)
+	// Ndof = 4 ? (four measurements, no free parameters)
+	// XXX this value is going to be biased low because of systematic errors.
+	// we need to calibrate it somehow
+	// source->psfProb = gsl_sf_gamma_inc_Q (2, 0.5*chisq);
+
+	// not strictly accurate: overcounts the chisq contribution from the center pixel (by
+	// factor of 4); also biases a bit low if any pixels are masked
+	// XXX I am not sure I want to keep this value...
+	source->psfChisq = PS_SQR(nX) + PS_SQR(nY) + PS_SQR(nL) + PS_SQR(nR);
+
+	float fCR = 0.0;
+	int nCR = 0;
+	if (nX > 0.0) {
+	    fCR += nX;
+	    nCR ++;
+	}
+	if (nY > 0.0) {
+	    fCR += nY;
+	    nCR ++;
+	}
+	if (nL > 0.0) {
+	    fCR += nL;
+	    nCR ++;
+	}
+	if (nR > 0.0) {
+	    fCR += nR;
+	    nCR ++;
+	}
+	source->crNsigma  = (nCR > 0)  ? fCR / nCR : 0.0;
+	source->tmpFlags |= PM_SOURCE_TMPF_SIZE_MEASURED;
+
+	if (!isfinite(source->crNsigma)) {
+	    continue;
+	}
+
+	// this source is thought to be a cosmic ray.  flag the detection and mask the pixels
+	if (source->crNsigma > options->nSigmaCR) {
+	    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
+	    // XXX still testing... : psphotMaskCosmicRay (readout->mask, source, maskVal, crMask);
+	    // XXX acting strange... psphotMaskCosmicRay_Old (source, maskVal, crMask);
+	}
+    }
+
+    // now that we have masked pixels associated with CRs, we can grow the mask
+    if (options->grow > 0) {
+	bool oldThreads = psImageConvolveSetThreads(true); // Old value of threading for psImageConvolveMask
+	psImage *newMask = psImageConvolveMask(NULL, readout->mask, options->crMask, options->crMask, -options->grow, options->grow, -options->grow, options->grow);
+	psImageConvolveSetThreads(oldThreads);
+	if (!newMask) {
+	    psError(PS_ERR_UNKNOWN, false, "Unable to grow CR mask");
+	    return false;
+	}
+	psFree(readout->mask);
+	readout->mask = newMask;
     }
     return true;
 }
-
-bool psphotMaskCosmicRay_Old (pmSource *source, psImageMaskType maskVal, psImageMaskType crMask) {
-
-    source->mode |= PM_SOURCE_MODE_CR_LIMIT;
-    pmPeak *peak = source->peak;
-    psAssert (peak, "NULL peak");
-
-    psImage *mask   = source->maskView;
-    psImage *pixels = source->pixels;
-    psImage *variance = source->variance;
-
-    // XXX This should be a recipe variable
-# define SN_LIMIT 5.0
-
-    int xo = peak->x - pixels->col0;
-    int yo = peak->y - pixels->row0;
-
-    // mark the pixels in this row to the left, then the right
-    for (int ix = xo; ix >= 0; ix--) {
-        float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
-        if (SN > SN_LIMIT) {
-            mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
-        }
-    }
-    for (int ix = xo + 1; ix < pixels->numCols; ix++) {
-        float SN = pixels->data.F32[yo][ix] / sqrt(variance->data.F32[yo][ix]);
-        if (SN > SN_LIMIT) {
-            mask->data.PS_TYPE_IMAGE_MASK_DATA[yo][ix] |= crMask;
-        }
-    }
-
-    // for each of the neighboring rows, mark the high pixels if they have a marked neighbor
-    // first go up:
-    for (int iy = PS_MIN(yo, mask->numRows-2); iy >= 0; iy--) {
-        // mark the pixels in this row to the left, then the right
-        for (int ix = 0; ix < pixels->numCols; ix++) {
-            float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
-            if (SN < SN_LIMIT) continue;
-
-            bool valid = false;
-            valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix] & crMask);
-            valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix-1] & crMask) : 0;
-            valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy+1][ix+1] & crMask) : 0;
-
-            if (!valid) continue;
-            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
-        }
-    }
-    // next go down:
-    for (int iy = PS_MIN(yo+1, mask->numRows-1); iy < pixels->numRows; iy++) {
-        // mark the pixels in this row to the left, then the right
-        for (int ix = 0; ix < pixels->numCols; ix++) {
-            float SN = pixels->data.F32[iy][ix] / sqrt(variance->data.F32[iy][ix]);
-            if (SN < SN_LIMIT) continue;
-
-            bool valid = false;
-            valid |= (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix] & crMask);
-            valid |= (ix > 0) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix-1] & crMask) : 0;
-            valid |= (ix <= mask->numCols) ? (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy-1][ix+1] & crMask) : 0;
-
-            if (!valid) continue;
-            mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] |= crMask;
-        }
-    }
-    return true;
-}
Index: branches/eam_branches/20090820/psphot/src/psphotSourceStats.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotSourceStats.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotSourceStats.c	(revision 25766)
@@ -1,5 +1,7 @@
 # include "psphotInternal.h"
 
-psArray *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections) {
+bool psphotSetMomentsWindow (psMetadata *recipe, psArray *sources);
+
+psArray *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections, bool setWindow) {
 
     bool status = false;
@@ -21,4 +23,7 @@
     float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
     if (!status) return NULL;
+
+    OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
+
     char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
     if (!status) return NULL;
@@ -60,4 +65,11 @@
         psphotVisualShowMoments (sources);
         return sources;
+    }
+
+    if (setWindow) {
+	if (!psphotSetMomentsWindow(recipe, sources)) {
+	    psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
+	    return NULL;
+	}
     }
 
@@ -144,6 +156,4 @@
     float RADIUS       = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
     if (!status) return false;
-    float MIN_PIXEL_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_MIN_PIXEL_SN");
-    if (!status) return false;
     float SIGMA        = psMetadataLookupF32 (&status, recipe, "MOMENTS_GAUSS_SIGMA");
     if (!status) return false;
@@ -194,6 +204,6 @@
         }
 
-        // measure basic source moments
-        status = pmSourceMoments (source, RADIUS, SIGMA, MIN_PIXEL_SN);
+        // measure basic source moments (no S/N clipping on input pixels)
+        status = pmSourceMoments (source, RADIUS, SIGMA, 0.0);
         if (status) {
             Nmoments ++;
@@ -205,5 +215,5 @@
         BIG_RADIUS = PS_MIN (INNER, 3*RADIUS);
         psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
-        status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, MIN_PIXEL_SN);
+        status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, 0.0);
         if (status) {
             source->mode |= PM_SOURCE_MODE_BIG_RADIUS;
@@ -231,84 +241,91 @@
 }
 
-# if (0)
-bool psphotSourceStats_Unthreaded (int *nfail, int *nmoments, psArray *sources, psMetadata *recipe) {
-
-    bool status = false;
-    float BIG_RADIUS;
-
-    float INNER    = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");
-    if (!status) return false;
-    float MIN_SN   = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
-    if (!status) return false;
-    float RADIUS   = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
-    if (!status) return false;
-
-    // bit-masks to test for good/bad pixels
-    psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
-    assert (maskVal);
-
-    // bit-mask to mark pixels not used in analysis
-    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
-    assert (markVal);
-
-    // maskVal is used to test for rejected pixels, and must include markVal
-    maskVal |= markVal;
-
-    // threaded measurement of the sources moments
-    int Nfail = 0;
-    int Nmoments = 0;
-    for (int i = 0; i < sources->n; i++) {
-        pmSource *source = sources->data[i];
-
-        // skip faint sources for moments measurement
-        if (source->peak->SN < MIN_SN) {
-            continue;
-        }
-
-        // measure a local sky value
-        // the local sky is now ignored; kept here for reference only
-        status = pmSourceLocalSky (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
-        if (!status) {
-            psErrorClear(); // XXX re-consider the errors raised here
-            Nfail ++;
-            continue;
-        }
-
-        // measure the local sky variance (needed if noise is not sqrt(signal))
-        // XXX EAM : this should use ROBUST not SAMPLE median, but it is broken
-        status = pmSourceLocalSkyVariance (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
-        if (!status) {
-            Nfail ++;
-            psErrorClear();
-            continue;
-        }
-
-        // measure basic source moments
-        status = pmSourceMoments (source, RADIUS, SIGMA, MIN_PIXEL_SN);
-        if (status) {
-            Nmoments ++;
-            continue;
-        }
-
-        // if no valid pixels, or massive swing, likely saturated source,
-        // try a much larger box
-        BIG_RADIUS = PS_MIN (INNER, 3*RADIUS);
-        psTrace ("psphot", 4, "retrying moments for %d, %d\n", source->peak->x, source->peak->y);
-        status = pmSourceMoments (source, BIG_RADIUS, 3.0*SIGMA, MIN_PIXEL_SN);
-        if (status) {
-            Nmoments ++;
-            continue;
-        }
-
-        Nfail ++;
-        psErrorClear();
-        continue;
-    }
-
-    // change the value of a scalar on the array (wrap this and put it in psArray.h)
-    *nmoments = Nmoments;
-    *nfail = Nfail;
-
+// this function attempts to iteratively determine the best value for sigma of the moments weighting Gaussian
+bool psphotSetMomentsWindow (psMetadata *recipe, psArray *sources) {
+
+    bool status;
+
+    float MIN_SN = psMetadataLookupF32 (&status, recipe, "MOMENTS_SN_MIN");
+    if (!status) return false;
+
+    // XXX move this to a config file?
+    float sigma[4] = {1.0, 2.0, 3.0, 4.5};
+    float Sout[4];
+
+    // this sorts by peak->SN
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    // loop over radii:
+    for (int i = 0; i < 4; i++) {
+
+	// XXX move max source number to config
+	for (int j = 0; (j < sources->n) && (j < 400); j++) {
+ 
+	    pmSource *source = sources->data[j];
+	    psAssert (source->moments, "force moments to exist");
+	    source->moments->nPixels = 0;
+
+	    // skip faint sources for moments measurement
+	    if (source->peak->SN < MIN_SN) {
+		continue;
+	    }
+
+	    // measure basic source moments (no S/N clipping on input pixels)
+	    status = pmSourceMoments (source, 4*sigma[i], sigma[i], 0.0);
+	}
+
+	// choose a grid scale that is a fixed fraction of the psf sigma^2
+	psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(sigma[i]));
+	psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));
+	psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(sigma[i]));
+
+	// determine the PSF parameters from the source moment values
+	pmPSFClump psfClump = pmSourcePSFClump (NULL, sources, recipe);
+	psLogMsg ("psphot", 3, "radius %.1f, nStars: %d, nSigma: %5.2f, X,  Y: %f, %f (%f, %f)\n", sigma[i], psfClump.nStars, psfClump.nSigma, psfClump.X, psfClump.Y, sqrt(psfClump.X) / sigma[i], sqrt(psfClump.Y) / sigma[i]);
+
+	psMetadataAddS32 (recipe, PS_LIST_TAIL, "PSF.CLUMP.NREGIONS",  PS_META_REPLACE, "psf clump regions", 1);
+	psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, "PSF.CLUMP.REGION.000");
+	if (!regionMD) {
+	    regionMD = psMetadataAlloc();
+	    psMetadataAddMetadata (recipe, PS_LIST_TAIL, "PSF.CLUMP.REGION.000", PS_META_REPLACE, "psf clump region", regionMD);
+	    psFree (regionMD);
+	}
+	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.X",  PS_META_REPLACE, "psf clump center", psfClump.X);
+	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.Y",  PS_META_REPLACE, "psf clump center", psfClump.Y);
+	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DX", PS_META_REPLACE, "psf clump center", psfClump.dX);
+	psMetadataAddF32 (regionMD, PS_LIST_TAIL, "PSF.CLUMP.DY", PS_META_REPLACE, "psf clump center", psfClump.dY);
+	    
+	// psphotVisualPlotMoments (recipe, sources);
+
+	Sout[i] = sqrt(0.5*(psfClump.X + psfClump.Y)) / sigma[i];
+    }
+
+    // we are looking for sigma for which Sout = 0.65 (or some other value)
+
+    float Sigma = NAN;
+    float minS = Sout[0];
+    float maxS = Sout[0];
+    for (int i = 0; i < 4; i++) {
+	minS = PS_MIN(Sout[i], minS);
+	maxS = PS_MAX(Sout[i], maxS);
+    }
+    if (minS > 0.65) Sigma = sigma[3];
+    if (maxS < 0.65) Sigma = sigma[0];
+
+    for (int i = 0; i < 3; i++) {
+	if ((Sout[i] > 0.65) && (Sout[i+1] > 0.65)) continue;
+	if ((Sout[i] < 0.65) && (Sout[i+1] < 0.65)) continue;
+	Sigma = sigma[i] + (0.65 - Sout[i])*(sigma[i+1] - sigma[i])/(Sout[i+1] - Sout[i]);
+    }
+    psAssert (isfinite(Sigma), "did we miss a case?");
+	
+    // choose a grid scale that is a fixed fraction of the psf sigma^2
+    psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_CLUMP_GRID_SCALE", PS_META_REPLACE, "clump grid", 0.1*PS_SQR(Sigma));
+    psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SX_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
+    psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_SY_MAX", PS_META_REPLACE, "moments limit", 2.0*PS_SQR(Sigma));
+    psMetadataAddF32(recipe, PS_LIST_TAIL, "MOMENTS_GAUSS_SIGMA", PS_META_REPLACE, "moments limit", Sigma);
+    psMetadataAddF32(recipe, PS_LIST_TAIL, "PSF_MOMENTS_RADIUS", PS_META_REPLACE, "moments limit", 4.0*Sigma);
+
+    psLogMsg ("psphot", 3, "using window function with sigma = %f\n", Sigma);
     return true;
 }
-# endif
Index: branches/eam_branches/20090820/psphot/src/psphotVersion.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotVersion.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotVersion.c	(revision 25766)
@@ -30,6 +30,6 @@
 psString psphotVersionLong(void)
 {
-    psString version = psLibVersion();  // Version, to return
-    psString source = psLibSource();    // Source
+    psString version = psphotVersion();  // Version, to return
+    psString source = psphotSource();    // Source
 
     psStringPrepend(&version, "psphot ");
Index: branches/eam_branches/20090820/psphot/src/psphotVisual.c
===================================================================
--- branches/eam_branches/20090820/psphot/src/psphotVisual.c	(revision 25206)
+++ branches/eam_branches/20090820/psphot/src/psphotVisual.c	(revision 25766)
@@ -15,11 +15,48 @@
 # include <kapa.h>
 
+bool pmVisualLimitsFromVectors (Graphdata *graphdata, psVector *xVec, psVector *yVec);
+
 // functions used to visualize the analysis as it goes
 // these are invoked by the -visual options
 
-static int kapa = -1;
+static int kapa1 = -1;
 static int kapa2 = -1;
 static int kapa3 = -1;
 
+int psphotKapaChannel (int channel) {
+
+    switch (channel) {
+      case 1:
+	if (kapa1 == -1) {
+	    kapa1 = KapaOpenNamedSocket ("kapa", "psphot:images");
+	    if (kapa1 == -1) {
+		fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+		pmVisualSetVisual(false);
+	    }
+	}
+	return kapa1;
+      case 2:
+	if (kapa2 == -1) {
+	    kapa2 = KapaOpenNamedSocket ("kapa", "psphot:plots");
+	    if (kapa2 == -1) {
+		fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+		pmVisualSetVisual(false);
+	    }
+	}
+	return kapa2;
+      case 3:
+	if (kapa3 == -1) {
+	    kapa3 = KapaOpenNamedSocket ("kapa", "psphot:stamps");
+	    if (kapa3 == -1) {
+		fprintf (stderr, "failure to open kapa; visual mode disabled\n");
+		pmVisualSetVisual(false);
+	    }
+	}
+	return kapa3;
+      default:
+	psAbort ("unknown kapa channel");
+    }
+    psAbort ("unknown kapa channel");
+}
 
 bool psphotVisualShowMask (int kapaFD, psImage *inImage, const char *name, int channel) {
@@ -131,12 +168,6 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa == -1) {
-        kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
-        if (kapa == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
+    int kapa = psphotKapaChannel (1);
+    if (kapa == -1) return false;
 
     // psphotVisualShowMask (kapa, readout->mask, "mask", 2);
@@ -144,11 +175,5 @@
     psphotVisualScaleImage (kapa, readout->image, "image", 0);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -160,12 +185,6 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa == -1) {
-        kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
-        if (kapa == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
+    int kapa = psphotKapaChannel (1);
+    if (kapa == -1) return false;
 
     bool status = false;
@@ -181,11 +200,5 @@
     psphotVisualScaleImage (kapa, readout->image, "backsub", 0);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -195,23 +208,10 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa == -1) {
-        kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
-        if (kapa == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
-
-    // XXX test: image->data.F32[10][10] = 10000;
+    int kapa = psphotKapaChannel (1);
+    if (kapa == -1) return false;
+
     psphotVisualRangeImage (kapa, image, "signif", 2, -1.0, 25.0*25.0);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -224,8 +224,6 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa == -1) {
-        fprintf (stderr, "kapa not opened, skipping\n");
-        return false;
-    }
+    int kapa = psphotKapaChannel (1);
+    if (kapa == -1) return false;
 
     psArray *peaks = detections->peaks;
@@ -233,5 +231,5 @@
     // note: this uses the Ohana allocation tools:
     // ALLOCATE (overlay, KiiOverlay, 3*peaks->n + 1);
-    ALLOCATE (overlay, KiiOverlay, peaks->n);
+    ALLOCATE (overlay, KiiOverlay, peaks->n + 2);
 
     Noverlay = 0;
@@ -271,10 +269,10 @@
     }
 
-# if (0)
+# if (1)
     overlay[Noverlay].type = KII_OVERLAY_BOX;
     overlay[Noverlay].x = 10.0;
     overlay[Noverlay].y = 10.0;
-    overlay[Noverlay].dx = 0.5;
-    overlay[Noverlay].dy = 0.5;
+    overlay[Noverlay].dx = 1.0;
+    overlay[Noverlay].dy = 1.0;
     overlay[Noverlay].angle = 0.0;
     overlay[Noverlay].text = NULL;
@@ -285,11 +283,5 @@
     FREE (overlay);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -302,8 +294,6 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa == -1) {
-        fprintf (stderr, "kapa not opened, skipping\n");
-        return false;
-    }
+    int kapa = psphotKapaChannel (1);
+    if (kapa == -1) return false;
 
     psArray *footprints = detections->footprints;
@@ -325,4 +315,5 @@
 
         // draw the top
+	// XXX need to allow top (and bottom) to have more than one span
         span = footprint->spans->data[0];
         overlay[Noverlay].type = KII_OVERLAY_LINE;
@@ -399,11 +390,5 @@
     FREE (overlay);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -419,8 +404,9 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa == -1) {
-        fprintf (stderr, "kapa not opened, skipping\n");
-        return false;
-    }
+    int kapa = psphotKapaChannel (1);
+    if (kapa == -1) return false;
+
+    // XXX mark the different source classes with different color/shape dots
+    // XXX are moments S/N and peak S/N consistent?
 
     // note: this uses the Ohana allocation tools:
@@ -448,5 +434,7 @@
         overlay[Noverlay].dx = 2.0*axes.major;
         overlay[Noverlay].dy = 2.0*axes.minor;
-        overlay[Noverlay].angle = -axes.theta * PS_DEG_RAD;  // XXXXXXXX the axes angle is negative to display of object on kapa
+
+        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
+
         overlay[Noverlay].text = NULL;
         Noverlay ++;
@@ -456,12 +444,5 @@
     FREE (overlay);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
-
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -475,22 +456,16 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa3 == -1) {
-        kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
-        if (kapa3 == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
-
-    KapaClearPlots (kapa3);
+    int myKapa = psphotKapaChannel (2);
+    if (myKapa == -1) return false;
+
+    KapaClearPlots (myKapa);
     KapaInitGraph (&graphdata);
-    KapaSetFont (kapa3, "courier", 14);
+    KapaSetFont (myKapa, "courier", 14);
 
     float SN_LIM = psMetadataLookupF32(&status, recipe, "PSF_SN_LIM");
 
     // select the max psfX,Y values for the plot limits
-    float Xmin = 0.0, Xmax = 0.0;
-    float Ymin = 0.0, Ymax = 0.0;
+    float Xmin = 1000.0, Xmax = 0.0;
+    float Ymin = 1000.0, Ymax = 0.0;
     {
         int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
@@ -511,10 +486,12 @@
 	    float Y1 = psfY + 4.0*psfdY;
 
-	    if (isfinite(X0)) { Xmin = PS_MAX(Xmin, X0); }
+	    if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
 	    if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
-	    if (isfinite(Y0)) { Ymin = PS_MAX(Ymin, Y0); }
+	    if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
 	    if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
         }
     }
+    Xmin = PS_MAX(Xmin, -0.1); 
+    Ymin = PS_MAX(Ymin, -0.1); 
 
     // storage vectors for data to be plotted
@@ -564,5 +541,5 @@
     section.y  = 0.00;
     section.name = psStringCopy ("MxxMyy");
-    KapaSetSection (kapa3, &section);
+    KapaSetSection (myKapa, &section);
     psFree (section.name);
 
@@ -572,9 +549,9 @@
     graphdata.xmax = Xmax;
     graphdata.ymax = Ymax;
-    KapaSetLimits (kapa3, &graphdata);
-
-    KapaBox (kapa3, &graphdata);
-    KapaSendLabel (kapa3, "M_xx| (pixels)", KAPA_LABEL_XM);
-    KapaSendLabel (kapa3, "M_yy| (pixels)", KAPA_LABEL_YM);
+    KapaSetLimits (myKapa, &graphdata);
+
+    KapaBox (myKapa, &graphdata);
+    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
+    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
 
     graphdata.color = KapaColorByName ("black");
@@ -582,7 +559,7 @@
     graphdata.size = 0.3;
     graphdata.style = 2;
-    KapaPrepPlot (kapa3, nF, &graphdata);
-    KapaPlotVector (kapa3, nF, xFaint->data.F32, "x");
-    KapaPlotVector (kapa3, nF, yFaint->data.F32, "y");
+    KapaPrepPlot (myKapa, nF, &graphdata);
+    KapaPlotVector (myKapa, nF, xFaint->data.F32, "x");
+    KapaPlotVector (myKapa, nF, yFaint->data.F32, "y");
 
     graphdata.color = KapaColorByName ("red");
@@ -590,7 +567,7 @@
     graphdata.size = 0.5;
     graphdata.style = 2;
-    KapaPrepPlot (kapa3, nB, &graphdata);
-    KapaPlotVector (kapa3, nB, xBright->data.F32, "x");
-    KapaPlotVector (kapa3, nB, yBright->data.F32, "y");
+    KapaPrepPlot (myKapa, nB, &graphdata);
+    KapaPlotVector (myKapa, nB, xBright->data.F32, "x");
+    KapaPlotVector (myKapa, nB, yBright->data.F32, "y");
 
     // second section: MagMyy
@@ -600,5 +577,5 @@
     section.y  = 0.80;
     section.name = psStringCopy ("MagMyy");
-    KapaSetSection (kapa3, &section);
+    KapaSetSection (myKapa, &section);
     psFree (section.name);
 
@@ -608,10 +585,10 @@
     graphdata.ymin = Ymin;
     graphdata.ymax = Ymax;
-    KapaSetLimits (kapa3, &graphdata);
+    KapaSetLimits (myKapa, &graphdata);
 
     strcpy (graphdata.labels, "0210");
-    KapaBox (kapa3, &graphdata);
-    KapaSendLabel (kapa3, "inst mag", KAPA_LABEL_XP);
-    KapaSendLabel (kapa3, "M_yy| (pixels)", KAPA_LABEL_YM);
+    KapaBox (myKapa, &graphdata);
+    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XP);
+    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
 
     graphdata.color = KapaColorByName ("black");
@@ -619,7 +596,7 @@
     graphdata.size = 0.3;
     graphdata.style = 2;
-    KapaPrepPlot (kapa3, nF, &graphdata);
-    KapaPlotVector (kapa3, nF, mFaint->data.F32, "x");
-    KapaPlotVector (kapa3, nF, yFaint->data.F32, "y");
+    KapaPrepPlot (myKapa, nF, &graphdata);
+    KapaPlotVector (myKapa, nF, mFaint->data.F32, "x");
+    KapaPlotVector (myKapa, nF, yFaint->data.F32, "y");
 
     graphdata.color = KapaColorByName ("red");
@@ -627,7 +604,7 @@
     graphdata.size = 0.5;
     graphdata.style = 2;
-    KapaPrepPlot (kapa3, nB, &graphdata);
-    KapaPlotVector (kapa3, nB, mBright->data.F32, "x");
-    KapaPlotVector (kapa3, nB, yBright->data.F32, "y");
+    KapaPrepPlot (myKapa, nB, &graphdata);
+    KapaPlotVector (myKapa, nB, mBright->data.F32, "x");
+    KapaPlotVector (myKapa, nB, yBright->data.F32, "y");
 
     // third section: MagMxx
@@ -637,5 +614,5 @@
     section.y  = 0.00;
     section.name = psStringCopy ("MagMxx");
-    KapaSetSection (kapa3, &section);
+    KapaSetSection (myKapa, &section);
     psFree (section.name);
 
@@ -645,10 +622,10 @@
     graphdata.ymin =  -7.9;
     graphdata.ymax = -17.1;
-    KapaSetLimits (kapa3, &graphdata);
+    KapaSetLimits (myKapa, &graphdata);
 
     strcpy (graphdata.labels, "2001");
-    KapaBox (kapa3, &graphdata);
-    KapaSendLabel (kapa3, "M_xx| (pixels)", KAPA_LABEL_XM);
-    KapaSendLabel (kapa3, "inst mag", KAPA_LABEL_YP);
+    KapaBox (myKapa, &graphdata);
+    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
+    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_YP);
 
     graphdata.color = KapaColorByName ("black");
@@ -656,7 +633,7 @@
     graphdata.size = 0.3;
     graphdata.style = 2;
-    KapaPrepPlot (kapa3, nF, &graphdata);
-    KapaPlotVector (kapa3, nF, xFaint->data.F32, "x");
-    KapaPlotVector (kapa3, nF, mFaint->data.F32, "y");
+    KapaPrepPlot (myKapa, nF, &graphdata);
+    KapaPlotVector (myKapa, nF, xFaint->data.F32, "x");
+    KapaPlotVector (myKapa, nF, mFaint->data.F32, "y");
 
     graphdata.color = KapaColorByName ("red");
@@ -664,11 +641,11 @@
     graphdata.size = 0.5;
     graphdata.style = 2;
-    KapaPrepPlot (kapa3, nB, &graphdata);
-    KapaPlotVector (kapa3, nB, xBright->data.F32, "x");
-    KapaPlotVector (kapa3, nB, mBright->data.F32, "y");
+    KapaPrepPlot (myKapa, nB, &graphdata);
+    KapaPlotVector (myKapa, nB, xBright->data.F32, "x");
+    KapaPlotVector (myKapa, nB, mBright->data.F32, "y");
 
     // draw N circles to outline the clumps
     {
-        KapaSelectSection (kapa3, "MxxMyy");
+        KapaSelectSection (myKapa, "MxxMyy");
 
         // draw a circle centered on psfX,Y with size of the psf limit
@@ -686,5 +663,5 @@
 	graphdata.xmax = Xmax;
 	graphdata.ymax = Ymax;
-	KapaSetLimits (kapa3, &graphdata);
+	KapaSetLimits (myKapa, &graphdata);
 
         for (int n = 0; n < nRegions; n++) {
@@ -705,47 +682,11 @@
                 yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
             }
-            KapaPrepPlot (kapa3, xLimit->n, &graphdata);
-            KapaPlotVector (kapa3, xLimit->n, xLimit->data.F32, "x");
-            KapaPlotVector (kapa3, yLimit->n, yLimit->data.F32, "y");
+            KapaPrepPlot (myKapa, xLimit->n, &graphdata);
+            KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
+            KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
         }
         psFree (xLimit);
         psFree (yLimit);
     }
-
-# if (0)
-    // *** make a histogram of the source counts in the x and y directions
-    psHistogram *nX = psHistogramAlloc (graphdata.xmin, graphdata.xmax, 50.0);
-    psHistogram *nY = psHistogramAlloc (graphdata.ymin, graphdata.ymax, 50.0);
-    psVectorHistogram (nX, xFaint, NULL, NULL, 0);
-    psVectorHistogram (nY, yFaint, NULL, NULL, 0);
-    psVector *dX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
-    psVector *vX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
-    psVector *dY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
-    psVector *vY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
-    for (int i = 0; i < nX->nums->n; i++) {
-        dX->data.F32[i] = nX->nums->data.S32[i];
-        vX->data.F32[i] = 0.5*(nX->bounds->data.F32[i] + nX->bounds->data.F32[i+1]);
-    }
-    for (int i = 0; i < nY->nums->n; i++) {
-        dY->data.F32[i] = nY->nums->data.S32[i];
-        vY->data.F32[i] = 0.5*(nY->bounds->data.F32[i] + nY->bounds->data.F32[i+1]);
-    }
-
-    graphdata.color = KapaColorByName ("black");
-    graphdata.ptype = 0;
-    graphdata.size = 0.0;
-    graphdata.style = 0;
-    KapaPrepPlot (kapa3, dX->n, &graphdata);
-    KapaPlotVector (kapa3, dX->n, dX->data.F32, "x");
-    KapaPlotVector (kapa3, vX->n, vX->data.F32, "y");
-
-    psFree (nX);
-    psFree (dX);
-    psFree (vX);
-
-    psFree (nY);
-    psFree (dY);
-    psFree (vY);
-# endif
 
     psFree (xBright);
@@ -756,16 +697,10 @@
     psFree (mFaint);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    pmVisualAskUser(NULL);
     return true;
 }
 
 // assumes 'kapa' value is checked and set
-bool psphotVisualShowRoughClass_Single (psArray *sources, pmSourceType type, pmSourceMode mode, char *color) {
+bool psphotVisualShowRoughClass_Single (int myKapa, psArray *sources, pmSourceType type, pmSourceMode mode, char *color) {
 
     int Noverlay;
@@ -802,10 +737,10 @@
         overlay[Noverlay].dx = 2.0*axes.major;
         overlay[Noverlay].dy = 2.0*axes.minor;
-        overlay[Noverlay].angle = -axes.theta * PS_DEG_RAD;
+        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
         overlay[Noverlay].text = NULL;
         Noverlay ++;
     }
 
-    KiiLoadOverlay (kapa, overlay, Noverlay, color);
+    KiiLoadOverlay (myKapa, overlay, Noverlay, color);
     FREE (overlay);
 
@@ -817,26 +752,18 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa == -1) {
-        fprintf (stderr, "kapa not opened, skipping\n");
-        return false;
-    }
-
-    KiiEraseOverlay (kapa, "yellow"); // moments
-
-    psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, 0, "red");
-    psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_EXTENDED, 0, "blue");
-    psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_DEFECT, 0, "blue");
-    psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_SATURATED, 0, "red");
-    psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_PSFSTAR, "yellow");
-    psphotVisualShowRoughClass_Single (sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_SATSTAR, "green");
-
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
+    int myKapa = psphotKapaChannel (1);
+    if (myKapa == -1) return false;
+
+    KiiEraseOverlay (myKapa, "yellow"); // moments
+
+    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, 0, "red");
+    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_EXTENDED, 0, "blue");
+    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_DEFECT, 0, "blue");
+    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_SATURATED, 0, "red");
+    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_PSFSTAR, "yellow");
+    psphotVisualShowRoughClass_Single (myKapa, sources, PM_SOURCE_TYPE_STAR, PM_SOURCE_MODE_SATSTAR, "green");
+
     fprintf (stdout, "red: STAR or SAT AREA; blue: EXTENDED or DEFECT; green: SATSTAR; yellow: PSFSTAR\n");
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -846,12 +773,6 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa2 == -1) {
-        kapa2 = KapaOpenNamedSocket ("kapa", "psphot:psfstars");
-        if (kapa2 == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
+    int myKapa = psphotKapaChannel (3);
+    if (myKapa == -1) return false;
 
     int DX = 64;
@@ -898,7 +819,7 @@
 
     psImage *psfLogFlux = (psImage *) psUnaryOp (NULL, psfMosaic, "log");
-    psphotVisualRangeImage (kapa2, psfLogFlux, "psf_mosaic",    0, -2.0, 3.0);
-    psphotVisualRangeImage (kapa2, funMosaic, "psf_analytical", 1, -10.0, 100.0);
-    psphotVisualRangeImage (kapa2, resMosaic, "psf_residual",   2, -10.0, 100.0);
+    psphotVisualRangeImage (myKapa, psfLogFlux, "psf_mosaic",    0, -2.0, 3.0);
+    psphotVisualRangeImage (myKapa, funMosaic, "psf_analytical", 1, -10.0, 100.0);
+    psphotVisualRangeImage (myKapa, resMosaic, "psf_residual",   2, -10.0, 100.0);
 
     psFree (psfMosaic);
@@ -908,11 +829,5 @@
     psFree (modelRef);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -924,12 +839,6 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa2 == -1) {
-        kapa2 = KapaOpenNamedSocket ("kapa", "psphot:psfstars");
-        if (kapa2 == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
+    int myKapa = psphotKapaChannel (3);
+    if (myKapa == -1) return false;
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
@@ -1017,10 +926,12 @@
             if (Xo == 0) {
                 // place source alone on this row
-                psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+		bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+		if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
                 psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
 
-                psphotSubWithTest (source, false, maskVal); // remove source (force)
+		pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
                 psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
-                psphotSetState (source, false, maskVal); // reset source Add/Sub state to recorded
+
+		if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
 
                 Yo += DY;
@@ -1032,10 +943,12 @@
                 Xo = 0;
 
-                psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+		bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+		if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
                 psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
 
-                psphotSubWithTest (source, false, maskVal); // remove source (force)
+		pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
                 psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
-                psphotSetState (source, false, maskVal); // replace source (has been subtracted)
+
+		if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
 
                 Xo = DX;
@@ -1044,10 +957,11 @@
         } else {
             // extend this row
-            psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+	    bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+	    if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
             psphotMosaicSubimage (outpos, source, Xo, Yo, DX, DY, true);
 
-            psphotSubWithTest (source, false, maskVal); // remove source (force)
+	    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
             psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
-            psphotSetState (source, false, maskVal); // replace source (has been subtracted)
+	    if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
 
             Xo += DX;
@@ -1056,15 +970,8 @@
     }
 
-    psphotVisualRangeImage (kapa2, outpos, "psfpos", 0, -0.05, 0.95);
-    psphotVisualRangeImage (kapa2, outsub, "psfsub", 1, -0.05, 0.95);
-
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
-
+    psphotVisualRangeImage (myKapa, outpos, "psfpos", 0, -0.05, 0.95);
+    psphotVisualRangeImage (myKapa, outsub, "psfsub", 1, -0.05, 0.95);
+
+    pmVisualAskUser(NULL);
     psFree (outpos);
     psFree (outsub);
@@ -1084,12 +991,6 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa2 == -1) {
-        kapa2 = KapaOpenNamedSocket ("kapa", "psphot:images");
-        if (kapa2 == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
+    int myKapa = psphotKapaChannel (3);
+    if (myKapa == -1) return false;
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
@@ -1119,7 +1020,7 @@
         pmSource *source = sources->data[i];
 
-        bool keep = false;
-        keep |= (source->mode & PM_SOURCE_MODE_SATSTAR);
-        if (!keep) continue;
+	// only show "real" saturated stars (not defects)
+        if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
+        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
 
         // how does this subimage get placed into the output image?
@@ -1164,10 +1065,8 @@
         pmSource *source = sources->data[i];
 
-        bool keep = false;
-        if (source->mode & PM_SOURCE_MODE_SATSTAR) {
-            nSAT ++;
-            keep = true;
-        }
-        if (!keep) continue;
+	// only show "real" saturated stars (not defects)
+        if (!(source->mode & PM_SOURCE_MODE_SATSTAR)) continue;;
+        if (source->mode & PM_SOURCE_MODE_DEFECT) continue;;
+	nSAT ++;
 
         if (Xo + DX > NX) {
@@ -1175,7 +1074,8 @@
             if (Xo == 0) {
                 // place source alone on this row
-                psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+		bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+		if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
                 psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
-                psphotSetState (source, true, maskVal); // reset source Add/Sub state to recorded
+		if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
 
                 Yo += DY;
@@ -1186,7 +1086,9 @@
                 Yo += dY;
                 Xo = 0;
-                psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+
+		bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+		if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
                 psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
-                psphotSetState (source, true, maskVal); // replace source (has been subtracted)
+		if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
 
                 Xo = DX;
@@ -1195,7 +1097,8 @@
         } else {
             // extend this row
-            psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+	    bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+	    if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
             psphotMosaicSubimage (outsat, source, Xo, Yo, DX, DY, false);
-            psphotSetState (source, true, maskVal); // replace source (has been subtracted)
+	    if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
 
             Xo += DX;
@@ -1204,14 +1107,7 @@
     }
 
-    psphotVisualScaleImage (kapa2, outsat, "satstar", 2);
-
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
-
+    psphotVisualScaleImage (myKapa, outsat, "satstar", 2);
+
+    pmVisualAskUser(NULL);
     psFree (outsat);
     return true;
@@ -1222,6 +1118,6 @@
     Graphdata graphdata;
 
-    bool state = !(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
-    psphotAddWithTest (source, true, maskVal); // replace source if subtracted
+    bool subtracted = (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED);
+    if (subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
 
     int nPts = source->pixels->numRows * source->pixels->numCols;
@@ -1240,12 +1136,12 @@
         for (int ix = 0; ix < source->pixels->numCols; ix++) {
             if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix]) {
-                // rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
-                rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
+                rb->data.F32[nb] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
+                // rb->data.F32[nb] = hypot (ix - Xo, iy - Yo) ;
                 Rb->data.F32[nb] = log10(rb->data.F32[nb]);
                 fb->data.F32[nb] = log10(source->pixels->data.F32[iy][ix]);
                 nb++;
             } else {
-                // rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
-                rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ;
+                rg->data.F32[ng] = hypot (ix + 0.5 - Xo, iy + 0.5 - Yo) ;
+                // rg->data.F32[ng] = hypot (ix - Xo, iy - Yo) ;
                 Rg->data.F32[ng] = log10(rg->data.F32[ng]);
                 fg->data.F32[ng] = log10(source->pixels->data.F32[iy][ix]);
@@ -1256,5 +1152,5 @@
 
     // reset source Add/Sub state to recorded
-    psphotSetState (source, state, maskVal);
+    if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
 
     KapaInitGraph (&graphdata);
@@ -1337,12 +1233,6 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa3 == -1) {
-        kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
-        if (kapa3 == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
+    int myKapa = psphotKapaChannel (2);
+    if (myKapa == -1) return false;
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
@@ -1351,5 +1241,5 @@
     assert (maskVal);
 
-    KapaClearPlots (kapa3);
+    KapaClearPlots (myKapa);
     // first section : mag vs CR nSigma
     section.dx = 1.0;
@@ -1359,5 +1249,5 @@
     section.name = NULL;
     psStringAppend (&section.name, "linlog");
-    KapaSetSection (kapa3, &section);
+    KapaSetSection (myKapa, &section);
     psFree (section.name);
 
@@ -1369,5 +1259,5 @@
     section.name = NULL;
     psStringAppend (&section.name, "loglog");
-    KapaSetSection (kapa3, &section);
+    KapaSetSection (myKapa, &section);
     psFree (section.name);
 
@@ -1378,5 +1268,5 @@
         if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
 
-        psphotVisualPlotRadialProfile (kapa3, source, maskVal);
+        psphotVisualPlotRadialProfile (myKapa, source, maskVal);
 
         // pause and wait for user input:
@@ -1388,5 +1278,5 @@
         }
         if (key[0] == 'e') {
-            KapaClearPlots (kapa3);
+            KapaClearPlots (myKapa);
         }
         if (key[0] == 's') {
@@ -1407,10 +1297,11 @@
     psEllipseAxes axes;
 
+    // XXX skip this for now: it is not very clear
+    return true;
+
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa == -1) {
-        fprintf (stderr, "kapa not opened, skipping\n");
-        return false;
-    }
+    int myKapa = psphotKapaChannel (1);
+    if (myKapa == -1) return false;
 
     // note: this uses the Ohana allocation tools:
@@ -1485,40 +1376,28 @@
     }
 
-    KiiLoadOverlay (kapa, overlayE, NoverlayE, "red");
-    KiiLoadOverlay (kapa, overlayO, NoverlayO, "yellow");
+    KiiLoadOverlay (myKapa, overlayE, NoverlayE, "red");
+    KiiLoadOverlay (myKapa, overlayO, NoverlayO, "yellow");
     FREE (overlayE);
     FREE (overlayO);
 
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
     fprintf (stdout, "even bits (0x0001, 0x0004, ... : red\n");
     fprintf (stdout, "odd bits (0x0002, 0x0008, ... : yellow\n");
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
-
-    return true;
-}
-
-bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources) {
-
-    int Noverlay, NOVERLAY;
+    pmVisualAskUser(NULL);
+
+    return true;
+}
+
+bool psphotVisualShowSourceSize_Single (int myKapa, psArray *sources, pmSourceMode mode, bool keep, float scale, char *color) {
+
+    int Noverlay;
     KiiOverlay *overlay;
 
-    if (!pmVisualIsVisual()) return true;
-
-    if (kapa == -1) {
-        fprintf (stderr, "kapa not opened, skipping\n");
-        return false;
-    }
+    psEllipseMoments emoments;
+    psEllipseAxes axes;
 
     // note: this uses the Ohana allocation tools:
+    ALLOCATE (overlay, KiiOverlay, sources->n);
+
     Noverlay = 0;
-    NOVERLAY = 100;
-    ALLOCATE (overlay, KiiOverlay, sources->n);
-
-    // mark CRs with red boxes
     for (int i = 0; i < sources->n; i++) {
 
@@ -1526,60 +1405,65 @@
         if (source == NULL) continue;
 
-        if (!(source->mode & PM_SOURCE_MODE_CR_LIMIT)) continue;
-
-        overlay[Noverlay].type = KII_OVERLAY_BOX;
-        overlay[Noverlay].x = source->peak->xf;
-        overlay[Noverlay].y = source->peak->yf;
-
-        overlay[Noverlay].dx = 4;
-        overlay[Noverlay].dy = 4;
-        overlay[Noverlay].angle = 0;
+        // if (source->type != type) continue;
+	if (mode) {
+	    if (keep) {
+		if (!(source->mode & mode)) continue;
+	    } else {
+		if (source->mode & mode) continue;
+	    }
+	}
+
+        pmMoments *moments = source->moments;
+        if (moments == NULL) continue;
+
+        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
+        overlay[Noverlay].x = moments->Mx;
+        overlay[Noverlay].y = moments->My;
+
+        emoments.x2 = moments->Mxx;
+        emoments.y2 = moments->Myy;
+        emoments.xy = moments->Mxy;
+
+        axes = psEllipseMomentsToAxes (emoments, 20.0);
+
+        overlay[Noverlay].dx = scale*2.0*axes.major;
+        overlay[Noverlay].dy = scale*2.0*axes.minor;
+        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
         overlay[Noverlay].text = NULL;
         Noverlay ++;
-        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
-    }
-    KiiLoadOverlay (kapa, overlay, Noverlay, "red");
-
-
-    Noverlay = 0;
-    for (int i = 0; i < sources->n; i++) {
-
-        pmSource *source = sources->data[i];
-        if (source == NULL) continue;
-
-        // mark EXTs with yellow circles
-        if (!(source->mode & PM_SOURCE_MODE_EXT_LIMIT)) continue;
-
-        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
-        overlay[Noverlay].x = source->peak->xf;
-        overlay[Noverlay].y = source->peak->yf;
-
-        overlay[Noverlay].dx = 10;
-        overlay[Noverlay].dy = 10;
-        overlay[Noverlay].angle = 0;
-        overlay[Noverlay].text = NULL;
-        Noverlay ++;
-        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
-    }
-
-    KiiLoadOverlay (kapa, overlay, Noverlay, "blue");
+    }
+
+    KiiLoadOverlay (myKapa, overlay, Noverlay, color);
     FREE (overlay);
 
-    psphotVisualShowMask (kapa, readout->mask, "mask", 2);
-
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "CR: 4pix red BOX; EXT: 10pix blue circle\n");
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
-
-    return true;
-}
-
-bool psphotVisualPlotSourceSize (psArray *sources) {
-
+    return true;
+}
+
+bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources) {
+
+    if (!pmVisualIsVisual()) return true;
+
+    int myKapa = psphotKapaChannel (1);
+    if (myKapa == -1) return false;
+
+    KiiEraseOverlay (myKapa, "red");
+    KiiEraseOverlay (myKapa, "blue");
+    KiiEraseOverlay (myKapa, "green");
+    KiiEraseOverlay (myKapa, "yellow");
+
+    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_EXT_LIMIT | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_SATSTAR, 0, 1.0, "green");
+    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_EXT_LIMIT, 1, 1.0, "blue");
+    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_CR_LIMIT, 1, 1.0, "red");
+    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_DEFECT, 1, 2.0, "red");
+    psphotVisualShowSourceSize_Single (myKapa, sources, PM_SOURCE_MODE_SATSTAR, 1, 1.0, "yellow");
+
+    fprintf (stdout, "red: CR; blue: EXTENDED; green: PSF-like; yellow: SATSTAR\n");
+    pmVisualAskUser(NULL);
+    return true;
+}
+
+bool psphotVisualPlotSourceSize (psMetadata *recipe, psArray *sources) {
+
+    bool status;
     Graphdata graphdata;
     KapaSection section;
@@ -1587,185 +1471,484 @@
     if (!pmVisualIsVisual()) return true;
 
-    if (kapa3 == -1) {
-        kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
-        if (kapa3 == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
+    int myKapa = psphotKapaChannel (2);
+    if (myKapa == -1) return false;
+
+    KapaClearPlots (myKapa);
+    KapaInitGraph (&graphdata);
+    KapaSetFont (myKapa, "courier", 14);
+
+    // select the max psfX,Y values for the plot limits
+    float Xmin = 1000.0, Xmax = 0.0;
+    float Ymin = 1000.0, Ymax = 0.0;
+    {
+        int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
+        for (int n = 0; n < nRegions; n++) {
+
+            char regionName[64];
+            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
+            psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
+
+	    float psfX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
+            float psfY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
+            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
+            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
+
+	    float X0 = psfX - 10.0*psfdX;
+	    float X1 = psfX + 10.0*psfdX;
+	    float Y0 = psfY - 10.0*psfdY;
+	    float Y1 = psfY + 10.0*psfdY;
+
+	    if (isfinite(X0)) { Xmin = PS_MIN(Xmin, X0); }
+	    if (isfinite(X1)) { Xmax = PS_MAX(Xmax, X1); }
+	    if (isfinite(Y0)) { Ymin = PS_MIN(Ymin, Y0); }
+	    if (isfinite(Y1)) { Ymax = PS_MAX(Ymax, Y1); }
         }
     }
-
-    KapaClearPlots (kapa3);
+    Xmin = PS_MAX(Xmin, -0.1); 
+    Ymin = PS_MAX(Ymin, -0.1); 
+
+    // storage vectors for data to be plotted
+    psVector *xSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *ySAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *mSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *sSAT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+
+    psVector *xPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *yPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *mPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *sPSF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+
+    psVector *xEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *yEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *mEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *sEXT = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+
+    psVector *xDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *yDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *mDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *sDEF = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+
+    psVector *xCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *yCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *mCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *sCR = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+
+    // construct the vectors
+    int nSAT = 0;
+    int nEXT = 0;
+    int nPSF = 0;
+    int nDEF = 0;
+    int nCR  = 0;
+    for (int i = 0; i < sources->n; i++) {
+        pmSource *source = sources->data[i];
+        if (source->moments == NULL) continue;
+
+	if (source->mode & PM_SOURCE_MODE_CR_LIMIT) { 
+	    xCR->data.F32[nCR] = source->moments->Mxx;
+	    yCR->data.F32[nCR] = source->moments->Myy;
+	    mCR->data.F32[nCR] = -2.5*log10(source->moments->Sum);
+	    sCR->data.F32[nCR] = source->extNsigma;
+	    nCR++;
+	}
+	if (source->mode & PM_SOURCE_MODE_SATSTAR) { 
+	    xSAT->data.F32[nSAT] = source->moments->Mxx;
+	    ySAT->data.F32[nSAT] = source->moments->Myy;
+	    mSAT->data.F32[nSAT] = -2.5*log10(source->moments->Sum);
+	    sSAT->data.F32[nSAT] = source->extNsigma;
+	    nSAT++;
+	}
+	if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) { 
+	    xEXT->data.F32[nEXT] = source->moments->Mxx;
+	    yEXT->data.F32[nEXT] = source->moments->Myy;
+	    mEXT->data.F32[nEXT] = -2.5*log10(source->moments->Sum);
+	    sEXT->data.F32[nEXT] = source->extNsigma;
+	    nEXT++;
+	    continue;
+	}
+	if (source->mode & PM_SOURCE_MODE_DEFECT) { 
+	    xDEF->data.F32[nDEF] = source->moments->Mxx;
+	    yDEF->data.F32[nDEF] = source->moments->Myy;
+	    mDEF->data.F32[nDEF] = -2.5*log10(source->moments->Sum);
+	    sDEF->data.F32[nDEF] = source->extNsigma;
+	    nDEF++;
+	    continue;
+	}
+	if ((source->mode & PM_SOURCE_MODE_CR_LIMIT) || (source->mode & PM_SOURCE_MODE_SATSTAR)) {
+	    continue;
+	}
+	xPSF->data.F32[nPSF] = source->moments->Mxx;
+	yPSF->data.F32[nPSF] = source->moments->Myy;
+	mPSF->data.F32[nPSF] = -2.5*log10(source->moments->Sum);
+	sPSF->data.F32[nPSF] = source->extNsigma;
+	nPSF++;
+    }
+    xSAT->n = nSAT;
+    ySAT->n = nSAT;
+    mSAT->n = nSAT;
+    sSAT->n = nSAT;
+
+    xPSF->n = nPSF;
+    yPSF->n = nPSF;
+    mPSF->n = nPSF;
+    sPSF->n = nPSF;
+
+    xEXT->n = nEXT;
+    yEXT->n = nEXT;
+    mEXT->n = nEXT;
+    sEXT->n = nEXT;
+
+    xCR->n = nCR;
+    yCR->n = nCR;
+    mCR->n = nCR;
+    sCR->n = nCR;
+
+    xDEF->n = nDEF;
+    yDEF->n = nDEF;
+    mDEF->n = nDEF;
+    sDEF->n = nDEF;
+
+    // four sections: MxxMyy, MagMxx, MagMyy, MagSigma
+
+    // first section: MxxMyy
+    section.dx = 0.75;
+    section.dy = 0.60;
+    section.x  = 0.00;
+    section.y  = 0.00;
+    section.name = psStringCopy ("MxxMyy");
+    KapaSetSection (myKapa, &section);
+    psFree (section.name);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.xmin = Xmin;
+    graphdata.ymin = Ymin;
+    graphdata.xmax = Xmax;
+    graphdata.ymax = Ymax;
+    KapaSetLimits (myKapa, &graphdata);
+
+    KapaBox (myKapa, &graphdata);
+    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
+    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nPSF, &graphdata);
+    KapaPlotVector (myKapa, nPSF, xPSF->data.F32, "x");
+    KapaPlotVector (myKapa, nPSF, yPSF->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nEXT, &graphdata);
+    KapaPlotVector (myKapa, nEXT, xEXT->data.F32, "x");
+    KapaPlotVector (myKapa, nEXT, yEXT->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nDEF, &graphdata);
+    KapaPlotVector (myKapa, nDEF, xDEF->data.F32, "x");
+    KapaPlotVector (myKapa, nDEF, yDEF->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 7;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nCR, &graphdata);
+    KapaPlotVector (myKapa, nCR, xCR->data.F32, "x");
+    KapaPlotVector (myKapa, nCR, yCR->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 7;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nSAT, &graphdata);
+    KapaPlotVector (myKapa, nSAT, xSAT->data.F32, "x");
+    KapaPlotVector (myKapa, nSAT, ySAT->data.F32, "y");
+
+    // second section: MagMyy
+    section.dx = 0.75;
+    section.dy = 0.20;
+    section.x  = 0.00;
+    section.y  = 0.80;
+    section.name = psStringCopy ("MagMyy");
+    KapaSetSection (myKapa, &section);
+    psFree (section.name);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.xmin = -17.1;
+    graphdata.xmax =  -7.9;
+    graphdata.ymin = Ymin;
+    graphdata.ymax = Ymax;
+    KapaSetLimits (myKapa, &graphdata);
+
+    strcpy (graphdata.labels, "0210");
+    KapaBox (myKapa, &graphdata);
+    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XP);
+    KapaSendLabel (myKapa, "M_yy| (pixels)", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nPSF, &graphdata);
+    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "x");
+    KapaPlotVector (myKapa, nPSF, yPSF->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nEXT, &graphdata);
+    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "x");
+    KapaPlotVector (myKapa, nEXT, yEXT->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nDEF, &graphdata);
+    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "x");
+    KapaPlotVector (myKapa, nDEF, yDEF->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 7;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nCR, &graphdata);
+    KapaPlotVector (myKapa, nCR, mCR->data.F32, "x");
+    KapaPlotVector (myKapa, nCR, yCR->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 7;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nSAT, &graphdata);
+    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "x");
+    KapaPlotVector (myKapa, nSAT, ySAT->data.F32, "y");
+
+    // third section: MagMxx
+    section.dx = 0.25;
+    section.dy = 0.60;
+    section.x  = 0.80;
+    section.y  = 0.00;
+    section.name = psStringCopy ("MagMxx");
+    KapaSetSection (myKapa, &section);
+    psFree (section.name);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.xmin = Xmin;
+    graphdata.xmax = Xmax;
+    graphdata.ymin =  -7.9;
+    graphdata.ymax = -17.1;
+    KapaSetLimits (myKapa, &graphdata);
+
+    strcpy (graphdata.labels, "2001");
+    KapaBox (myKapa, &graphdata);
+    KapaSendLabel (myKapa, "M_xx| (pixels)", KAPA_LABEL_XM);
+    KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_YP);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nPSF, &graphdata);
+    KapaPlotVector (myKapa, nPSF, xPSF->data.F32, "x");
+    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nEXT, &graphdata);
+    KapaPlotVector (myKapa, nEXT, xEXT->data.F32, "x");
+    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nDEF, &graphdata);
+    KapaPlotVector (myKapa, nDEF, xDEF->data.F32, "x");
+    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 7;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nCR, &graphdata);
+    KapaPlotVector (myKapa, nCR, xCR->data.F32, "x");
+    KapaPlotVector (myKapa, nCR, mCR->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 7;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nSAT, &graphdata);
+    KapaPlotVector (myKapa, nSAT, xSAT->data.F32, "x");
+    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "y");
+
+    // fourth section: MagSigma
+    section.dx = 0.75;
+    section.dy = 0.15;
+    section.x  = 0.00;
+    section.y  = 0.65;
+    section.name = psStringCopy ("MagSigma");
+    KapaSetSection (myKapa, &section);
+    psFree (section.name);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.xmax =  -7.9;
+    graphdata.xmin = -17.1;
+    graphdata.ymin = -20.1;
+    graphdata.ymax = +20.1;
+    KapaSetLimits (myKapa, &graphdata);
+
+    strcpy (graphdata.labels, "0100");
+    KapaBox (myKapa, &graphdata);
+    // KapaSendLabel (myKapa, "inst mag", KAPA_LABEL_XM);
+    KapaSendLabel (myKapa, "EXT&ss&c", KAPA_LABEL_YM);
+
+    graphdata.color = KapaColorByName ("black");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nPSF, &graphdata);
+    KapaPlotVector (myKapa, nPSF, mPSF->data.F32, "x");
+    KapaPlotVector (myKapa, nPSF, sPSF->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nEXT, &graphdata);
+    KapaPlotVector (myKapa, nEXT, mEXT->data.F32, "x");
+    KapaPlotVector (myKapa, nEXT, sEXT->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nDEF, &graphdata);
+    KapaPlotVector (myKapa, nDEF, mDEF->data.F32, "x");
+    KapaPlotVector (myKapa, nDEF, sDEF->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 7;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nCR, &graphdata);
+    KapaPlotVector (myKapa, nCR, mCR->data.F32, "x");
+    KapaPlotVector (myKapa, nCR, sCR->data.F32, "y");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 7;
+    graphdata.size = 1.0;
+    graphdata.style = 2;
+    KapaPrepPlot   (myKapa, nSAT, &graphdata);
+    KapaPlotVector (myKapa, nSAT, mSAT->data.F32, "x");
+    KapaPlotVector (myKapa, nSAT, sSAT->data.F32, "y");
+
+    // draw N circles to outline the clumps
+    {
+        KapaSelectSection (myKapa, "MxxMyy");
+
+        // draw a circle centered on psfX,Y with size of the psf limit
+        psVector *xLimit  = psVectorAlloc (120, PS_TYPE_F32);
+        psVector *yLimit  = psVectorAlloc (120, PS_TYPE_F32);
+
+        int nRegions = psMetadataLookupS32 (&status, recipe, "PSF.CLUMP.NREGIONS");
+        float PSF_CLUMP_NSIGMA = psMetadataLookupF32 (&status, recipe, "PSF_CLUMP_NSIGMA");
+
+        graphdata.color = KapaColorByName ("blue");
+        graphdata.style = 0;
+
+	graphdata.xmin = Xmin;
+	graphdata.ymin = Ymin;
+	graphdata.xmax = Xmax;
+	graphdata.ymax = Ymax;
+	KapaSetLimits (myKapa, &graphdata);
+
+        for (int n = 0; n < nRegions; n++) {
+
+            char regionName[64];
+            snprintf (regionName, 64, "PSF.CLUMP.REGION.%03d", n);
+            psMetadata *regionMD = psMetadataLookupPtr (&status, recipe, regionName);
+
+            float psfX  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.X");
+            float psfY  = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.Y");
+            float psfdX = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DX");
+            float psfdY = psMetadataLookupF32 (&status, regionMD, "PSF.CLUMP.DY");
+            float Rx = psfdX * PSF_CLUMP_NSIGMA;
+            float Ry = psfdY * PSF_CLUMP_NSIGMA;
+
+            for (int i = 0; i < xLimit->n; i++) {
+                xLimit->data.F32[i] = Rx*cos(i*2.0*M_PI/120.0) + psfX;
+                yLimit->data.F32[i] = Ry*sin(i*2.0*M_PI/120.0) + psfY;
+            }
+            KapaPrepPlot (myKapa, xLimit->n, &graphdata);
+            KapaPlotVector (myKapa, xLimit->n, xLimit->data.F32, "x");
+            KapaPlotVector (myKapa, yLimit->n, yLimit->data.F32, "y");
+        }
+        psFree (xLimit);
+        psFree (yLimit);
+    }
+
+    psFree (xSAT);
+    psFree (ySAT);
+    psFree (mSAT);
+
+    psFree (xEXT);
+    psFree (yEXT);
+    psFree (mEXT);
+
+    psFree (xPSF);
+    psFree (yPSF);
+    psFree (mPSF);
+
+    psFree (xDEF);
+    psFree (yDEF);
+    psFree (mDEF);
+
+    psFree (xCR);
+    psFree (yCR);
+    psFree (mCR);
+
+    pmVisualAskUser(NULL);
+    return true;
+}
+
+bool psphotVisualShowResidualImage (pmReadout *readout) {
+
+    if (!pmVisualIsVisual()) return true;
+
+    int myKapa = psphotKapaChannel (1);
+    if (myKapa == -1) return false;
+
+    psphotVisualScaleImage (myKapa, readout->image, "resid", 1);
+
+    pmVisualAskUser(NULL);
+    return true;
+}
+
+bool psphotVisualPlotApResid (psArray *sources, float mean, float error) {
+
+    Graphdata graphdata;
+    float lineX[2], lineY[2];
+
+    if (!pmVisualIsVisual()) return true;
+
+    int myKapa = psphotKapaChannel (2);
+    if (myKapa == -1) return false;
+
+    KapaClearPlots (myKapa);
     KapaInitGraph (&graphdata);
-
-    // first section : mag vs CR nSigma
-    section.dx = 1.0;
-    section.dy = 0.5;
-    section.x = 0.0;
-    section.y = 0.0;
-    section.name = NULL;
-    psStringAppend (&section.name, "a1");
-    KapaSetSection (kapa3, &section);
-    psFree (section.name);
 
     psVector *x = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
     psVector *y = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
-
-    graphdata.xmin = +32.0;
-    graphdata.xmax = -32.0;
-    graphdata.ymin = +32.0;
-    graphdata.ymax = -32.0;
-
-    // construct the plot vectors
-    int n = 0;
-    for (int i = 0; i < sources->n; i++) {
-        pmSource *source = sources->data[i];
-        if (!source) continue;
-        if (source->type != PM_SOURCE_TYPE_STAR) continue;
-        if (!isfinite (source->crNsigma)) continue;
-
-        x->data.F32[n] = -2.5*log10(source->peak->flux);
-        y->data.F32[n] = source->crNsigma;
-        graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
-        graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
-        graphdata.ymin = -0.5;
-        graphdata.ymax = 10.0;
-
-        n++;
-    }
-    x->n = y->n = n;
-
-    float range;
-    range = graphdata.xmax - graphdata.xmin;
-    graphdata.xmax += 0.05*range;
-    graphdata.xmin -= 0.05*range;
-
-    // XXX set the plot range to match the image
-    KapaSetLimits (kapa3, &graphdata);
-
-    KapaSetFont (kapa3, "helvetica", 14);
-    KapaBox (kapa3, &graphdata);
-    KapaSendLabel (kapa3, "Peak as Mag", KAPA_LABEL_XM);
-    KapaSendLabel (kapa3, "CR N Sigma", KAPA_LABEL_YM);
-
-    graphdata.color = KapaColorByName ("black");
-    graphdata.ptype = 2;
-    graphdata.size = 0.5;
-    graphdata.style = 2;
-    KapaPrepPlot (kapa3, n, &graphdata);
-    KapaPlotVector (kapa3, n, x->data.F32, "x");
-    KapaPlotVector (kapa3, n, y->data.F32, "y");
-
-    // second section : mag vs EXT nSigma
-    section.dx = 1.0;
-    section.dy = 0.5;
-    section.x = 0.0;
-    section.y = 0.5;
-    section.name = NULL;
-    psStringAppend (&section.name, "a2");
-    KapaSetSection (kapa3, &section);
-    psFree (section.name);
-
-    graphdata.xmin = +32.0;
-    graphdata.xmax = -32.0;
-    graphdata.ymin = +32.0;
-    graphdata.ymax = -32.0;
-
-    // construct the plot vectors
-    n = 0;
-    for (int i = 0; i < sources->n; i++) {
-        pmSource *source = sources->data[i];
-        if (!source) continue;
-        if (source->type != PM_SOURCE_TYPE_STAR) continue;
-        if (!isfinite (source->extNsigma)) continue;
-
-        x->data.F32[n] = -2.5*log10(source->peak->flux);
-        y->data.F32[n] = source->extNsigma;
-        graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
-        graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
-        graphdata.ymin = -0.5;
-        graphdata.ymax = 10.0;
-
-        n++;
-    }
-    x->n = y->n = n;
-
-    range = graphdata.xmax - graphdata.xmin;
-    graphdata.xmax += 0.05*range;
-    graphdata.xmin -= 0.05*range;
-
-    // XXX set the plot range to match the image
-    KapaSetLimits (kapa3, &graphdata);
-
-    KapaSetFont (kapa3, "helvetica", 14);
-    KapaBox (kapa3, &graphdata);
-    KapaSendLabel (kapa3, "EXT N Sigma", KAPA_LABEL_YM);
-
-    graphdata.color = KapaColorByName ("black");
-    graphdata.ptype = 2;
-    graphdata.size = 0.5;
-    graphdata.style = 2;
-    KapaPrepPlot (kapa3, n, &graphdata);
-    KapaPlotVector (kapa3, n, x->data.F32, "x");
-    KapaPlotVector (kapa3, n, y->data.F32, "y");
-
-    psFree (x);
-    psFree (y);
-
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
-    return true;
-}
-
-bool psphotVisualShowResidualImage (pmReadout *readout) {
-
-    if (!pmVisualIsVisual()) return true;
-
-    if (kapa == -1) {
-        kapa = KapaOpenNamedSocket ("kapa", "psphot:images");
-        if (kapa == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
-
-    psphotVisualScaleImage (kapa, readout->image, "resid", 1);
-
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
-    return true;
-}
-
-bool psphotVisualPlotApResid (psArray *sources) {
-
-    Graphdata graphdata;
-
-    if (!pmVisualIsVisual()) return true;
-
-    if (kapa3 == -1) {
-        kapa3 = KapaOpenNamedSocket ("kapa", "psphot:plots");
-        if (kapa3 == -1) {
-            fprintf (stderr, "failure to open kapa; visual mode disabled\n");
-            pmVisualSetVisual(false);
-            return false;
-        }
-    }
-
-    KapaClearPlots (kapa3);
-    KapaInitGraph (&graphdata);
-
-    psVector *x = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
-    psVector *y = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
+    psVector *dy = psVectorAllocEmpty (sources->n, PS_TYPE_F32);
 
     graphdata.xmin = +32.0;
@@ -1785,4 +1968,5 @@
         x->data.F32[n] = source->psfMag;
         y->data.F32[n] = source->apMag - source->psfMag;
+        dy->data.F32[n] = source->errMag;
         graphdata.xmin = PS_MIN(graphdata.xmin, x->data.F32[n]);
         graphdata.xmax = PS_MAX(graphdata.xmax, x->data.F32[n]);
@@ -1792,5 +1976,5 @@
         n++;
     }
-    x->n = y->n = n;
+    x->n = y->n = dy->n = n;
 
     float range;
@@ -1802,11 +1986,16 @@
     graphdata.ymin -= 0.05*range;
 
-    // XXX set the plot range to match the image
-    KapaSetLimits (kapa3, &graphdata);
-
-    KapaSetFont (kapa3, "helvetica", 14);
-    KapaBox (kapa3, &graphdata);
-    KapaSendLabel (kapa3, "PSF Mag", KAPA_LABEL_XM);
-    KapaSendLabel (kapa3, "Ap Mag - PSF Mag", KAPA_LABEL_YM);
+    // XXX test
+    graphdata.xmin = -17.0;
+    graphdata.xmax =  -9.0;
+    graphdata.ymin = -0.31;
+    graphdata.ymax = +0.31;
+
+    KapaSetLimits (myKapa, &graphdata);
+
+    KapaSetFont (myKapa, "helvetica", 14);
+    KapaBox (myKapa, &graphdata);
+    KapaSendLabel (myKapa, "PSF Mag", KAPA_LABEL_XM);
+    KapaSendLabel (myKapa, "Ap Mag - PSF Mag", KAPA_LABEL_YM);
 
     graphdata.color = KapaColorByName ("black");
@@ -1814,18 +2003,105 @@
     graphdata.size = 0.5;
     graphdata.style = 2;
-    KapaPrepPlot (kapa3, n, &graphdata);
-    KapaPlotVector (kapa3, n, x->data.F32, "x");
-    KapaPlotVector (kapa3, n, y->data.F32, "y");
+    graphdata.etype |= 0x01;
+    KapaPrepPlot (myKapa, n, &graphdata);
+    KapaPlotVector (myKapa, n, x->data.F32, "x");
+    KapaPlotVector (myKapa, n, y->data.F32, "y");
+    KapaPlotVector (myKapa, n, dy->data.F32, "dym");
+    KapaPlotVector (myKapa, n, dy->data.F32, "dyp");
+
+    graphdata.color = KapaColorByName ("blue");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 0;
+    graphdata.etype = 0;
+    lineX[0] = graphdata.xmin;
+    lineX[1] = graphdata.xmax;
+    lineY[0] = lineY[1] = mean;
+    KapaPrepPlot (myKapa, 2, &graphdata);
+    KapaPlotVector (myKapa, 2, lineX, "x");
+    KapaPlotVector (myKapa, 2, lineY, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 0;
+    graphdata.etype = 0;
+    lineX[0] = graphdata.xmin;
+    lineX[1] = graphdata.xmax;
+    lineY[0] = lineY[1] = mean + error;
+    KapaPrepPlot (myKapa, 2, &graphdata);
+    KapaPlotVector (myKapa, 2, lineX, "x");
+    KapaPlotVector (myKapa, 2, lineY, "y");
+
+    graphdata.color = KapaColorByName ("red");
+    graphdata.ptype = 0;
+    graphdata.size = 0.5;
+    graphdata.style = 0;
+    graphdata.etype = 0;
+    lineX[0] = graphdata.xmin;
+    lineX[1] = graphdata.xmax;
+    lineY[0] = lineY[1] = mean - error;
+    KapaPrepPlot (myKapa, 2, &graphdata);
+    KapaPlotVector (myKapa, 2, lineX, "x");
+    KapaPlotVector (myKapa, 2, lineY, "y");
 
     psFree (x);
     psFree (y);
-
-    // pause and wait for user input:
-    // continue, save (provide name), ??
-    char key[10];
-    fprintf (stdout, "[c]ontinue? ");
-    if (!fgets(key, 8, stdin)) {
-        psWarning("Unable to read option");
-    }
+    psFree (dy);
+
+    pmVisualAskUser(NULL);
+    return true;
+}
+
+bool psphotVisualShowPetrosians (psArray *sources) {
+
+    int Noverlay, NOVERLAY;
+    KiiOverlay *overlay;
+
+    if (!pmVisualIsVisual()) return true;
+
+    int kapa = psphotKapaChannel (1);
+    if (kapa == -1) return false;
+
+    Noverlay = 0;
+    NOVERLAY = 100;
+    ALLOCATE (overlay, KiiOverlay, NOVERLAY);
+
+    for (int i = 0; i < sources->n; i++) {
+	pmSource *source = sources->data[i];
+
+	if (!source) continue;
+	if (!source->extpars) continue;
+	if (!source->extpars->profile) continue;
+	if (!source->extpars->petrosian_80) continue;
+
+	pmSourceRadialProfile *profile = source->extpars->profile;
+	pmSourceExtendedFlux *petrosian = source->extpars->petrosian_80;
+
+	overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
+	overlay[Noverlay].x = source->peak->xf;
+	overlay[Noverlay].y = source->peak->yf;
+	overlay[Noverlay].dx = 2.0*petrosian->radius;
+	overlay[Noverlay].dy = 2.0*petrosian->radius*profile->axes.minor/profile->axes.major;
+	overlay[Noverlay].angle = profile->axes.theta * PS_DEG_RAD;
+	overlay[Noverlay].text = NULL;
+	Noverlay ++;
+        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
+
+	overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
+	overlay[Noverlay].x = source->peak->xf;
+	overlay[Noverlay].y = source->peak->yf;
+	overlay[Noverlay].dx = 4.0*petrosian->radius;
+	overlay[Noverlay].dy = 4.0*petrosian->radius*profile->axes.minor/profile->axes.major;
+	overlay[Noverlay].angle = profile->axes.theta * PS_DEG_RAD;
+	overlay[Noverlay].text = NULL;
+	Noverlay ++;
+        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
+    }
+
+    KiiLoadOverlay (kapa, overlay, Noverlay, "red");
+    FREE (overlay);
+
+    pmVisualAskUser(NULL);
     return true;
 }
@@ -1850,2 +2126,40 @@
 
 # endif
+
+# if (0)
+// *** make a histogram of the source counts in the x and y directions
+psHistogram *nX = psHistogramAlloc (graphdata.xmin, graphdata.xmax, 50.0);
+psHistogram *nY = psHistogramAlloc (graphdata.ymin, graphdata.ymax, 50.0);
+psVectorHistogram (nX, xFaint, NULL, NULL, 0);
+psVectorHistogram (nY, yFaint, NULL, NULL, 0);
+psVector *dX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
+psVector *vX = psVectorAlloc (nX->nums->n, PS_TYPE_F32);
+psVector *dY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
+psVector *vY = psVectorAlloc (nY->nums->n, PS_TYPE_F32);
+for (int i = 0; i < nX->nums->n; i++) {
+    dX->data.F32[i] = nX->nums->data.S32[i];
+    vX->data.F32[i] = 0.5*(nX->bounds->data.F32[i] + nX->bounds->data.F32[i+1]);
+}
+for (int i = 0; i < nY->nums->n; i++) {
+    dY->data.F32[i] = nY->nums->data.S32[i];
+    vY->data.F32[i] = 0.5*(nY->bounds->data.F32[i] + nY->bounds->data.F32[i+1]);
+}
+
+graphdata.color = KapaColorByName ("black");
+graphdata.ptype = 0;
+graphdata.size = 0.0;
+graphdata.style = 0;
+KapaPrepPlot (myKapa, dX->n, &graphdata);
+KapaPlotVector (myKapa, dX->n, dX->data.F32, "x");
+KapaPlotVector (myKapa, vX->n, vX->data.F32, "y");
+
+psFree (nX);
+psFree (dX);
+psFree (vX);
+
+psFree (nY);
+psFree (dY);
+psFree (vY);
+
+# endif
+
Index: branches/eam_branches/20090820/pstamp/scripts/Makefile.am
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/scripts/Makefile.am	(revision 25766)
@@ -4,4 +4,5 @@
 install_files = \
 	pstamp_finish.pl \
+	pstamp_insert_request.pl \
 	pstamp_job_run.pl \
 	pstamp_listjobs.pl \
@@ -10,4 +11,5 @@
 	pstamp_parser_run.pl \
 	pstamp_queue_requests.pl \
+	pstamp_request_file \
 	pstamp_results_file.pl \
 	pstamp_revert_request.pl \
Index: branches/eam_branches/20090820/pstamp/scripts/pstamp_finish.pl
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/pstamp_finish.pl	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/scripts/pstamp_finish.pl	(revision 25766)
@@ -68,4 +68,7 @@
 }
 
+if ($product eq "NULL") {
+    stop_request_and_exit($req_id, $PS_EXIT_PROG_ERROR);
+}
 
 my $outputDataStoreRoot = metadataLookupStr($ipprc->{_siteConfig}, 'DATA_STORE_ROOT');
@@ -77,12 +80,4 @@
     # set the output fileset's name to the request name.
     my $fileset = $req_name;
-
-
-    # Here we invoke the assumption that the output for the request is placed in the
-    # fileset directory directly
-#    my $out_dir = "$outputDataStoreRoot/$product/$fileset";
-
-    # now we are assuming that the output directory is the dirname of the request file
-    # XXX: put this in the database
 
     print STDERR "product: $product  REQ_NAME: $req_name $out_dir\n" if $verbose;
@@ -174,5 +169,5 @@
         my $exp_id = $job->{exp_id};
 
-        if ($fault eq $PSTAMP_DUP_REQUEST) {
+        if (($fault eq $PSTAMP_DUP_REQUEST) and ($req_name eq "NULL")) {
             # this request had a duplicate request name. We can't put the results
             # on the data store since the product name is already used
@@ -180,5 +175,4 @@
             stop_request_and_exit($req_id, $fault);
         }
-
         my ($row, $req_info, $project) = get_request_info($rows, $rownum);
 
@@ -199,5 +193,5 @@
         }
 
-        if (($job_type eq "stamp") || ($job_type eq "get_image")) {
+        if (($job_type eq "stamp") || ($job_type eq "get_image") || ($job_type eq "none")) {
             my $jreglist = "$out_dir/reglist$job_id";
             if (open JRL, "<$jreglist") {;
@@ -214,6 +208,9 @@
 
                     # ra_deg and dec_deg are the coordinates of center of the stamp
-                    # XXX: parse the stamp header to find it
-                    print $tdf "0.0|0.0|";
+                    # XXX do this more cleanly
+                    my (undef, $ra_deg, $dec_deg) = split " ", `echo $out_dir/$img_name | fields -x -1 RA_DEG DEC_DEG`;
+                    $ra_deg = 0.0 if (!$ra_deg);
+                    $dec_deg = 0.0 if (!$dec_deg);
+                    print $tdf "$ra_deg|$dec_deg|";
 
                     print $tdf "$exp_info|";
@@ -253,5 +250,5 @@
         # register the fileset
         my $command = "$dsreg --list $reglist_name --add $fileset --product $product --type PSRESULTS";
-        $command .= " --link --datapath $out_dir";
+        $command .= " --link --datapath $out_dir --ps0 $req_id";
         $command .= " --dbname $dbname" if $dbname;
 
@@ -299,5 +296,10 @@
     my $rownum = shift;
 
+    if ($rownum eq 0) {
+        my $dummy_rowinfo = "0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|";
+        return (undef, $dummy_rowinfo, "none");
+    }
     my $row = $rows->{$rownum};
+
 
     # these may be set to null during processing
@@ -306,11 +308,16 @@
     my $tess_id = $row->{TESS_ID};
     $tess_id = "null" if !$tess_id;
+    my $comment = $row->{COMMENT};
+    $comment = "null" if !$comment;
+    my $label = $row->{LABEL};
+    $label = "null" if !$label;
 
     # This is ugly, error prone and hard to change.
     # Create a results file module and provide a list of the names (we have the data in the columns)
     my $rowinfo = "$row->{PROJECT}|$row->{JOB_TYPE}|$row->{REQ_TYPE}|$row->{IMG_TYPE}|";
-    $rowinfo   .= "$row->{ID}|$tess_id|$component|$row->{OPTION_MASK}|$row->{MJD_MIN}|$row->{MJD_MAX}|";
+    $rowinfo   .= "$row->{ID}|$tess_id|$component|$label|$row->{OPTION_MASK}|$row->{MJD_MIN}|$row->{MJD_MAX}|";
     $rowinfo   .= "$row->{REQFILT}|$row->{COORD_MASK}|$row->{CENTER_X}|$row->{CENTER_Y}|";
-    $rowinfo   .= "$row->{WIDTH}|$row->{HEIGHT}";
+    $rowinfo   .= "$row->{WIDTH}|$row->{HEIGHT}|";
+    $rowinfo   .= $comment;
 
     return ($row, $rowinfo, $row->{PROJECT});
Index: branches/eam_branches/20090820/pstamp/scripts/pstamp_insert_request.pl
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/pstamp_insert_request.pl	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/scripts/pstamp_insert_request.pl	(revision 25766)
@@ -0,0 +1,143 @@
+#!/bin/env perl
+###
+#
+# create a postage stamp request
+#
+###
+
+use warnings;
+use strict;
+
+use Carp;
+use Getopt::Long qw( GetOptions );
+use Sys::Hostname;
+use File::Copy;
+use POSIX qw( strftime );
+
+my $host = hostname();
+my $verbose = 0;
+my $dbname;
+my $dbserver;
+my $tmp_req_file;
+my $workdir;
+
+GetOptions(
+    'tmp_req_file=s'=>  \$tmp_req_file,
+    'workdir=s'     =>  \$workdir,
+    'dbname=s'      =>  \$dbname,
+    'dbserver=s'    =>  \$dbserver,
+    'verbose'       =>  \$verbose,
+);
+
+die "required arguments --tmp_req_file --workdir --dbname --dbserver"
+    if( !defined($tmp_req_file) or !defined($workdir) or !defined ($dbname)
+        or !defined($dbserver));
+use IPC::Cmd 0.36 qw( can_run run );
+
+use PS::IPP::Config qw( :standard );
+
+use Cwd;
+
+my $cwd = cwd();
+
+my $missing_tools;
+
+my $pstamptool = can_run('pstamptool')  or (warn "Can't find pstamptool"  and $missing_tools = 1);
+my $pstampdump = can_run('pstampdump')  or (warn "Can't find pstampdump"  and $missing_tools = 1);
+
+if ($missing_tools) {
+    warn("Can't find required tools.");
+    exit ($PS_EXIT_CONFIG_ERROR);
+}
+
+my ($extname, $extver, $req_name);
+{
+    my $command = "$pstampdump -headeronly $tmp_req_file";
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        print STDERR @$stderr_buf;
+        exit $error_code >> 8;
+    }
+    my $output = join "", @$stdout_buf;
+    ($extname, $extver, $req_name) = split " ", $output;
+    if ($extname and ($extname ne "PS1_PS_REQUEST")) {
+        print STDERR "invalid request file\n";
+        exit $PS_EXIT_DATA_ERROR;
+    }
+    if (!defined $req_name) {
+        print STDERR "invalid request file no REQ_NAME\n";
+        exit $PS_EXIT_DATA_ERROR;
+    }
+}
+
+my $datestr = strftime "%Y%m%d", gmtime;
+my $datedir = "$workdir/webreq/$datestr";
+if (! -e $datedir ) {
+    if (!  mkdir $datedir ) {
+        print STDERR  "failed to create working directory $datedir";
+        exit $PS_EXIT_CONFIG_ERROR;
+    }
+}
+
+my $webreq_num = get_webreq_num();
+my $req_file = "$datedir/web_$webreq_num.fits";
+
+if (!copy( $tmp_req_file, $req_file)) {
+    die("Unable to copy request file $tmp_req_file to $req_file");
+}
+
+# Queue the request
+my $req_id = 0;
+{
+
+    my $command = "$pstamptool -addreq -name $req_name -uri $req_file -ds_id 0";
+    $command .= " -dbname $dbname" if $dbname;
+    $command .= " -dbserver $dbserver" if $dbserver;
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        my $errbuf = join "", @$stderr_buf;
+        print STDERR $errbuf;
+        if ($errbuf =~ /Duplicate entry/) {
+            print "Request Name $req_name has already been used";
+            exit $PS_EXIT_DATA_ERROR;
+        } else {
+            exit $PS_EXIT_UNKNOWN_ERROR;
+        }
+    }
+    $req_id = ${$stdout_buf}[0];
+}
+
+print "$req_id $req_name\n";
+
+exit 0;
+
+# Temporary hack
+# webrequest number is stored in a file in the current directory
+#
+# get this number from the database
+sub get_webreq_num
+{
+    my $filename = "$workdir/webreq_num.txt";
+    if (! open IN, "+< $filename" ) {
+        my $initial_num = 1;
+        open IN, "> $filename" or die "can't open $filename";
+        print IN "$initial_num\n" or die "failed to initialize $filename";
+        close IN;
+        return $initial_num;
+    }
+
+    my $webreq_num = <IN>;
+    chomp $webreq_num;
+
+    print STDERR "$webreq_num\n" if $verbose;
+
+    my $next = $webreq_num + 1;
+    truncate IN, 0;
+    seek IN, 0, 0;
+    print IN "$next\n";
+
+    close IN;
+    return $webreq_num;
+}
Index: branches/eam_branches/20090820/pstamp/scripts/pstamp_job_run.pl
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/pstamp_job_run.pl	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/scripts/pstamp_job_run.pl	(revision 25766)
@@ -16,4 +16,5 @@
 use PS::IPP::PStamp::RequestFile qw( :standard );
 use IPC::Cmd 0.36 qw( can_run run );
+use POSIX;
 
 use PS::IPP::Metadata::Config;
@@ -93,5 +94,13 @@
         run(command => $command, verbose => $verbose);
 
-    if ($success) {
+    my $exitStatus;
+    if (WIFEXITED($error_code)) {
+        $exitStatus = WEXITSTATUS($error_code);
+    } else {
+        print STDERR "ppstamp failed error_code: $error_code\n";
+        $exitStatus = $PS_EXIT_SYS_ERROR;
+    }
+
+    if ($exitStatus == 0) {
         my $dir = dirname($outputBase);
 
@@ -133,7 +142,8 @@
         close F;
         $jobStatus = $PS_EXIT_SUCCESS;
-    } else {
-        $jobStatus = $error_code >> 8;
-        my_die( "ppstamp failed with error code: $jobStatus", $job_id, $jobStatus);
+    } elsif ($exitStatus == $PSTAMP_NO_OVERLAP) {
+        $jobStatus = $PSTAMP_NO_OVERLAP
+    } else {
+        my_die( "ppstamp failed with error code: $exitStatus", $job_id, $exitStatus);
     }
 } elsif ($jobType eq "get_image") {
@@ -162,4 +172,5 @@
 {
     my $command = "$pstamptool -updatejob -job_id $job_id -state stop"; 
+    $command .= " -fault $jobStatus" if $jobStatus;
     $command .= " -dbname $dbname" if $dbname;
     $command .= " -dbserver $dbserver" if $dbserver;
@@ -202,5 +213,5 @@
     my $exit_code = shift;      # Exit code to add
 
-    $exit_code = $PS_EXIT_PROG_ERROR unless defined $exit_code;
+    $exit_code = $PS_EXIT_PROG_ERROR unless $exit_code;
 
     carp($msg);
Index: branches/eam_branches/20090820/pstamp/scripts/pstamp_parser_run.pl
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/pstamp_parser_run.pl	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/scripts/pstamp_parser_run.pl	(revision 25766)
@@ -14,4 +14,12 @@
 use File::Basename qw( basename dirname);
 use POSIX qw( strftime );
+use Carp;
+use IPC::Cmd 0.36 qw( can_run run );
+
+use PS::IPP::Metadata::Config;
+use PS::IPP::Metadata::Stats;
+use PS::IPP::Metadata::List qw( parse_md_list );
+
+use PS::IPP::Config qw( :standard );
 
 my $req_id;
@@ -39,26 +47,21 @@
 }
 
-die "--req_id --uri --product are required" 
+my $missing_tools;
+
+my $pstamptool  = can_run('pstamptool')  or (warn "Can't find pstamptool"  and $missing_tools = 1);
+my $pstampparse = can_run('pstampparse.pl') or (warn "Can't find pstampparse.pl" and $missing_tools = 1);
+my $dqueryparse = can_run('dqueryparse.pl') or (warn "Can't find dqueryparse.pl" and $missing_tools = 1);
+my $dsget = can_run('dsget') or (warn "Can't find dsget" and $missing_tools = 1);
+
+if ($missing_tools) {
+    warn("Can't find required tools.");
+    exit ($PS_EXIT_CONFIG_ERROR);
+}
+
+
+my_die("--req_id --uri --product are required", $req_id, $PS_EXIT_CONFIG_ERROR)
     if !defined($req_id) or
        !defined($uri) or
        !defined($product);
-
-use IPC::Cmd 0.36 qw( can_run run );
-
-use PS::IPP::Metadata::Config;
-use PS::IPP::Metadata::Stats;
-use PS::IPP::Metadata::List qw( parse_md_list );
-
-use PS::IPP::Config qw($PS_EXIT_SUCCESS
-		       $PS_EXIT_UNKNOWN_ERROR
-		       $PS_EXIT_SYS_ERROR
-		       $PS_EXIT_CONFIG_ERROR
-		       $PS_EXIT_PROG_ERROR
-		       $PS_EXIT_DATA_ERROR
-		       $PS_EXIT_TIMEOUT_ERROR
-		       metadataLookupStr
-		       metadataLookupBool
-		       caturi
-		       );
 
 my $ipprc = PS::IPP::Config->new(); # IPP Configuration
@@ -80,10 +83,12 @@
 my $datedir = "$pstamp_workdir/$datestr";
 if (! -e $datedir ) {
-    mkdir $datedir or die "failed to create working directory $datedir for request id $req_id";
+    mkdir $datedir or my_die( "failed to create working directory $datedir for request id $req_id", $req_id,
+        $PS_EXIT_CONFIG_ERROR);
 }
 
 my $workdir = "$datedir/$req_id";
 if (! -e $workdir ) {
-    mkdir $workdir or die "failed to create working directory $workdir for request id $req_id";
+    mkdir $workdir or my_die("failed to create working directory $workdir for request id $req_id", $req_id,
+        $PS_EXIT_CONFIG_ERROR);
 }
 
@@ -96,16 +101,4 @@
 exit ($PS_EXIT_CONFIG_ERROR) unless defined $defaultDSProduct;
     
-my $missing_tools;
-
-my $pstamptool  = can_run('pstamptool')  or (warn "Can't find pstamptool"  and $missing_tools = 1);
-my $pstampparse = can_run('pstampparse.pl') or (warn "Can't find pstampparse.pl" and $missing_tools = 1);
-my $dqueryparse = can_run('dqueryparse.pl') or (warn "Can't find dqueryparse.pl" and $missing_tools = 1);
-my $dsget = can_run('dsget') or (warn "Can't find dsget" and $missing_tools = 1);
-
-if ($missing_tools) {
-    warn("Can't find required tools.");
-    exit ($PS_EXIT_CONFIG_ERROR);
-}
-
 my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
 
@@ -119,18 +112,18 @@
         run(command => $command, verbose => $verbose);
     unless ($success) {
-        die("Unable to perform $command error code: $error_code");
+        my_die("Unable to perform $command error code: $error_code", $req_id, $error_code >> 8);
     }
 } elsif ($uri ne $new_uri) {
     # put a link to the file into the workdir
     if (-e $new_uri) {
-        unlink $new_uri or die "failed to unlink $new_uri";
+        unlink $new_uri or my_die("failed to unlink $new_uri", $req_id, $PS_EXIT_UNKNOWN_ERROR);
     }
     if (! symlink $uri, $new_uri) {
-        die ("failed to link request file $uri to workdir $workdir");
+        my_die ("failed to link request file $uri to workdir $workdir", $req_id, $PS_EXIT_UNKNOWN_ERROR);
     }
 }
 $uri = $new_uri;
 
-die "request file $uri not found" if ! -e $uri;
+my_die("request file $uri not found", $req_id, $PS_EXIT_UNKNOWN_ERROR) if ! -e $uri;
 
 #  if product was not defined (in database), use the default
@@ -263,2 +256,20 @@
     }
 }
+
+sub my_die {
+    my $msg = shift;
+    my $req_id = shift;
+    my $fault = shift;
+
+    carp($msg);
+
+    my $command = "$pstamptool -updatereq -req_id $req_id  -fault $fault";
+    $command   .= " -dbname $dbname" if $dbname;
+    $command   .= " -dbserver $dbserver" if $dbserver;
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+        run(command => $command, verbose => $verbose);
+    unless ($success) {
+        die("Unable to perform $command error code: $error_code");
+    }
+    exit $fault;
+}
Index: branches/eam_branches/20090820/pstamp/scripts/pstamp_request_file
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/pstamp_request_file	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/scripts/pstamp_request_file	(revision 25766)
@@ -0,0 +1,329 @@
+#!/usr/bin/env perl
+
+# create a Postage Stamp Request file from a textual description
+
+use warnings;
+use strict;
+
+use Astro::FITS::CFITSIO qw( :constants );
+Astro::FITS::CFITSIO::PerlyUnpacking(1);
+
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+use Pod::Usage qw( pod2usage );
+use File::Basename;
+
+use constant EXTNAME => 'PS1_PS_REQUEST'; # Extension name for output table
+
+my ( $input,			# Name of input text file
+     $output,			# Name of output table
+     $req_name, 
+     $help
+     );
+
+GetOptions(
+	   'input|i=s'    => \$input,
+	   'output|o=s'   => \$output,
+	   'req_name|r=s' => \$req_name,
+           'help|h'         => \$help,
+) or pod2usage( 2 );
+
+printhelp($0) if $help;
+pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
+pod2usage( -msg => "Required options: --input",
+           -exitval => 3) unless defined $input;
+
+# The header kewords
+my $header = [
+        { name =>  'REQ_NAME', 
+                    writetype => TSTRING, 
+                    comment => 'Postage Stamp request name',
+                    value => undef
+        },
+        { name =>  'EXTVER', 
+                    writetype => TSTRING, 
+                    comment => 'Extension version',
+                    value => undef
+        },
+];
+
+# Specification of columns to write
+my $columns = [ 
+        { name => 'ROWNUM',     type => 'J',   writetype => TULONG }, 
+
+        { name => 'CENTER_X',   type => 'D',  writetype => TDOUBLE },
+        { name => 'CENTER_Y',   type => 'D',  writetype => TDOUBLE },
+        { name => 'WIDTH',      type => 'D',  writetype => TDOUBLE },
+        { name => 'HEIGHT',     type => 'D',  writetype => TDOUBLE },
+        # 2 bits in COORD_MASK indicate what units of roi coords are
+        { name => 'COORD_MASK', type => 'J',  writetype => TULONG },
+
+        { name => 'JOB_TYPE',   type => '16A', writetype => TSTRING },
+        { name => 'OPTION_MASK',type => 'J',   writetype => TULONG },
+
+        # image selection parameters
+        { name => 'PROJECT',    type => '16A', writetype => TSTRING },
+        { name => 'REQ_TYPE',   type => '16A', writetype => TSTRING },
+        { name => 'IMG_TYPE',   type => '16A', writetype => TSTRING },
+        { name => 'ID',         type => '16A', writetype => TSTRING },           
+        { name => 'TESS_ID',    type => '64A', writetype => TSTRING },
+        { name => 'COMPONENT',  type => '64A', writetype => TSTRING },
+
+        { name => 'LABEL ',     type => '64A', writetype => TSTRING },
+
+        { name => 'REQFILT',    type => '16A', writetype => TSTRING },
+        { name => 'MJD_MIN',    type => 'D',   writetype => TDOUBLE },
+        { name => 'MJD_MAX',    type => 'D',   writetype => TDOUBLE },
+
+        { name => 'COMMENT ',   type => '64A', writetype => TSTRING },
+];
+
+my $in;
+if ($input eq '-') {
+    $in = \*STDIN;
+} else {
+    open $in, "<$input" or die "cannot open $input for reading";
+}
+
+my @colData;
+foreach (@$columns) {
+    push @colData, [];
+}
+
+
+my $minimum_cols = 6;
+my $numRows = read_data_for_table($in,'\s+', \@colData, $header, $minimum_cols); 
+if (!$numRows) {
+    print STDERR "no data in $input\n";
+    exit 1;
+}
+
+# overwrite the REQ_NAME value from the input file with the command
+# line argument
+
+if ($req_name) {
+    $header->[0]->{value} = $req_name;
+} else {
+    $req_name = $header->[0]->{value};
+}
+
+die "no request name defined" unless defined $req_name;
+
+$output = $req_name . ".fits" if !$output;
+
+my $status = make_fits_table($output, EXTNAME, $numRows, \@colData, $columns, $header);
+
+exit $status;
+
+# XXXXX: This should be in a module
+# two utility functions that may be used to create a FITS binary
+# table from hashes describing the header keywords and columns
+
+# read_table_description reads the data for a table from a simple text file
+# make_fits_table writes out the table to a named file
+
+
+# A function to build a fits binary table from supplied data 
+# 
+sub make_fits_table {
+        my $output = shift;     # name of output file
+        my $extname = shift;    # extension name
+        my $numRows = shift;    # number of rows in the table
+        my $colData = shift;    # ref to array of arrays containing the data for each column
+        my $columns = shift;    # ref to array of column descriptions (each a hash)
+                                # with keys: name, type, and writetype
+        my $header = shift;     # ref to array of header keyword descriptions - each a hash
+                                # with keys: name, name, writetype, comment, and value
+        my $status = 0;
+
+        die "incorrect arguments" if !defined($columns);
+        # note $header can be nil
+
+        # build arrays for cfitsio
+        my @colNames;			# Names of columns
+        my @colTypes;			# Types of columns
+        my @colWriteType;               # type to use to write
+
+        foreach my $colSpec ( @$columns) {
+            push @colNames, $colSpec->{name};
+            push @colTypes, $colSpec->{type};
+            push @colWriteType, $colSpec->{writetype};
+        }
+
+        if (-e $output) {
+            unlink "$output" or die "failed to remove existing $output";
+        }
+
+        my $outFits = Astro::FITS::CFITSIO::create_file( $output, $status ); # Output file handle
+        check_fitsio( $status );
+
+        $outFits->create_img( 16, 0, undef, $status );
+        check_fitsio( $status );
+
+        # Create the table
+
+        $outFits->create_tbl( BINARY_TBL(), $numRows, scalar @colNames,
+                                \@colNames, \@colTypes, undef, $extname, $status );
+        check_fitsio( $status );
+
+        # if header keyword descriptions were provided add them
+        if ($header) {
+            foreach my $headerword ( @$header ) {
+                my $value = $headerword->{value};
+                unless (defined $value) {
+                    print "Can't find header keyword $headerword\n";
+                    next;
+                }
+                # zap quotation marks
+                $value =~ s/\'//g;
+                my $name    = $headerword->{name};
+                my $type    = $headerword->{writetype};
+                my $comment = $headerword->{comment};
+                $outFits->write_key( $type, $name, $value, $comment, $status );
+                check_fitsio( $status );
+            }
+        }
+
+
+        for (my $i = 0; $i < scalar @colNames; $i++) {
+            my $writeType = $colWriteType[$i];
+            $outFits->write_col( $writeType, $i + 1, 1, 1, $numRows, $colData->[$i], $status );
+            check_fitsio( $status );
+        }
+
+        $outFits->close_file( $status );
+
+        return 0;
+
+} # end of sub make_fits_table
+
+
+
+# read the table contents from a file
+#
+# input text file format:
+#   lines that begin with '#' are comment lines and are skipped.
+#   other lines are data. Each data line is split into fields with the
+#   provided separator
+#
+# if $header is not null header the first non-commented line is read to
+# fill the value for each header keyword. The number of fields must match
+# the number of keywords.
+#
+# Following the optional header data, each data line contains data for each
+# row in the table. The number of fields must match the number of column
+# arrays provided.
+
+sub read_data_for_table {
+    my $in      = shift;    # input file handle
+    my $sep     = shift;    # string containing field separator
+    my $colData = shift;    # reference to an array of arrays for the data
+    my $header  = shift;    # rerence to array of header keyword descriptions
+    my $minimum_required_vals = shift;
+
+    my $line_num = 0;
+
+    # read data for header if any data is expected
+    if ($header) {
+        my $nhead = @$header;
+        while (my $line = <$in>) {
+            $line_num++;
+            chomp $line;
+            next if !$line;             # skip blank lines
+            next if ($line =~ /^#/);    # skip comment lines
+            my @vals = split /$sep/, $line;
+            my $nvals = @vals;
+            die "number of header columns in input $nvals does not equal expected number of header words $nhead"
+                    if (@vals != @$header);
+
+            for (my $i=0; $i < @$header; $i++) {
+                $header->[$i]->{value} = $vals[$i];
+            }
+
+            last; # only one header line
+        }
+    }
+
+    my $num_rows = 0;
+    my $ncols = @$colData - 1;  # -1 because COMMENT is handled seperatly
+    my @last_vals;
+    my %used_ROWNUMS;
+    my $auto_row_num = 0;
+    while (my $line = <$in>) {
+        chomp $line;
+        $line_num++;
+        next if !$line;             # skip blank lines
+        next if ($line =~ /^#/);    # skip comment lines
+
+        my ($spec, $comment) = split /\|/, $line;
+        if (!$spec) {
+            print STDERR "improper format on line $line_num\n";
+            print STDERR "$line\n";
+            exit 1;
+        }
+        $comment = "null" if !$comment;
+        my @vals = split /$sep/, $spec;
+        my $nvals = @vals;
+        if ($nvals < $minimum_required_vals) {
+            die "Too few values $nvals found at line $line_num. Each row must contain at least $minimum_required_vals columns\n";
+        }
+        if ($nvals < $ncols) {
+            if (!scalar @last_vals) {
+                die "Too few values $nvals found at line $line_num. $ncols values are required\n";
+            }
+            for (my $i = $nvals; $i < $ncols; $i++) {
+                $vals[$i] = $last_vals[$i];
+            }
+        }
+        $vals[$ncols] = $comment;
+        @last_vals = @vals;
+    
+        # check the input ROWNUM value. If zero set it automatically
+        my $this_ROWNUM = $vals[0];
+        $this_ROWNUM = ++$auto_row_num if $this_ROWNUM eq 0;
+
+        # fail if this ROWNUM value has already been used
+        my $previous = $used_ROWNUMS{$this_ROWNUM};
+        if ($previous) {
+            die "ROWNUM for line $line_num: $this_ROWNUM has already been used at line $previous\n";
+        }
+        $used_ROWNUMS{$this_ROWNUM} = $line_num;
+
+        $colData->[0]->[$num_rows] = $this_ROWNUM;
+        for (my $col = 1; $col < @$colData; $col++) {
+            $colData->[$col]->[$num_rows] = $vals[$col];
+        }
+        $num_rows++;
+    }
+
+    # we return the number of rows read
+    return $num_rows;
+}
+
+# From Astro::FITS::CFITSIO demo
+sub check_fitsio
+{
+    my $status = shift;		# Status of FITSIO calls
+
+    if ($status != 0) {
+	my $msg;		# Message to output
+	Astro::FITS::CFITSIO::fits_get_errstatus( $status , $msg );
+	die "CFITSIO error: $msg\n";
+    }
+}
+
+sub printhelp
+{
+    my $prog = basename($_[0]);
+
+    print "Create a postage stamp request fits file from a textual description.\n";
+    print "Usage:\n";
+    print "\t$prog --input input_file_name [--req_name request_name] [--output output_file_name ]\n\n";
+    print "If --req_name is provided the REQ_NAME value in the input file is ignored.\n";
+    print "If --output is omitted the output file name is set to REQ_NAME.fits\n\n";
+    print "Header 1 Line.  Format:\n\n";
+    print "  REQ_NAME EXTVER\n\n";
+    print "REQUEST specification (1 or more lines). Format:\n\n";
+    print "  ROWNUM CENTER_X CENTER_Y WIDTH HEIGHT COORD_MASK JOB_TYPE OPTION_MASK PROJECT REQ_TYPE IMG_TYPE ID TESS_ID COMPONENT LABEL REQFILT MJD_MIN MJD_MAX | COMMENT\n\n";
+
+    exit 0;
+}
Index: branches/eam_branches/20090820/pstamp/scripts/pstamp_results_file.pl
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/pstamp_results_file.pl	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/scripts/pstamp_results_file.pl	(revision 25766)
@@ -90,4 +90,5 @@
         { name => 'TESS_ID',    type => '64A', writetype => TSTRING },    
         { name => 'COMPONENT',  type => '64A', writetype => TSTRING },    
+        { name => 'LABEL',      type => '64A', writetype => TSTRING },    
 
         # output parameters
@@ -104,4 +105,5 @@
         { name => 'WIDTH',      type => 'D', writetype => TDOUBLE },   
         { name => 'HEIGHT',     type => 'D', writetype => TDOUBLE },  
+        { name => 'COMMENT',    type => '64A', writetype => TSTRING },    
 ];
 
Index: branches/eam_branches/20090820/pstamp/scripts/pstamp_webrequest.pl
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/pstamp_webrequest.pl	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/scripts/pstamp_webrequest.pl	(revision 25766)
@@ -82,5 +82,5 @@
 my $cur_dir = getcwd();
 #print STDERR "cur_dir is $cur_dir\n";
-my $request_name = "web" . get_webreq_num();
+my $request_name = "web_" . get_webreq_num();
 my $request_file = "$cur_dir/$request_name.fits";
 {
@@ -136,5 +136,5 @@
 }
 
-print "$req_id";
+print "$req_id $request_name";
 
 exit 0;
Index: branches/eam_branches/20090820/pstamp/scripts/pstampparse.pl
===================================================================
--- branches/eam_branches/20090820/pstamp/scripts/pstampparse.pl	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/scripts/pstampparse.pl	(revision 25766)
@@ -14,5 +14,7 @@
 use PS::IPP::PStamp::Job qw( :standard );
 use File::Temp qw(tempfile);
+use File::Basename qw(basename);
 use Carp;
+use POSIX;
 
 my $verbose;
@@ -70,4 +72,5 @@
 }
 
+# list_job is a deugging mode
 $no_update = 1 if $mode eq "list_job";
 
@@ -97,7 +100,9 @@
 my_die("wrong EXTVER $extver found in $request_file_name", $PS_EXIT_PROG_ERROR) if ($extver ne "1");
 
+
 # check for duplicate request name
-if (!$no_update) {
-    my $command = "$pstamptool -listreq  -name $req_name";
+my $duplicate_req_name = 0;
+if ($req_id and !$no_update) {
+    my $command = "$pstamptool -listreq  -name $req_name -not_req_id $req_id";
     $command .= " -dbname $dbname" if $dbname;
     $command .= " -dbserver $dbserver" if $dbserver;
@@ -108,9 +113,10 @@
     if ($success) {
         # -listreq succeeded duplicate request name
+        print STDERR "REQ_NAME $req_name has already been used\n";
         insertFakeJobForRow(undef, 0, $PSTAMP_DUP_REQUEST);
-        exit 0;
-    } elsif ($exitStatus ne $PS_EXIT_DATA_ERROR) {
-        # wrong error code something else is wrong
-        my_die("$command failed", $exitStatus);
+        $duplicate_req_name = 1;
+        my $datestr = strftime "%Y%m%d%H%M%S.$req_id", gmtime;
+        $req_name = "ERROR.$datestr";
+        #exit 0;
     }
 }
@@ -129,4 +135,7 @@
     }
 }
+if ($duplicate_req_name) {
+    exit 0;
+}
 
 #
@@ -177,11 +186,13 @@
     }
     my $req_type = $row->{REQ_TYPE};
-    $stage = $row->{IMG_TYPE};
-    my $id       = $row->{ID};
+    $stage       = $row->{IMG_TYPE};
+    my $id      = $row->{ID};
     my $component = $row->{COMPONENT};
-
-    my $filter   = $row->{REQFILT};
+    my $tess_id = $row->{TESS_ID};
+
+    my $filter  = $row->{REQFILT};
     my $mjd_min = $row->{MJD_MIN};
     my $mjd_max = $row->{MJD_MAX};
+    my $label   = $row->{LABEL};
 
     my $option_mask= $row->{OPTION_MASK};
@@ -214,8 +225,12 @@
     my_die("job_type is list_uri but mode is $mode", $PS_EXIT_PROG_ERROR) if ($job_type eq "list_uri") and ($mode ne "list_uri");
 
-
     my $image_db   = $proj_hash->{dbname};
     my $camera     = $proj_hash->{camera};
     $need_magic = $proj_hash->{need_magic};
+
+    # Temporary hack so that MOPS can get at non-magicked data
+    if ($product and ($product eq "mops-pstamp-results")) {
+        $need_magic = 0;
+    }
 
     # collect rows with the same images of interest in a list so that they
@@ -256,6 +271,6 @@
         my ($x, $y);
 
-        $imageList = locate_images($ipprc, $image_db, $req_type, $stage, $id, $search_component,
-                $inverse, $skycenter, $x, $y, $mjd_min, $mjd_max, $filter, $verbose);
+        $imageList = locate_images($ipprc, $image_db, $req_type, $stage, $id, $tess_id, $search_component,
+                $inverse, $need_magic, $x, $y, $mjd_min, $mjd_max, $filter, $label, $verbose);
 
         if (!$imageList or !@$imageList) {
@@ -289,8 +304,8 @@
     my $have_skycells = shift;
     my $need_magic = shift;
+
     my $num_jobs = 0;
-
     my $rownum = $row->{ROWNUM};
-
+    my $option_mask = $row->{OPTION_MASK};
     my $components = $row->{components};
 
@@ -334,9 +349,12 @@
         if (($stage ne "stack") and ($need_magic and !$image->{magicked})) {
             # XXX: should we add a faulted job so the client can know what happened if no images come back?
-            print STDERR "skippping non-magicked image $imagefile\n" if $verbose;
+            # This test is made in locate_images now so this code never runs. This leads to no feedback
+            # to users, but speeds up processing significatnly
+            print STDERR "skipping non-magicked image $imagefile\n" if $verbose;
 
             # for now assume yes.
 
             insertFakeJobForRow($row, $job_num, $PSTAMP_NOT_DESTREAKED);
+            $num_jobs++;
 
             next;
@@ -356,12 +374,18 @@
         $args .= " -file $imagefile";
 
-        if (($row->{OPTION_MASK} & $PSTAMP_SELECT_MASK) &&  $image->{mask} ) {
+        if (($option_mask & $PSTAMP_SELECT_MASK) &&  $image->{mask} ) {
             $args .= " -mask $image->{mask}";
         }
-        if (($row->{OPTION_MASK} & $PSTAMP_SELECT_WEIGHT) and $image->{weight} ) {
+        if (($option_mask & $PSTAMP_SELECT_WEIGHT) and $image->{weight} ) {
             $args .= " -variance $image->{weight}";
         }
 
-        my $output_base = "$out_dir/${rownum}_${job_num}";
+        my $base = basename($image->{path_base});
+        # XXX: TODO use filerule for this. I don't have a camera defined here
+        if (($stage eq 'chip') and ($image->{camera} eq 'GPC1')) {
+            $base = "${base}.${component}";
+        }
+
+        my $output_base = "$out_dir/${rownum}_${job_num}_${base}";
         my $argslist = "${output_base}.args";
 
@@ -388,5 +412,5 @@
         $num_jobs++;
         my $command = "$pstamptool -addjob  -req_id $req_id -job_type $row->{JOB_TYPE}"
-                        . " -outputBase $output_base -rownum $rownum -state $newState";
+                        . " -outputBase $output_base -rownum $rownum -state $newState -options $option_mask";
         $command .= " -fault $fault" if $fault;
         $command .= " -exp_id $exp_id" if $exp_id;
@@ -465,21 +489,36 @@
         my $thisRun;
 
-        my ($pointsList, $pointsListName) = tempfile ("/tmp/pointsList.XXXX", UNLINK => !$save_temps);
         my $npoints = 0;
-        foreach my $row (@$rowList) {
-            $row->{components} = {};
-            if ($row->{skycenter}) {
-                print $pointsList "$row->{ROWNUM} $row->{CENTER_X} $row->{CENTER_Y}\n";
-                $npoints++;
-            } else {
-                # this row's center is in pixel coordinates add all images to the component list for this row
-                foreach my $i (@$imageList) {
-                    my $component = $have_skycells ? $i->{skycell_id} : $i->{class_id};
-                    my_die( "image found with no value for component", $PS_EXIT_UNKNOWN_ERROR) if !$component;
-                    $row->{components}->{$component} = 1;
+        my ($pointsList, $pointsListName);
+        if (scalar @$imageList > 1) {
+            ($pointsList, $pointsListName) = tempfile ("/tmp/pointsList.XXXX", UNLINK => !$save_temps);
+            foreach my $row (@$rowList) {
+                $row->{components} = {};
+                if ($row->{skycenter}) {
+                    print $pointsList "$row->{ROWNUM} $row->{CENTER_X} $row->{CENTER_Y}\n";
+                    $npoints++;
+                } else {
+                    # this row's center is in pixel coordinates add all images to the component list for this row
+                    foreach my $i (@$imageList) {
+                        my $component = $have_skycells ? $i->{skycell_id} : $i->{class_id};
+                        my_die( "image found with no value for component", $PS_EXIT_UNKNOWN_ERROR)
+                                if !$component;
+                        $row->{components}->{$component} = 1;
+                    }
                 }
             }
-        }
-        close $pointsList;
+            close $pointsList;
+        } else {
+            # only one image. Avoid the expense of dvoImagesAtCoords. 
+            # queue the job and let ppstamp figure out if the center is valid for the image
+            # the resulting result code will be the same.
+            foreach my $row (@$rowList) {
+                $row->{components} = {};
+                my $i = $imageList->[0];
+                my $component = $have_skycells ? $i->{skycell_id} : $i->{class_id};
+                my_die( "image found with no value for component", $PS_EXIT_UNKNOWN_ERROR) if !$component;
+                $row->{components}->{$component} = 1;
+            }
+        }
 
         my $tess_dir_abs;
@@ -487,6 +526,7 @@
         while ($thisRun = getOneRun($stage, $imageList)) {
             if ($npoints) {
-                # we collected a set of sky coordintates above filter the images so that only
-                # those tat contain the centers are processed
+                my_die( "pointsListName is not defined", $PS_EXIT_PROG_ERROR) if !$pointsListName;
+                # we collected a set of sky coordinates above.
+                # filter the images so that only those that contain the centers of the ROIs are processed
                 my $command = "$dvoImagesAtCoords $pointsListName";
                 if ($have_skycells) {
@@ -507,7 +547,11 @@
                     run(command => $command, verbose => $verbose);
                 unless ($success) {
-                    print STDERR @$stderr_buf;
-                    my $rc = $error_code >> 8;
-                    my_die( "dvoImagesAtCoords failed: $rc", $PS_EXIT_UNKNOWN_ERROR);
+                    # don't fail if the program exited normally and exit status was PSTAMP_NO_OVERLAP
+                    # That just means that the coordinate didn't match any image/skycell
+                    if (!WIFEXITED($error_code) || (WEXITSTATUS($error_code) ne $PSTAMP_NO_OVERLAP)) {
+                        print STDERR @$stderr_buf;
+                        my $rc = WIFEXITED($error_code) ? WEXITSTATUS($error_code) : $PS_EXIT_SYS_ERROR;
+                        my_die( "dvoImagesAtCoords failed: $rc", $rc);
+                    }
                 }
                 # now we have a list of row numbers and components
@@ -519,5 +563,5 @@
                     my ($rownum, undef, undef, $component) = split " ", $line;
 
-                    # I guess since we need this function we should be useing a hash for rowList 
+                    # I guess since we need this function we should be using a hash for rowList 
                     my $row = findRow($rownum, $rowList);
                     $row->{components}->{$component} = 1;
@@ -624,4 +668,9 @@
     return 0 if ($r1->{IMG_TYPE} ne $r2->{IMG_TYPE});
     return 0 if ($r1->{ID} ne $r2->{ID});
+    return 0 if ($r1->{TESS_ID} ne $r2->{TESS_ID});
+    return 0 if ($r1->{REQFILT} ne $r2->{REQFILT});
+    return 0 if ($r1->{LABEL} ne $r2->{LABEL});
+    return 0 if ($r1->{MJDMIN} ne $r2->{MJDMAX});
+    return 0 if ($r1->{MJDMAX} ne $r2->{MJDMAX});
     return 0 if ($r1->{inverse} ne $r2->{inverse});
 
@@ -631,5 +680,6 @@
         # if first row has no component all of the images will be retrieved, so
         # the fact that this row has a component is ok. Fall through to return 1
-        # XXX Nope that doesn't work (yet)
+        # XXX Nope this doesn't work. It is consistent with the other logic in some way
+        # that i haven't fully thought through
         return 0;
     }
Index: branches/eam_branches/20090820/pstamp/src/Makefile.am
===================================================================
--- branches/eam_branches/20090820/pstamp/src/Makefile.am	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/src/Makefile.am	(revision 25766)
@@ -1,6 +1,10 @@
 bin_PROGRAMS = ppstamp pstamprequest pstampdump
+
+include_HEADERS = \
+	pstamp.h
 
 noinst_HEADERS = \
 	ppstamp.h  \
+	pstampint.h \
         pstampErrorCodes.h
 
Index: branches/eam_branches/20090820/pstamp/src/ppstamp.c
===================================================================
--- branches/eam_branches/20090820/pstamp/src/ppstamp.c	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/src/ppstamp.c	(revision 25766)
@@ -29,9 +29,5 @@
 
     // find the pixels that we need to copy, setup the output image
-    if (ppstampMakeStamp(config, options)) {
-        exitCode = 0;
-    } else {
-        exitCode = PS_EXIT_DATA_ERROR;
-    }
+    exitCode = ppstampMakeStamp(config, options);
 
     psLogMsg ("ppstamp", 3, "Complete ppstamp run: %f sec\n", psTimerMark(TIMERNAME));
Index: branches/eam_branches/20090820/pstamp/src/ppstamp.h
===================================================================
--- branches/eam_branches/20090820/pstamp/src/ppstamp.h	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/src/ppstamp.h	(revision 25766)
@@ -6,5 +6,5 @@
 #endif
 
-#include "pstamp.h"
+#include "pstampint.h"
 #include "ppstampOptions.h"
 
@@ -20,5 +20,5 @@
 bool ppstampParseCamera(pmConfig *config);
 
-bool ppstampMakeStamp(pmConfig *config, ppstampOptions *);
+int ppstampMakeStamp(pmConfig *config, ppstampOptions *);
 pmFPAfile * ppstampBuildMosaic(pmConfig *config, pmFPAfile *input, pmFPAview *view);
 
Index: branches/eam_branches/20090820/pstamp/src/ppstampMakeStamp.c
===================================================================
--- branches/eam_branches/20090820/pstamp/src/ppstampMakeStamp.c	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/src/ppstampMakeStamp.c	(revision 25766)
@@ -48,5 +48,5 @@
 }
 
-static bool copyMetadata(pmFPAfile *output, pmFPAfile *input, pmChip *inChip, ppstampOptions *options)
+static bool copyMetadata(pmFPAfile *output, pmFPAfile *input, pmChip *inChip, ppstampOptions *options, pmAstromObj *center)
 {
     pmChip    *outChip;
@@ -61,7 +61,4 @@
     // since some of the keywords might be duplicated we may not want to copy both
 
-    // copy the fpa concepts
-    outChip->parent->concepts = psMetadataCopy(outChip->parent->concepts, inChip->parent->concepts);
-
     pmHDU *inHDU  = pmHDUFromChip(inChip);
     pmHDU *outHDU = pmHDUGetHighest(output->fpa, outChip, NULL);
@@ -73,4 +70,23 @@
     }
 
+    // copy the fpa concepts
+    pmConceptsCopyFPA(output->fpa, input->fpa, false, false);
+    pmConceptsCopyChip(outChip, inChip, false);
+    pmCell *outCell = outChip->cells->data[0]; // The only output cell
+
+    if (inChip->cells->n == 1) {
+        pmConceptsCopyCell(outCell, inChip->cells->data[0]);
+        // Need to fix up the trimsec and biassec to correspond to the output
+        psMetadataItem *trimsec = psMetadataLookup(outCell->concepts, "CELL.TRIMSEC");
+        psFree(trimsec->data.V);
+        trimsec->data.V = NULL;
+        psMetadataItem *biassec = psMetadataLookup(outCell->concepts, "CELL.BIASSEC");
+        psFree(biassec->data.V);
+        biassec->data.V = psListAlloc(NULL);
+    } else {
+        psList *inCells = psArrayToList(inChip->cells); // Input cells
+        pmConceptsAverageCells(outCell, inCells, NULL, NULL, false);
+        psFree(inCells);
+    }
 
     // If input had WCS convert it for stamp
@@ -93,4 +109,7 @@
     }
 
+    psMetadataAddF64(outHDU->header, PS_LIST_TAIL, "RA_DEG", PS_META_REPLACE, "Right Ascension of stamp center", RAD_TO_DEG(center->sky->r));
+    psMetadataAddF64(outHDU->header, PS_LIST_TAIL, "DEC_DEG", PS_META_REPLACE, "Declination of stamp center", RAD_TO_DEG(center->sky->d));
+
     ppstampVersionMetadata(outHDU->header, options);
 
@@ -100,13 +119,15 @@
 // Extract pixels from an image. If part of the bounds of the region are
 // partially outside of the input those pixels are set to zero.
-psImage *extractStampOld(psImage *image, psRegion region)
-{
-    int width  = region.x1 - region.x0;
-    int height = region.y1 - region.y0;
+static psImage *extractStamp(psImage *image, psRegion region, double value)
+{
+    int width  = region.x1 - region.x0 + 0.5;
+    int height = region.y1 - region.y0 + 0.5;
 
     if (width < 0) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "negative width\n");
         return NULL;
     }
     if (height < 0) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "negative height\n");
         return NULL;
     }
@@ -132,79 +153,4 @@
 
     int copyWidth  = lastX - srcX;
-    int rightBlank = width - copyWidth - leftBlank;
-    if (copyWidth <= 0) {
-        return NULL;
-    }
-
-    psImage *output = psImageAlloc(width, height, image->type.type);
-
-    psElemType  type = image->type.type;
-    psS32       elementSize =  PSELEMTYPE_SIZEOF(type);
-    int         copySize = copyWidth * elementSize;
-
-    for (int dstY=0 ; dstY < height; srcY++, dstY++) {
-        psU8 *pdst = output->data.U8[dstY];
-
-        if ((srcY < image->row0) || (srcY >= lastY)) {
-            // zero the row
-            memset(pdst, 0, width*elementSize);
-        } else {
-            psU8 *psrc = image->data.U8[srcY]  + (srcX * elementSize);
-
-            if (leftBlank) {
-                memset(pdst, 0, leftBlank*elementSize);
-            }
-
-            // copy copyWidth pixels from srcX,srcY to dstX, dstY
-            pdst += dstX*elementSize;
-            memcpy(pdst, psrc, copySize);
-
-            if (rightBlank) {
-                pdst += copyWidth * elementSize;
-                memset(pdst, 0, rightBlank);
-            }
-        }
-    }
-
-
-    return output;
-}
-// Extract pixels from an image. If part of the bounds of the region are
-// partially outside of the input those pixels are set to zero.
-static psImage *extractStamp(psImage *image, psRegion region, double value)
-{
-    int width  = region.x1 - region.x0;
-    int height = region.y1 - region.y0;
-
-    if (width < 0) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "negative width\n");
-        return NULL;
-    }
-    if (height < 0) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "negative height\n");
-        return NULL;
-    }
-
-    int srcX  = region.x0;
-    int srcY  = region.y0;
-    int lastX = region.x1;
-    int lastY = region.y1;
-    if (lastX > (image->col0 + image->numCols)) {
-        lastX = image->col0 + image->numCols;
-    }
-    if (lastY > (image->row0 + image->numRows)) {
-        lastY = image->row0 + image->numRows;
-    }
-
-    int leftBlank = 0;
-    int dstX  = 0;
-    if (srcX < image->col0) {
-        leftBlank = image->col0 - srcX;
-        dstX += leftBlank;
-        srcX = 0;
-    }
-
-    int copyWidth  = lastX - srcX;
-//    int rightBlank = width - copyWidth - leftBlank;
     if (copyWidth <= 0) {
         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "copyWidth is invalid: %d\n", copyWidth);
@@ -231,5 +177,4 @@
     if (skip > 0) {
         dstY = skip;
-        height -= skip;
         srcY = image->row0;
     }
@@ -238,10 +183,9 @@
             break;
         }
-        psU8 *pdst = output->data.U8[dstY];
+        // copy copyWidth pixels from srcX,srcY to dstX, dstY
+        psU8 *pdst = output->data.U8[dstY] + (dstX * elementSize);
 
         psU8 *psrc = image->data.U8[srcY]  + (srcX * elementSize);
 
-        // copy copyWidth pixels from srcX,srcY to dstX, dstY
-        pdst += dstX*elementSize;
         memcpy(pdst, psrc, copySize);
     }
@@ -252,6 +196,6 @@
 // Build the postage stamp output file
 
-static bool makeStamp(pmConfig *config, ppstampOptions *options, pmFPAfile *input,
-                pmChip *inChip, pmFPAview *view)
+static int makeStamp(pmConfig *config, ppstampOptions *options, pmFPAfile *input,
+                pmChip *inChip, pmFPAview *view, pmAstromObj *center)
 {
     int status = false;
@@ -260,5 +204,5 @@
     if (!output) {
         psError(PS_ERR_UNKNOWN, false, "Can't find output data\n");
-        return false;
+        return PS_EXIT_DATA_ERROR;
     }
     char *fpaName = psMetadataLookupStr(NULL, input->fpa->concepts, "FPA.OBS"); // Name of FPA
@@ -284,5 +228,5 @@
         pmFPAfile *mosaic = ppstampBuildMosaic(config, input, view);
         if (mosaic == NULL) {
-            return false;
+            return PS_EXIT_UNKNOWN_ERROR;
         }
         srcFile = mosaic;
@@ -320,5 +264,5 @@
         }
 
-        outReadout->image = extractStamp(readout->image, extractRegion,  0);
+        outReadout->image = extractStamp(readout->image, extractRegion,  NAN);
         if (!outReadout->image) {
             psError(PS_ERR_UNKNOWN, false, "failed to create postage stamp image\n");
@@ -327,5 +271,5 @@
         }
         if (readout->variance) {
-            outReadout->variance = extractStamp(readout->variance, extractRegion,  0);
+            outReadout->variance = extractStamp(readout->variance, extractRegion,  NAN);
             if (!outReadout->variance) {
                 psError(PS_ERR_UNKNOWN, false, "failed to create postage stamp weight image\n");
@@ -360,7 +304,7 @@
 
     if (status) {
-        status = copyMetadata(output, input, inChip, options);
-    }
-    return status;
+        status = copyMetadata(output, input, inChip, options, center);
+    }
+    return status ? PS_EXIT_SUCCESS : PS_EXIT_UNKNOWN_ERROR;
 }
 
@@ -396,11 +340,15 @@
 
 
-static void skyToChip(pmAstromObj *pt, pmFPA *fpa, pmChip *chip)
-{
-    // convert from sky to TP to FP
-    psProject(pt->TP, pt->sky, fpa->toSky);
+static void TPToChip(pmAstromObj *pt, pmFPA *fpa, pmChip *chip)
+{
     psPlaneTransformApply(pt->FP, fpa->fromTPA, pt->TP);
     // convert from FP to chip
     psPlaneTransformApply(pt->chip, chip->fromFPA, pt->FP);
+}
+static void skyToChip(pmAstromObj *pt, pmFPA *fpa, pmChip *chip)
+{
+    // convert from sky to TP to FP
+    psProject(pt->TP, pt->sky, fpa->toSky);
+    TPToChip(pt, fpa, chip);
 }
 
@@ -412,5 +360,4 @@
     psPlaneTransformApply(pt->TP, fpa->toTPA, pt->FP);
     psDeproject(pt->sky, pt->TP, fpa->toSky);
-
 }
 
@@ -433,9 +380,4 @@
     pmAstromObj *pt = pmAstromObjAlloc();
 
-    if (!options->roip.celestialCenter) {
-        // Center was specified in chip coordinates, transform to the sky
-        chipToSky(center, fpa, chip);
-    }
-
     // calculate the four corners of the bounding box in sky coordinates, translate them to
     // chip coordinates and build the ROI by comparison.
@@ -446,25 +388,28 @@
     options->roi.y1 = -INFINITY;
 
-    pt->sky->rErr = 0;
-    pt->sky->dErr = 0;
-
-    pt->sky->r = center->sky->r - options->roip.dRA/2;
-    pt->sky->d = center->sky->d - options->roip.dDEC/2;
-    skyToChip(pt, fpa, chip);
+    double dx = 0.5 * options->roip.dRA  / fpa->toSky->Xs;
+    double dy = 0.5 * options->roip.dDEC / fpa->toSky->Ys;
+
+    pt->TP->xErr = 0;
+    pt->TP->yErr = 0;
+
+    pt->TP->x = center->TP->x - dx;
+    pt->TP->y = center->TP->y - dy;
+    TPToChip(pt, fpa, chip);
     compareToBox(&options->roi, pt->chip);
 
-    pt->sky->r = center->sky->r + options->roip.dRA/2;
-    pt->sky->d = center->sky->d - options->roip.dDEC/2;
-    skyToChip(pt, fpa, chip);
+    pt->TP->x = center->TP->x + dx;
+    pt->TP->y = center->TP->y - dy;
+    TPToChip(pt, fpa, chip);
     compareToBox(&options->roi, pt->chip);
 
-    pt->sky->r = center->sky->r + options->roip.dRA/2;
-    pt->sky->d = center->sky->d + options->roip.dDEC/2;
-    skyToChip(pt, fpa, chip);
+    pt->TP->x = center->TP->x + dx;
+    pt->TP->y = center->TP->y + dy;
+    TPToChip(pt, fpa, chip);
     compareToBox(&options->roi, pt->chip);
 
-    pt->sky->r = center->sky->r - options->roip.dRA/2;
-    pt->sky->d = center->sky->d + options->roip.dDEC/2;
-    skyToChip(pt, fpa, chip);
+    pt->TP->x = center->TP->x - dx;
+    pt->TP->y = center->TP->y + dy;
+    TPToChip(pt, fpa, chip);
     compareToBox(&options->roi, pt->chip);
 
@@ -539,4 +484,5 @@
             center->chip->yErr = 0;
             onChip = true;
+            chipToSky(center, input->fpa, chip);
         }
     }
@@ -574,8 +520,8 @@
 }
 
-bool ppstampMakeStamp (pmConfig *config, ppstampOptions *options)
+int ppstampMakeStamp (pmConfig *config, ppstampOptions *options)
 {
     bool        status = false;
-    bool        returnval = false;;
+    int        returnval = PS_EXIT_SUCCESS;;
     bool        foundOverlap = false;
 
@@ -583,5 +529,5 @@
     if (!status) {
         psError(PS_ERR_UNKNOWN, true, "Can't find input file!\n");
-        return false;
+        return PS_EXIT_DATA_ERROR;
     }
 
@@ -591,5 +537,5 @@
     } else if (astrom->camera != input->camera) {
         psError(PS_ERR_UNKNOWN, true, "Input camera and astrometry camera do not match");
-        return false;
+        return PS_EXIT_CONFIG_ERROR;
     }
 
@@ -600,5 +546,5 @@
         psError(PS_ERR_UNKNOWN, false, "Failed to load input.");
         psFree (view);
-        return false;
+        return PS_EXIT_DATA_ERROR;
     }
     bool bilevelAstrometry  = false;
@@ -614,5 +560,5 @@
             psError(PS_ERR_UNKNOWN, false, "Unable to read bilevel mosaic astrometry for input FPA.");
             psFree(view);
-            return false;
+            return PS_EXIT_DATA_ERROR;
         }
     }
@@ -642,10 +588,10 @@
         case PPSTAMP_ON:
         case PPSTAMP_PARTIALLY_ON:
-            returnval = makeStamp(config, options, input, chip, view);
+            returnval = makeStamp(config, options, input, chip, view, center);
             allDone = true;
             foundOverlap = true;
             break;
         case PSTAMP_ERROR:
-            returnval = false;
+            returnval = PS_EXIT_UNKNOWN_ERROR;
             allDone = true;
             break;
@@ -667,6 +613,7 @@
     psFree(view);
 
-    if (!foundOverlap) {
+    if (!foundOverlap && (returnval == PS_EXIT_SUCCESS)) {
         fprintf(stderr, "ROI not found in input\n");
+        returnval = PSTAMP_NO_OVERLAP;
     }
 
Index: branches/eam_branches/20090820/pstamp/src/pstamp.h
===================================================================
--- branches/eam_branches/20090820/pstamp/src/pstamp.h	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/src/pstamp.h	(revision 25766)
@@ -1,30 +1,4 @@
 #ifndef PSTAMP_H
 #define PSTAMP_H
-
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>  // for strcasecmp
-#include <unistd.h>   // for unlink
-#include "pslib.h"
-#include "psmodules.h"
-#include "pstampErrorCodes.h"
-
-typedef enum {
-    PSTAMP_UNKNOWN = -1,
-    PSTAMP_RAW,
-    PSTAMP_CHIP,
-    PSTAMP_WARP,
-    PSTAMP_DIFF,
-    PSTAMP_STACK
-} pstampImageType;
-
-
-// command modes for pstampparse 
-typedef enum {
-    PSP_MODE_UNKNOWN = 0,
-    PSP_MODE_QUEUE_JOB,
-    PSP_MODE_LIST_URI,
-    PSP_MODE_LIST_JOB
-} pspMode;
 
 // error codes returned to users in results flie
@@ -42,5 +16,6 @@
 	PSTAMP_NOT_AVAILABLE    = 25,
 	PSTAMP_GONE             = 26,
-	PSTAMP_NO_JOBS_QUEUED   = 27
+	PSTAMP_NO_JOBS_QUEUED   = 27,
+        PSTAMP_NO_OVERLAP       = 28
 } pstampJobErrors;
 
@@ -49,4 +24,5 @@
 #define PSTAMP_SELECT_MASK   2
 #define PSTAMP_SELECT_WEIGHT 4
+#define PSTAMP_SELECT_INVERSE 1024
 
 #define PSTAMP_CENTER_IN_PIXELS 1
@@ -59,5 +35,3 @@
 #define STAMP_RESULTS_VERSION "1"
 
-
-
 #endif
Index: branches/eam_branches/20090820/pstamp/src/pstampGetROI.c
===================================================================
--- branches/eam_branches/20090820/pstamp/src/pstampGetROI.c	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/src/pstampGetROI.c	(revision 25766)
@@ -3,5 +3,5 @@
 #endif
 
-#include "pstamp.h"
+#include "pstampint.h"
 #include "pstampROI.h"
 #include "ohana.h"
Index: branches/eam_branches/20090820/pstamp/src/pstampdump.c
===================================================================
--- branches/eam_branches/20090820/pstamp/src/pstampdump.c	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/src/pstampdump.c	(revision 25766)
@@ -1,7 +1,7 @@
-// pstampdump  - read a fits table describing a postage stamp request or response file and
+// pstampdump  - read a fits file  containing a postage stamp request or response table and
 //               print the contents to stdout
 //
-//              Actually should work for any kind of fits table, but I'm not sure what will
-//              happen for binary data.
+//              Actually this should work fine for dumping the rows of any of any kind of fits table
+//              The -header option is pstamp table specific
 
 #include <pslib.h>
@@ -9,22 +9,35 @@
 #include <string.h>
 
-static psArray *readRequestTable(psString fileName)
+static bool readFitsFile(psString fileName, psMetadata **pHeader, psArray **pTable)
 {
-    psFits *fitsFile = psFitsOpen(fileName, "r");
-    if (fitsFile == NULL) {
+    psFits *fits = psFitsOpen(fileName, "r");
+    if (fits == NULL) {
         psError(PS_ERR_IO, false, "failed to open %s for output", fileName);
-        return NULL;
+        return false;
+    }
+    if (!psFitsMoveExtNum(fits, 1, true)) {
+        psError(PS_ERR_IO, false, "failed to move to first extension from %s", fileName);
+        return false;
     }
 
-    psArray *array = psFitsReadTable(fitsFile);
+    if (pHeader) {
+        *pHeader = psFitsReadHeader(NULL, fits);
+        if (!*pHeader) {
+            psError(PS_ERR_IO, false, "failed to header from %s", fileName);
+            return false;
+        }
+    }
 
-    psFitsClose(fitsFile);
+    if (pTable) {
+        *pTable = psFitsReadTable(fits);
+        if (*pTable == NULL) {
+            psError(PS_ERR_IO, false, "psFitsReadTable failed for %s", fileName);
+            return false;
+        }
+    }
 
-    if (array == NULL) {
-        psError(PS_ERR_IO, false, "psFitsReadTable failed for %s", fileName);
-        return NULL;
-    } 
+    psFitsClose(fits);
 
-    return array;
+    return true;
 }
 
@@ -32,9 +45,28 @@
 usage(char *program_name)
 {
-    fprintf(stderr, "usage: %s filename\n", program_name);
+    fprintf(stderr, "usage: %s [-header] [-simple] filename\n", program_name);
     exit(1);
 }
+
 int main(int argc, char *argv[])
 {
+    bool dumpHeader = false;
+    bool simple = false;
+    bool dumpTable = true;
+    int argnum;
+    if ((argnum = psArgumentGet(argc, argv, "-header"))) {
+        dumpHeader = true;
+        psArgumentRemove(argnum, &argc, argv);
+    }
+    if ((argnum = psArgumentGet(argc, argv, "-simple"))) {
+        simple = true;
+        psArgumentRemove(argnum, &argc, argv);
+    }
+    if ((argnum = psArgumentGet(argc, argv, "-headeronly"))) {
+        dumpTable = false;
+        dumpHeader = true;
+        psArgumentRemove(argnum, &argc, argv);
+    }
+
     if (argc != 2) {
         usage(argv[0]);
@@ -43,29 +75,92 @@
     psString fileName = argv[1];
 
-    psArray *array = readRequestTable(fileName);
-    if (array == NULL) {
-        psErrorStackPrint(stderr, "failed to read fits table: %s\n", fileName);
+    psMetadata *header;
+    psArray *array;
+    if (!readFitsFile(fileName, dumpHeader ? &header : NULL, dumpTable ? &array : NULL)) {
+        psErrorStackPrint(stderr, "failed to process fits table from: %s\n", fileName);
+        return PS_EXIT_DATA_ERROR;
+    }
+    if (dumpHeader) {
+        psString extname = psMetadataLookupStr(NULL, header, "EXTNAME");
+        if (!extname) {
+            psErrorStackPrint(stderr, "failed to find EXTNAME in fits header of: %s\n", fileName);
+            return PS_EXIT_DATA_ERROR;
+        }
+        psString req_name = psMetadataLookupStr(NULL, header, "REQ_NAME");
+        if (!req_name) {
+            psErrorStackPrint(stderr, "failed to find REQ_NAME in fits header of: %s\n", fileName);
+            return PS_EXIT_DATA_ERROR;
+        }
+        if (!strcmp(extname, "PS1_PS_REQUEST")) {
+            psString extver = psMetadataLookupStr(NULL, header, "EXTVER");
+            if (!extver) {
+                // work around bug in MOPS request files
+                // Accept an integer for the version number
+                psS32 extver_num = psMetadataLookupS32(NULL, header, "EXTVER");
+                if (extver_num) {
+                    psStringAppend(&extver, "%d", extver_num);
+                } else {
+                    psErrorStackPrint(stderr, "failed to find EXTVER in fits header of: %s\n", fileName);
+                    return PS_EXIT_DATA_ERROR;
+                }
+            }
+            printf("%s %s %s\n", extname, extver, req_name);
+        } else if (!strcmp(extname, "PS1_PS_RESULTS")) {
+            psS64 req_id = psMetadataLookupS64(NULL, header, "REQ_ID");
+            printf("%s %s %" PRId64 "\n", extname, req_name, req_id);
+        } else {
+            psErrorStackPrint(stderr, "do not recognize extname: %s in %s\n", extname, fileName);
+            return PS_EXIT_DATA_ERROR;
+        }
+    }
+    if (!dumpTable) {
+        // done
+        return 0;
+    }
+
+    if (!psArrayLength(array)) {
+        fprintf(stderr, "%s contains an empty table\n", fileName);
         return 1;
     }
 
-    if (!psArrayLength(array)) {
-        fprintf(stderr, "%s is an empty table\n", fileName);
-        exit(1);
-    }
-
-//    printf("FITS_TABLE METADATA\n");
     for (int i=0; i<psArrayLength(array); i++) {
-        printf("ROW_%d METADATA\n", i);
-        // psMetadataPrint(stderr, array->data[i], 0);
-        // psMetadataConfigWrite(array->data[i], "-");
         psString str = psMetadataConfigFormat(array->data[i]);
         if (!str) {
-            psErrorStackPrint(stderr, "Can't write to STDOUT\n");
-            exit(PS_EXIT_SYS_ERROR);
+            psErrorStackPrint(stderr, "failed to format metadata item\n");
+            return (PS_EXIT_SYS_ERROR);
         }
-        printf("%s", str);
-        printf("END\n");
+        if (!simple) {
+            printf("ROW_%d METADATA\n", i);
+            printf("%s", str);
+            printf("END\n");
+        } else {
+            // simple output format space separated values one line per row
+            char *p = str;
+            char *pnl;
+            while ((pnl = strchr(p, '\n'))) {
+                // terminate the string for this line
+                *pnl = 0;
+                bool blank = (p == pnl);
+                if (blank) {
+                    p = pnl + 1;
+                    continue;
+                }
+                // split line into space separated tokens
+                char *name = strtok(p, " ");
+                char *type = strtok(NULL, " ");
+                char *val = strtok(NULL, " ");
+
+                // avoid unused variables warning/error
+                (void) name; (void) type;
+
+                if (val) {
+                    printf("%s ", val);
+                }
+                // next line
+                p = pnl + 1;
+            }
+            printf("\n");
+        }
     }
-//   printf("END\n");
 
     return 0;
Index: branches/eam_branches/20090820/pstamp/src/pstampint.h
===================================================================
--- branches/eam_branches/20090820/pstamp/src/pstampint.h	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/src/pstampint.h	(revision 25766)
@@ -0,0 +1,31 @@
+#ifndef PSTAMP_INT_H
+#define PSTAMP_INT_H
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>  // for strcasecmp
+#include <unistd.h>   // for unlink
+#include "pslib.h"
+#include "psmodules.h"
+#include "pstampErrorCodes.h"
+
+#include "pstamp.h"
+typedef enum {
+    PSTAMP_UNKNOWN = -1,
+    PSTAMP_RAW,
+    PSTAMP_CHIP,
+    PSTAMP_WARP,
+    PSTAMP_DIFF,
+    PSTAMP_STACK
+} pstampImageType;
+
+
+// command modes for pstampparse 
+typedef enum {
+    PSP_MODE_UNKNOWN = 0,
+    PSP_MODE_QUEUE_JOB,
+    PSP_MODE_LIST_URI,
+    PSP_MODE_LIST_JOB
+} pspMode;
+
+#endif
Index: branches/eam_branches/20090820/pstamp/src/pstamprequest.c
===================================================================
--- branches/eam_branches/20090820/pstamp/src/pstamprequest.c	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/src/pstamprequest.c	(revision 25766)
@@ -1,5 +1,5 @@
 #include <pslib.h>
 #include <string.h>
-#include "pstamp.h"
+#include "pstampint.h"
 #include "pstampROI.h"
 
Index: branches/eam_branches/20090820/pstamp/test/asteroid.txt
===================================================================
--- branches/eam_branches/20090820/pstamp/test/asteroid.txt	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/test/asteroid.txt	(revision 25766)
@@ -0,0 +1,30 @@
+# Sample Postage stamp request description file
+# This can be parsed by the program pstamp_req_create to build a 
+# PS1_PSTAMP_REQUEST binary table
+
+# First line of data is for the extension header
+# The order of keywords follows TABLE 6 of ICD
+#
+# Note that value for REQ_NAME may be overriden by a command line
+# argument to pstamp_req_create.
+# Blank and comment lines are ignored
+
+# REQ_NAME EXTVER
+CHANGEME     1
+
+# subsequent lines define the rows in the table
+#
+
+# These coordinates get stamps from warp and diff images that show a moving object that mops found.
+
+# ID    |     ROI Specification                   |  JOB Specification | Images of interest specification
+# ROWNUM CENTER_X         CENTER_Y         WIDTH HEIGHT COORD_MASK JOB_TYPE OPTION_MASK PROJECT REQ_TYPE IMG_TYPE    ID   TESS_ID COMPONENTLABEL REQFILT MJD_MIN MJD_MAX | COMMENT
+#
+1        284.688522833822 -3.86916140936841 200  200        2       stamp    3           gpc1     bydiff   warp      362483  NULL    NULL   null  null    0       0      | 
+2        284.688522833822 -3.86916140936841 200  200        2       stamp    3           gpc1     bydiff   diff      362483  NULL    NULL   null  null    0       0      | 
+3        284.688522833822 -3.86916140936841 200  200        2       stamp    1027        gpc1     bydiff   warp      362483  NULL    NULL   null  null    0       0      | 
+4        284.688522833822 -3.86916140936841 200  200        2       stamp    1027        gpc1     bydiff   diff      362483  NULL    NULL   null  null    0       0      | 
+
+
+
+
Index: branches/eam_branches/20090820/pstamp/test/byskycell.txt
===================================================================
--- branches/eam_branches/20090820/pstamp/test/byskycell.txt	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/test/byskycell.txt	(revision 25766)
@@ -0,0 +1,33 @@
+# Sample Postage stamp request description file
+# This can be parsed by the program pstamp_req_create to build a 
+# PS1_PSTAMP_REQUEST binary table
+
+# First line of data is for the extension header
+# The order of keywords follows TABLE 6 of ICD
+#
+# Note that value for REQ_NAME may be overriden by a command line
+# argument to pstamp_req_create.
+# Blank and comment lines are ignored
+
+# REQ_NAME      EXTVER
+byskycell_test     1
+
+# subsequent lines define the rows in the table
+
+################################ OLD Format
+#
+# ROWNUM PROJECT JOB_TYPE OPTION_MASK REQ_TYPE IMG_TYPE    ID      TESS_ID COMPONENT   COORD_MASK CENTER_X   CENTER_Y WIDTH HEIGHT REQFILT MJD_MIN MJD_MAX
+# warps from various epochs for one of the SN candidates. Specifiying the skycell speeds up processing
+# 1         gpc1   stamp      1        byskycell    warp     null   MD07 skycell.044 2 214.509667604725 52.5181290488877  200 200 null 55009 55011
+
+
+
+# If ROWNUM is set to zero, pstamp_request_file will set insert a value for each row beginning with 1
+# If a later input row reuses a value an error occurs
+
+# ID    |     ROI Specification                   |  JOB Specification | Images of interest specification
+# ROWNUM CENTER_X         CENTER_Y         WIDTH HEIGHT COORD_MASK JOB_TYPE OPTION_MASK PROJECT REQ_TYPE IMG_TYPE    ID   TESS_ID COMPONENT    LABEL  REQFILT MJD_MIN MJD_MAX | COMMENT
+#
+0        214.509667604725 52.5181290488877 200    200      2        stamp       1        gpc1    byskycell warp      null   MD07   skycell.044  null   i.00000   54938  54939   |i filter
+0        214.509667604725 52.5181290488877 200    200      2        stamp       1        gpc1    byskycell warp      null   MD07   skycell.044  null   r.00000   54950  54951   |r filter
+9        214.509667604725 52.5181290488877 200    200      2        stamp       1        gpc1    byskycell warp      null   MD07   skycell.044  MD07.200905.v1   g.00000   54979.451  54979.55   |g filter use label too
Index: branches/eam_branches/20090820/pstamp/test/gpc1_sample.txt
===================================================================
--- branches/eam_branches/20090820/pstamp/test/gpc1_sample.txt	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/test/gpc1_sample.txt	(revision 25766)
@@ -0,0 +1,45 @@
+# Sample Postage stamp request description file
+# This can be parsed by the program pstamp_req_create to build a 
+# PS1_PSTAMP_REQUEST binary table
+
+# First line of data is for the extension header
+# The order of keywords follows TABLE 6 of ICD
+#
+# Note that value for REQ_NAME may be overriden by a command line
+# argument to pstamp_req_create.
+# Blank and comment lines are ignored
+
+# REQ_NAME EXTVER
+CHANGEME     1
+
+# subsequent lines define the rows in the table
+
+## ID    |     ROI Specification                   |  JOB Specification | Images of interest specification 
+# ROWNUM CENTER_X       CENTER_Y WIDTH HEIGHT COORD_MASK JOB_TYPE OPTION_MASK PROJECT REQ_TYPE IMG_TYPE    ID   TESS_ID COMPONENT    LABEL REQFILT MJD_MIN MJD_MAX | COMMENT
+# warps from various epochs for one of the SN candidates. Specifiying the skycell speeds up processing
+1        242.400666     55.273513 200   200     2          stamp    1          gpc1   byid      warp     6245   null    skycell.077   null null     0        0     |
+2        242.400666     55.273513 200   200     2          stamp    1          gpc1   byid      warp     6254   null    skycell.077   null null     0        0     |
+3        242.400666     55.273513 200   200     2          stamp    1          gpc1   byid      warp     6264   null    skycell.077   null null     0        0     |
+4        242.400666     55.273513 200   200     2          stamp    1          gpc1   byid      warp     6317   null    skycell.077   null null     0        0     |
+5        242.400666     55.273513 200   200     2          stamp    1          gpc1   byid      warp     6324   null    skycell.077   null null     0        0     |
+6        242.400666     55.273513 200   200     2          stamp    1          gpc1   byid      warp     6465   null    skycell.077   null null     0        0     |
+7        242.400666     55.273513 200   200     2          stamp    1          gpc1   byid      warp     6466   null    skycell.077   null null     0        0     |
+
+# get a specific warp
+10        242.400666     55.273513 200   200     2          stamp    1         gpc1   byid      warp     6316   null     skycell.077   null null     0        0     |
+
+# get stamps from all warps for exposure (only destreaked ones will succeed)
+11        242.400666     55.273513 200   200     2          stamp    1         gpc1   byexp     warp  o4973g0123o   null skycell.077   null null     0        0     |
+
+# get stamps from all chipRuns for exposure (only destreaked ones will succeed)
+# add the mask and weight images as well
+12        242.400666     55.273513 200   200     2          stamp    7         gpc1   byexp  chip  o4973g0123o   null    skycell.077   null null     0        0     |
+
+# get the corresponding diff
+13        242.400666     55.273513 200   200     2          stamp    1        gpc1   byexp   diff  o4973g0123o   null    null         null null     0        0     |
+
+# get the stack that was the template for that stack
+14        242.400666     55.273513 200   200     2          stamp    1         gpc1   byid    stack      14031   null     null        null null     0        0     |
+
+# get the same stamp by go through the diff
+15        242.400666     55.273513 200   200     2          stamp    1         gpc1   bydiff   stack    193939   null     null        null null     0        0     |
Index: branches/eam_branches/20090820/pstamp/test/pstamp_req_create
===================================================================
--- branches/eam_branches/20090820/pstamp/test/pstamp_req_create	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/test/pstamp_req_create	(revision 25766)
@@ -1,3 +1,6 @@
 #!/usr/bin/env perl
+
+print STDERR "This script is obsolete. See ../scripts/pstamp_request_file\n";
+exit 1;
 
 # create a Postage Stamp Request file from a textual description
Index: branches/eam_branches/20090820/pstamp/test/sample_query.txt
===================================================================
--- branches/eam_branches/20090820/pstamp/test/sample_query.txt	(revision 25206)
+++ 	(revision )
@@ -1,57 +1,0 @@
-# Sample Detectability Query description file used by the program
-# detect_query_create
-
-# First line of data is for the extension header
-# The order of keywords follows TABLE 6 of ICD
-# Note that value for QUERY_ID may be overriden by a command line
-# argument to detect_query_create.
-# Blank and comment lines are ignored
-
-# QUERY_ID EXTVER FPA_ID       MJD-OBS FILTER OBSCODE
-QUERY42       1   o4608g0103o   54608     g     566
-
-# subsequent lines define the rows in the table
-
-# ROWNUM     RA1_DEG        DEC1_DEG    RA2_DEG     DEC2_DEG     MAG
-1            312.44049389 30.54022727  312.44051968 30.54024139  18.4228     
-2            313.03337881 31.01317194  313.03344194 31.01324268  18.3961     
-3            312.91159232 30.95195459  312.91153476 30.95190113  18.1110     
-4            312.26742527 30.95207284  312.26744769 30.95206300  17.0908     
-5            313.20263734 30.62317841  313.20266984 30.62310935  18.2890     
-6            312.85365023 30.45667552  312.85358645 30.45661659  16.9252     
-7            312.86257534 30.73005531  312.86264564 30.73012644  16.5870     
-8            312.62651492 30.28398046  312.62654595 30.28390213  16.6911     
-9            312.30703743 30.99927709  312.30708709 30.99927981  17.4722     
-10           312.95440987 30.21452885  312.95434880 30.21444691  18.5156     
-11           313.09947609 30.93800421  313.09940219 30.93795549  17.8855     
-12           312.97417836 31.11301952  312.97423473 31.11296140  16.9911     
-13           313.11781918 30.37359317  313.11784695 30.37360958  16.7468     
-14           312.76927925 30.53972354  312.76933224 30.53976126  16.8949     
-15           313.14717536 30.25958068  313.14710913 30.25951218  16.8300     
-16           312.30604633 30.88958513  312.30599425 30.88959415  18.2257     
-17           312.43565662 30.43038293  312.43560908 30.43037934  19.0005     
-18           312.55589195 30.81649562  312.55594584 30.81655133  18.6992     
-19           312.48925222 30.79092013  312.48924050 30.79087193  19.2099     
-20           312.94560207 31.15170816  312.94554641 31.15162988  17.2162     
-21           313.19589134 30.74674862  313.19594142 30.74682054  16.6793     
-22           312.70278940 30.52926292  312.70271911 30.52926109  19.0436     
-23           312.56015422 30.77354938  312.56021167 30.77360353  19.2750     
-24           312.87989916 30.78926857  312.87996776 30.78920032  18.2502     
-25           312.81101394 30.65212801  312.81096654 30.65215390  18.5487     
-26           312.55607541 30.23260894  312.55612602 30.23263745  17.2404     
-27           312.47366234 31.02186968  312.47372919 31.02192895  18.9959     
-28           312.90062087 31.13704835  312.90061590 31.13697785  17.5652     
-29           313.01177949 31.16629118  313.01181621 31.16626516  17.0270     
-30           312.40371494 30.98672316  312.40366292 30.98677392  19.1234     
-31           312.56662477 31.01082034  312.56665651 31.01078413  17.6238     
-32           312.61398923 30.64616956  312.61399907 30.64618259  18.5522     
-33           313.07268041 30.96857880  313.07272131 30.96859005  17.7002     
-34           312.36144521 30.43367984  312.36146205 30.43373589  16.6557     
-35           312.74549146 30.89623741  312.74554546 30.89630365  18.8037     
-36           312.49256362 30.78465056  312.49260740 30.78459825  16.7909     
-37           312.92641571 30.76107785  312.92634812 30.76111408  17.2734     
-38           312.84561663 30.38510072  312.84561100 30.38515538  18.3349     
-39           312.48297202 31.08290934  312.48297374 31.08290383  17.6822     
-40           312.27670734 30.89704117  312.27664961 30.89698871  17.4518     
-41           312.82856967 30.65880493  312.82859245 30.65878537  18.8543     
-42           313.05680974 30.97207965  313.05672748 30.97211785  16.6627     
Index: branches/eam_branches/20090820/pstamp/test/sample_simtest.txt
===================================================================
--- branches/eam_branches/20090820/pstamp/test/sample_simtest.txt	(revision 25206)
+++ 	(revision )
@@ -1,31 +1,0 @@
-# Sample Postage stamp request description file
-# This can be parsed by the program pstamp_req_create to build a 
-# PS1_PSTAMP_REQUEST binary table
-
-# First line of data is for the extension header
-# The order of keywords follows TABLE 6 of ICD
-#
-# Note that value for REQ_NAME may be overriden by a command line
-# argument to pstamp_req_create allowing this file to be re-used.
-# Blank and comment lines are ignored
-
-# REQ_NAME EXTVER
-PSREQ00001     1
-
-# subsequent lines define the rows in the table
-
-# ROWNUM PROJECT       JOB_TYPE OPTION_MASK REQ_TYPE IMG_TYPE    ID            CLASS_ID COORD_MASK CENTER_X CENTER_Y WIDTH HEIGHT REQFILT MJD_MIN MJD_MAX
-# select by exposure name
-1        simtest        stamp      1           byexp    chip   simtest.004.000  null      3       500     500         100    100     null   0    0
-
-# select by database id this happens to select the  same image a row 1 using 'chip_id'
-2        simtest        stamp      1           byid     chip      2           null        3       600     500         100    100     null   0    0
-
-# stamp from a chip processed image that resulted in diff_id = 1 sky coords for center, pixels for range
-3        simtest        stamp      1           bydiff   chip      1           null        2      270.733 -23.7039     500    500     null   0    0
-
-# ... and the corespoding warp
-4        simtest        stamp      1           bydiff   warp      1           null        2      270.733 -23.7039     500    500     null   0    0
-
-# ... and the stack
-5        simtest        stamp      1           bydiff   stack     1           null        2      270.733 -23.7039     500    500     null   0    0
Index: branches/eam_branches/20090820/pstamp/web/authenticate.php
===================================================================
--- branches/eam_branches/20090820/pstamp/web/authenticate.php	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/web/authenticate.php	(revision 25766)
@@ -0,0 +1,33 @@
+<?php
+
+// function check_login()
+
+session_start();
+
+// XXX TODO use mysql
+$auth_user="setme";
+$auth_passwd="setmetoo";
+
+$user   = $_SERVER['PHP_AUTH_USER'];
+$passwd = $_SERVER['PHP_AUTH_PW'];
+$did_login = isset($_SESSION['did_login']);
+
+if ($did_login && isset($user) && isset($passwd) &&
+    ($auth_user == $user) && ($auth_passwd == $passwd)) {
+
+    echo "Welcome:  " . $user;
+    echo "&nbsp;&nbsp;&nbsp; <a href=\"./logout.php\">Logout</a>";
+    echo "<br />";
+    echo "<br />";
+} else {
+    $_SESSION['did_login'] = true;
+    header('WWW-Authenticate: Basic realm="Restricted Section"');
+    header('HTTP/1.0 401 Unauthorized');
+    // The following will be output if the user hits the cancel button
+    echo "please enter username and password";
+    echo "&nbsp;&nbsp;&nbsp;<a href=\"./upload.php\">Login</a>";
+    exit;
+}
+
+?>
+
Index: branches/eam_branches/20090820/pstamp/web/logout.php
===================================================================
--- branches/eam_branches/20090820/pstamp/web/logout.php	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/web/logout.php	(revision 25766)
@@ -0,0 +1,18 @@
+<?php
+
+// require_once "authenticate.php";
+
+// logout();
+session_start();
+$_SESSION = array();
+if (isset($_COOKIE[session_name()])) {
+    setcookie(session_name(), '', time()-42000, '/');
+}
+session_destroy();
+
+echo "You are now logged out<br /><br />";
+echo "<a href=\"./upload.php\">Upload</a>";
+
+// phpinfo(32);
+?>
+
Index: branches/eam_branches/20090820/pstamp/web/pstamp.php
===================================================================
--- branches/eam_branches/20090820/pstamp/web/pstamp.php	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/web/pstamp.php	(revision 25766)
@@ -0,0 +1,6 @@
+<?php
+
+require_once "pstampconfig.php";
+require_once "authenticate.php";
+
+?>
Index: branches/eam_branches/20090820/pstamp/web/pstampconfig.php
===================================================================
--- branches/eam_branches/20090820/pstamp/web/pstampconfig.php	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/web/pstampconfig.php	(revision 25766)
@@ -0,0 +1,19 @@
+<?php
+// BEGIN Local configuration
+
+$WORKDIR = "set to the location of pstamp working directory";
+$dsroot = "set to the root of the data store";
+$dbname = "set to the pstamp database name";
+$dbserver = "set to the pstamp database server";
+
+$PSCONFDIR = "";
+$PSCONFIG  = "";
+$PSBINDIR  = "$PSCONFDIR/$PSCONFIG.lin64/bin";
+
+// END Local configuration 
+
+# this script sets up the environment to run IPP commands with current directory
+# $WORKDIR
+$SCRIPT    = "$PSBINDIR/pstamp_runcommand.sh $PSCONFDIR $PSCONFIG $WORKDIR";
+
+?>
Index: branches/eam_branches/20090820/pstamp/web/request.php
===================================================================
--- branches/eam_branches/20090820/pstamp/web/request.php	(revision 25206)
+++ branches/eam_branches/20090820/pstamp/web/request.php	(revision 25766)
@@ -17,12 +17,15 @@
 
 
+// XXX: change to include pstampconfig.php
+
 // BEGIN Local configuration
 
-$WORKDIR = "XXXX/pstamp-work/web";
-$dsroot = "XXXX/datastore/dsroot";
-$dbname = "XXXX";
-
-$PSCONFDIR = "XXXX";
-$PSCONFIG  = "XXXX";
+$WORKDIR = "/data/ipp049.0/pstamp/work";
+$dsroot = "/data/ipp049.0/datastore/dsroot";
+$dbname = "ippRequestServer";
+$dbserver = "ipp049";
+
+$PSCONFDIR = "/data/ipp053.0/home/bills/psconfig";
+$PSCONFIG  = "debug";
 $PSBINDIR  = "$PSCONFDIR/$PSCONFIG.lin64/bin";
 
@@ -32,4 +35,6 @@
 # $WORKDIR
 $SCRIPT    = "$PSBINDIR/pstamp_runcommand.sh $PSCONFDIR $PSCONFIG $WORKDIR";
+
+// END of moved to pstampconfig.php
 
 // Initialize variables
@@ -95,5 +100,5 @@
 import_request_variables("gp", "rvar_");
 
-if ($rvar_project == "gpc1_rel_200901") {
+if ($rvar_project == "gpc1") {
     $gpc1_selected = "selected";
     $require_class_id = 1;
@@ -255,4 +260,5 @@
     global $command_line;
     global $dbname;
+    global $dbserver;
     global $require_class_id;
     global $PSCONFDIR, $PSCONFIG, $WORKDIR;
@@ -271,5 +277,5 @@
 
     if ($dbname) {
-        $cmd .= " --dbname $dbname";
+        $cmd .= " --dbname $dbname --dbserver $dbserver";
     }
 
@@ -281,5 +287,5 @@
     if ($making_stamps) {
         // TODO: put options on the GUI for these
-        $cmd .= " -mask -weight";
+//        $cmd .= " -mask -weight";
     }
 
@@ -406,5 +412,6 @@
                 global $dsroot;
                 $dirName  = "$dsroot/$product/$req_name";
-                $filesetURL = "/ds/$product/$req_name";
+                // XXX: TODO: make this a configuration parameter
+                $filesetURL = "http://datastore.ipp.ifa.hawaii.edu/$product/$req_name";
                 $fullpath = "$dirName/$fileName";
 // echo "<pre>fullpath: $fullpath filesetURL: $filesetURL\n</pre>";
@@ -412,5 +419,5 @@
                     // this job is done, list the url as a link
                     // echo "<a href=\"http:$path\" target=\"_blank\" type=\"image/fits\">";
-                    echo "<a href=\"http:$filesetURL\">";
+                    echo "<a href=\"$filesetURL\" TARGET=\"form_results_fileset\">";
 #                    echo $fileName;
                     $filesetName = basename($dirName);
@@ -463,6 +470,7 @@
     $command_line = "$SCRIPT pstamp_listjobs.pl $request_id";
     global $dbname;
+    global $dbserver;
     if ($dbname) {
-        $command_line .= " --dbname $dbname";
+        $command_line .= " --dbname $dbname --dbserver $dbserver";
     }
 
@@ -495,9 +503,10 @@
     global $outFileset;
     global $dbname;
+    global $dbserver;
     global $SCRIPT;
 
     $command_line = "$SCRIPT pstamptool -listreq -req_id $request_id -simple";
     if ($dbname) {
-        $command_line .= " -dbname $dbname";
+        $command_line .= " -dbname $dbname -dbserver $dbserver";
     }
     // echo "Running $command_line\n";
@@ -566,7 +575,9 @@
     <tr><td><b>Project:</b>&nbsp;&nbsp;&nbsp;</td>
         <td><select name="project">
-           <option <?php echo $gpc1_selected;?> >gpc1_rel_200901
+           <option <?php echo $gpc1_selected;?> >gpc1
+<!--
            <option <?php echo $mops_selected;?> >megacam-mops
            <option <?php echo $simtest_selected;?> >simtest
+-->
         </td>
     </tr>
@@ -596,9 +607,9 @@
     <td>
         <select name="img_type">" >
-            <option <?php echo $raw_selected;?>   >raw
             <option <?php echo $chip_selected;?>  >chip
             <option <?php echo $warp_selected ;?> >warp
             <option <?php echo $stack_selected;?> >stack   
             <option <?php echo $diff_selected;?>  >diff
+            <option <?php echo $raw_selected;?>   >raw
         </select>
     </td>
@@ -611,5 +622,5 @@
 &nbsp;&nbsp;&nbsp;&nbsp;
 <b>
-<?php if (0 && $rvar_project == "gpc1_rel_200901") {
+<?php if (0 && $rvar_project == "gpc1") {
         echo "Chip ID:";
       } else {
Index: branches/eam_branches/20090820/pstamp/web/upload.php
===================================================================
--- branches/eam_branches/20090820/pstamp/web/upload.php	(revision 25766)
+++ branches/eam_branches/20090820/pstamp/web/upload.php	(revision 25766)
@@ -0,0 +1,115 @@
+<?php // upload.php
+
+// get the locatl configuration variables
+include "pstamp.php";
+
+
+$user = $_SERVER['PHP_AUTH_USER'];
+$passwd = $_SERVER['PHP_AUTH_PW'];
+echo "<HTML>
+<head>
+    <title>
+        Upload Postage Stamp Request File
+    </title>
+<body>
+";
+
+// echo "Hello $user $passwd";
+
+echo <<<_END
+    <form method="post" enctype="multipart/form-data" action="">
+        <label>Postage Stamp Request File:
+        <input type="file" name='filename' accept='image/x-fits' /></label>
+    <br />
+    <br />
+    <input type="submit" value="Upload" />
+    &nbsp; &nbsp; &nbsp;
+    <input type="reset" name="cancel" value="Cancel"/>
+    <br />
+    </form>
+    <br />
+_END;
+
+$command = "";
+if ($_FILES) {
+    $name = $_FILES['filename']['name'];
+    $tmp_name = $_FILES['filename']['tmp_name'];
+    $type = $_FILES['filename']['type'];
+    $size = $_FILES['filename']['size'];
+
+    if ($name && ($size > 0)) {
+  //      echo "Uploaded $size bytes for '$type' file '$name' as '$tmp_name'<br />";
+        $command = "$SCRIPT pstamp_insert_request.pl --tmp_req_file $tmp_name --dbname $dbname --dbserver $dbserver --workdir $WORKDIR";
+    }
+}
+
+class Request
+{
+    public $id;
+    public $name;
+    function __construct($p1, $p2)
+    {
+        $this->id = $p1;
+        $this->name = $p2;
+    }
+}
+
+if (!isset($_SESSION['requests'])) {
+//    echo "initializing requests\n";
+//    echo "<br />";
+    $_SESSION['requests'] = array();
+}
+
+// echo "<br />SCRIPT is <br />$SCRIPT";
+$req_id = 0;
+$req_name = "";
+$new_request = 0;
+if ($command) {
+    $command = escapeshellcmd($command);
+   // echo "<br />command:<br />$command";
+    echo "<br />";
+    exec($command, $output, $command_status);
+    if ($command_status == 0) {
+        // it worked!
+        $req_id = $output[0];
+        // get rid of any whitespace in req_name
+        $req_name = trim($output[1]);
+        echo "Submitted Request ID:&nbsp; $req_id Request Name: &nbsp; $req_name<br \>";
+        $new_request = new Request($req_id, $req_name);
+        $num = count($_SESSION['requests']);
+//        echo "request array length: $num<br />";
+        $_SESSION['requests'][$num] = $new_request;
+        $num = count($_SESSION['requests']);
+//        echo "after request array length: $num<br />";
+    } else if ($command_status == 5) {
+        // PS_EXIT_DATA_ERROR
+        echo "Error:&nbsp;&nbsp;&nbsp;";
+        for ($i=0; $i < count($output); $i++) {
+            echo $output[$i];
+        }
+        echo "<br />\n";
+    } else {
+        echo "Unexpected Error.<br /> insert command returned $command_status<br \>";
+    }
+}
+echo "<br />";
+
+foreach ($_SESSION['requests'] as $req) {
+    echo "<br />";
+    echo $req->id;
+    echo "&nbsp;&nbsp";
+    $name = $req->name;
+    echo "&nbsp;&nbsp";
+    // XXX: get this data store product location a configuation
+    echo "<a href=\"http://datastore.ipp.ifa.hawaii.edu/pstampresults/$name\" TARGET=\"upload_results_fileset\">$name</a>\n";
+}
+echo "<br />";
+
+// print lots of information
+// phpinfo(-1);
+// print the most useful variables
+// phpinfo(32);
+
+echo "</body></html>";
+
+?>
Index: branches/eam_branches/20090820/pswarp/src/pswarpArguments.c
===================================================================
--- branches/eam_branches/20090820/pswarp/src/pswarpArguments.c	(revision 25206)
+++ branches/eam_branches/20090820/pswarp/src/pswarpArguments.c	(revision 25766)
@@ -74,9 +74,4 @@
     pswarpSetThreads ();
 
-    // PSF determination?
-    if ((N = psArgumentGet(argc, argv, "-psf"))) {
-        psArgumentRemove(N, &argc, argv);
-        psMetadataAddBool(config->arguments, PS_LIST_TAIL, "PSF", 0, "Do PSF determination?", true);
-    }
     if ((N = psArgumentGet(argc, argv, "-dumpconfig"))) {
         psArgumentRemove(N, &argc, argv);
@@ -163,4 +158,10 @@
     }
 
+    bool PSF = psMetadataLookupBool(&status, recipe, "PSF"); ///< Generate a PSF model?
+    if (!status) {
+	PSF = true;
+        psWarning("PSF is not set in the %s recipe --- defaulting to TRUE.", PSWARP_RECIPE);
+    }
+
     // Set recipe values in the recipe (since we've possibly altered some)
     psMetadataAddS32(recipe, PS_LIST_TAIL, "GRID.NX", PS_META_REPLACE,
@@ -174,4 +175,5 @@
     psMetadataAddF32(recipe, PS_LIST_TAIL, "POOR.FRAC", PS_META_REPLACE,
                      "Fraction of bad flux for a pixel to be marked as poor", poorFrac);
+    psMetadataAddBool(recipe, PS_LIST_TAIL, "PSF", PS_META_REPLACE, "Generate a PSF Model?", PSF);
 
     // Set recipe values in the arguments
@@ -186,4 +188,5 @@
     psMetadataAddF32(config->arguments, PS_LIST_TAIL, "POOR.FRAC", 0,
                      "Fraction of bad flux for a pixel to be marked as poor", poorFrac);
+    psMetadataAddBool(config->arguments, PS_LIST_TAIL, "PSF", PS_META_REPLACE, "Generate a PSF Model?", PSF);
 
     psTrace("pswarp", 1, "Done with pswarpArguments...\n");
Index: branches/eam_branches/20090820/pswarp/src/pswarpDefine.c
===================================================================
--- branches/eam_branches/20090820/pswarp/src/pswarpDefine.c	(revision 25206)
+++ branches/eam_branches/20090820/pswarp/src/pswarpDefine.c	(revision 25766)
@@ -65,4 +65,9 @@
         int numCols = psMetadataLookupS32(NULL, hdu->header, "NAXIS1"); ///< Number of columns
         int numRows = psMetadataLookupS32(NULL, hdu->header, "NAXIS2"); ///< Number of rows
+	if ((numCols == 0) || (numRows == 0)) {
+            psError(PS_ERR_UNKNOWN, false, "skycell has invalid dimensions %d x %d", numCols, numRows);
+            psFree(view);
+            return false;
+        }
 
         pmCell *target = pmFPAviewThisCell(view, output->fpa); ///< Target cell
Index: branches/eam_branches/20090820/pswarp/src/pswarpLoop.c
===================================================================
--- branches/eam_branches/20090820/pswarp/src/pswarpLoop.c	(revision 25206)
+++ branches/eam_branches/20090820/pswarp/src/pswarpLoop.c	(revision 25766)
@@ -16,5 +16,4 @@
 
 #define WCS_NONLIN_TOL 0.001            // Non-linear tolerance for header WCS
-#define PSPHOT_FIND_PSF 1               // Use psphot's findPSF function?
 #define TESTING 0                       // Testing output?
 
@@ -380,5 +379,5 @@
     // that's going to be tricky.  We have a list of sources, so we use those to redetermine the PSF model.
 
-    if (psMetadataLookupBool(&mdok, config->arguments, "PSF")) {
+    if (psMetadataLookupBool(&mdok, recipe, "PSF")) {
         fileActivation(config, photFiles, true);
         ioChecksBefore(config);
@@ -397,4 +396,6 @@
             return false;
         }
+
+        pmModelClassSetLimits(PM_MODEL_LIMITS_STRICT);
 
         // measure the PSF using these sources
Index: branches/eam_branches/20090820/pswarp/src/pswarpParseCamera.c
===================================================================
--- branches/eam_branches/20090820/pswarp/src/pswarpParseCamera.c	(revision 25206)
+++ branches/eam_branches/20090820/pswarp/src/pswarpParseCamera.c	(revision 25766)
@@ -126,6 +126,12 @@
     }
 
+    psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSWARP_RECIPE);
+    if (!recipe) {
+        psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSWARP_RECIPE);
+        return false;
+    }
+
     bool mdok;                          // Status of MD lookup
-    if (psMetadataLookupBool(&mdok, config->arguments, "PSF")) {
+    if (psMetadataLookupBool(&mdok, recipe, "PSF")) {
         // This file, PSPHOT.INPUT, is just used as a carrier; output files (eg, PSPHOT.RESID) are defined by
         // psphotDefineFiles
Index: branches/eam_branches/20090820/pswarp/src/pswarpTransformSources.c
===================================================================
--- branches/eam_branches/20090820/pswarp/src/pswarpTransformSources.c	(revision 25206)
+++ branches/eam_branches/20090820/pswarp/src/pswarpTransformSources.c	(revision 25766)
@@ -102,4 +102,5 @@
         new->sky = source->sky;
         new->skyErr = source->skyErr;
+        new->apRadius = source->apRadius;
 
         new->modelPSF = pmModelAlloc(source->modelPSF->type);
@@ -135,5 +136,5 @@
         new->modelPSF->nIter = model->nIter;
         new->modelPSF->flags = model->flags;
-        new->modelPSF->radiusFit = model->radiusFit;
+        new->modelPSF->fitRadius = model->fitRadius;
 
         psArrayAdd(outSources, SOURCE_ARRAY_BUFFER, new);
Index: branches/eam_branches/20090820/tools/examine_burntool_pcontrol.pl
===================================================================
--- branches/eam_branches/20090820/tools/examine_burntool_pcontrol.pl	(revision 25766)
+++ branches/eam_branches/20090820/tools/examine_burntool_pcontrol.pl	(revision 25766)
@@ -0,0 +1,221 @@
+#!/usr/bin/perl -w
+
+# script to print out information about the current status of a burntool run.
+use DBI;
+use Getopt::Std;
+
+getopts('hfcPv:',\%opt);
+if (exists($opt{h})) {
+    print STDERR "Usage: examine_burntool_pcontrol.pl [-f] <pcontrol.pro>\n";
+    print STDERR "         -f          Read all burntool entries, even those commented out.\n";
+    print STDERR "         -c          Print out the needed mysql statement to do a convert. DOES NOT EXECUTE THIS!\n";
+    print STDERR "         -v <val>    Use this value as the target burntool_state in convert statements.\n";
+    print STDERR "         -P          Print out the ipp_apply_burntool.pl commands, even if fully updated.\n";
+    print STDERR "\n";
+    print STDERR "         Reads in the pcontrol.pro file you're using to run burntool, and uses the\n";
+    print STDERR "         date ranges included there to query the database to tell you the current\n";
+    print STDERR "         status of the processing.  On the OTA grid:\n";
+    print STDERR "                  _             Blank chip\n";
+    print STDERR "                  N             Null/zero value for burntool_state. No burntool attempted.\n";
+    print STDERR "                  O             -1 value for burntool_state. Burntool is running.\n";
+    print STDERR "                  E             -2 value for burntool_state. Error!\n";
+    print STDERR "                  B             Current version value for burntool_state. Burntool succeeded.\n";
+    print STDERR "                  b             Old version value for burntool_state. Burntool needs to be rerun.\n";
+    print STDERR "                  ?             No matching rawImfile entry found in database.\n";
+    exit(1);
+}
+$| = 1;
+# 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";
+while(<LAZY>) {
+    chomp;
+    if ($_ =~ /BURNTOOL.STATE.GOOD/) {
+	@line = split /\s+/;
+	$burntoolStateGood = $line[2];
+    }
+}
+close(LAZY);
+unless( $burntoolStateGood == 999) {
+    print STDERR "GOOD == $burntoolStateGood\n";
+}
+$convert_bt_state = -1.0 * $burntoolStateGood;
+
+# Read a class_id and burntool_state pair, and set the correct cell of the (sorry, global) character array vector
+sub class_to_vector {
+    my $class = shift;
+    my $burntool_state = shift;
+    my $char = '_';
+    if (abs($burntool_state) == $burntoolStateGood) {
+	$char = '[32;01mB[m';
+	$burncount++;
+    }
+    elsif ($burntool_state == -1) {
+	$char = '[01;33mP[m';
+    }
+    elsif ($burntool_state == 0) {
+	$char = '[31mO[m';
+    }
+    elsif ($burntool_state == -2) {
+	$char = '[35;01;44;05mE[m';
+    }
+    elsif ($burntool_state == -3) {
+	$char = '[34mX[m';
+    }
+    else {
+	$char = '[32mb[m';
+    }
+    
+    my @cv = split //, $class;
+
+    my $id = $cv[2] * 8 + $cv[3];
+    if (($id == 0)||($id == 7)||($id == 63)||($id == 56)) {
+	die "impossible chip";
+    }
+    $vector[$id] = $char;
+}
+# Engauge autoflush, in case the database server is acting up.
+$| = 1;
+
+# Load the pcontrol.pro file, and create arrays of the dates included
+$file = shift(@ARGV);
+if (!defined($file)) {
+    system("$0 -h");
+    exit(1);
+}
+else {
+    @date_min = ();
+    @date_max = ();
+    open(F,$file);
+    while(<F>) {
+       chomp;
+       if (exists($opt{f})) {
+	   $_ =~ s/^\s*?#//;
+       }
+       $_ =~ s/^\s+//;
+
+       if ($_ =~ /^burntool /) {
+	   ($burncount,$start,$end) = split /\s+/; #lazy variable reuse
+           push @date_min, $start;
+           push @date_max, $end;
+
+       }
+    }
+    close(F);
+}
+
+# Set up the database
+use constant DB_SOCKET => '/var/run/mysqld/mysqld.sock';
+$dbname = 'gpc1';
+$dbserver = 'ippdb01';
+$dbuser = 'ipp';
+$dbpass = 'ipp';
+$db = DBI->connect("DBI:mysql:database=${dbname};host=${dbserver};" .
+                   "mysql_socket=" . DB_SOCKET(),
+                   ${dbuser},${dbpass}, 
+		   { RaiseError => 1, AutoCommit => 1}
+		   ) or die "Unable to connect to database $DBI::errstr\n";
+
+
+
+# Get the data for each date range we're running burntool over
+for ($i = 0; $i <= $#date_min; $i++) {
+    $dmin = $date_min[$i];
+    $dmax = $date_max[$i];
+    # Get the data.  The limit is there to keep the database happy.  I don't think you can observe that many
+    # images on a single night.
+    $sth = "SELECT exp_id,exp_name,obs_mode,dateobs,class_id,burntool_state,comment FROM rawImfile WHERE dateobs >= '${dmin}' AND dateobs <= '${dmax}' order by dateobs limit 600000";
+
+    $data_ref = $db->selectall_arrayref( $sth );
+
+
+    # Reset
+    $cur_exp_id = -99;
+    $burncount = 0;
+    for ($j = 0; $j < 64; $j++) {
+	$vector[$j] = '_';
+    }
+
+    # Print out query for clarity, and the header:
+    print "#### $sth\n";
+    if (exists($opt{c})) {
+	if (exists($opt{v})) {
+	    $no_sth = "UPDATE rawImfile SET burntool_state = $opt{v} WHERE dateobs >= '${dmin}' AND dateobs <= '${dmax}';";
+	}
+	else {
+	    $no_sth = "UPDATE rawImfile SET burntool_state = $convert_bt_state WHERE dateobs >= '${dmin}' AND dateobs <= '${dmax}';";
+	}
+	print "#### $no_sth\n";
+    }
+    print "#                                                     0       1       2       3       4       5       6       7       \n";
+    print "#exp_i exp_name       obs_mode dateobs             nB 0123456701234567012345670123456701234567012345670123456701234567 comment\n";
+    
+    # If the database returns no entries (because we have a mistake in pcontrol.pro perhaps), return a null entry.
+    if ($#{ $data_ref } == -1) {
+	$cur_exp_id = -99;
+	$burncount = 0;
+	for ($j = 0; $j < 64; $j++) {
+	    $vector[$j] = '_';
+	}
+    }
+    
+    foreach $row_ref (@{ $data_ref }) {
+	($exp_id,$exp_name, $obs_mode,$dateobs,$class_id,$burntool_state,$comment) = @{ $row_ref };
+
+	# Correct for nulls in the database.
+	if (!defined($obs_mode)) {
+	    $obs_mode = 'NULL';
+	}
+	if (!defined($burntool_state)) {
+	    $burntool_state = 0;
+	}
+	if (!defined($comment)) {
+	    $comment = ' ';
+	}
+#	print "$exp_id $class_id $burntool_state\n";
+	# If we're still working on the same exp_id, update the chip we got
+	if ($exp_id == $cur_exp_id) {
+	    class_to_vector($class_id,$burntool_state);
+	}
+	else {
+	    # otherwise, print, reset, and update
+	    $V = join '', @vector;
+	    
+	    if ($cur_exp_id != -99) {
+		printf("%6d %11s %11s %19s %2d %64s %s\n",
+		       $cur_exp_id,$cur_exp_name,$cur_obs_mode,$cur_dateobs,$burncount, $V,$cur_comment);
+		$burncount = 0;
+		for ($j = 0; $j < 64; $j++) {
+		    if (($j == 0)||($j == 7)||($j == 63)||($j == 56)) {
+			$vector[$j] = '_';
+		    }
+		    else {
+			$vector[$j] = '[36;40;01m?[m';
+		    }
+		}
+	    }
+	    ($cur_exp_id,$cur_exp_name,$cur_obs_mode,$cur_dateobs,$cur_comment) = ($exp_id,$exp_name,$obs_mode,$dateobs,$comment);
+	    class_to_vector($class_id,$burntool_state);
+	}
+    }
+    # Final entry needs a manual print to clear it out. Let's tack on a footer as well.
+    printf("%6d %11s %11s %19s %2d %64s %s\n",
+	   $cur_exp_id,$cur_exp_name,$cur_obs_mode,$cur_dateobs,$burncount, $V,$cur_comment);
+    print "#                                                     0       1       2       3       4       5       6       7       \n";
+    print "#exp_i exp_name       obs_mode dateobs             nB 0123456701234567012345670123456701234567012345670123456701234567 comment\n";
+    print"\n";
+
+    # If we didn't find that all 60 chips had succesful burntools run, print out the ipp_apply_burntool.pl command we would need to fix this:
+    if (($burncount != 60)||(exists($opt{P}))) {
+	for ($j = 0; $j < 64; $j++) {
+#	    printf("%d %s %d\n",$j, $vector[$j], ($vector[$j] !~ /B/));
+	    if (($vector[$j] !~ /B/)||(exists($opt{P}))) {
+		if ($vector[$j] ne '_') {
+		    $id = sprintf("XY%d%d",int($j / 8),$j % 8);
+		    print "#### ipp_apply_burntool.pl --class_id $id  --dateobs_begin $dmin --dateobs_end $dmax --dbname gpc1 --logfile ${id}.${dmin}.log\n";
+		}
+	    }
+	}
+    }
+    print "\n\n";	
+}
Index: branches/eam_branches/20090820/tools/ipp_apply_burntool.pl
===================================================================
--- branches/eam_branches/20090820/tools/ipp_apply_burntool.pl	(revision 25206)
+++ branches/eam_branches/20090820/tools/ipp_apply_burntool.pl	(revision 25766)
@@ -12,6 +12,6 @@
 use Carp;
 
-use IPC::Cmd 0.36 qw( can_run );
-use IPC::Run 0.36 qw( run );
+use IPC::Cmd 0.36 qw( can_run run );
+#use IPC::Run 0.36 qw( run );
 use PS::IPP::Metadata::List qw( parse_md_list );
 use PS::IPP::Config 1.01 qw( :standard );
@@ -20,15 +20,15 @@
 use Pod::Usage qw( pod2usage );
 
-my ( $class_id, $dateobs_begin, $dateobs_end, $skip_burned, $rerun_from_first, $dbname, $logfile, $verbose, $save_temps);
+my ( $class_id, $dateobs_begin, $dateobs_end, $convert, $camera, $dbname, $logfile, $verbose, $save_temps);
 GetOptions(
     'class_id=s'        => \$class_id, # chip identifier
     'dateobs_begin=s'   => \$dateobs_begin, # exposure date/time range start
     'dateobs_end=s'     => \$dateobs_end, # exposure date/time range stop
+    'camera=s'          => \$camera,     # Camera
     'dbname|d=s'        => \$dbname, # Database name
     'logfile=s'         => \$logfile,
-    'skip_burned'       => \$skip_burned,   # Print to stdout
-    'rerun_from_first'  => \$rerun_from_first,   # Print to stdout
     'verbose'           => \$verbose,   # Print to stdout
     'save-temps'        => \$save_temps, # Save temporary files?
+
     ) or pod2usage( 2 );
 
@@ -43,5 +43,8 @@
     defined $dbname;
 
-if ($skip_burned and $rerun_from_first) { &my_die("-rerun_from_first and -skip_burned are incompatible"); }
+unless (defined $camera) {
+    $camera = "GPC1";
+#    warn("No camera defined. Defaulting to $camera and warning.");
+}
 
 my $missing_tools;
@@ -49,5 +52,6 @@
 my $funpack  = can_run('funpack')  or (warn "Can't find funpack" and $missing_tools = 1);
 my $burntool = can_run('burntool') or (warn "Can't find burntool" and $missing_tools = 1);
-my $fpack    = can_run('fpack')    or (warn "Can't find fpack" and $missing_tools = 1);
+my $ppConfigDump = can_run('ppConfigDump') or (warn "Can't find ppConfigDump" and $missing_tools = 1);
+#my $fpack    = can_run('fpack')    or (warn "Can't find fpack" and $missing_tools = 1);
 if ($missing_tools) {
     warn("Can't find required tools.");
@@ -57,4 +61,35 @@
 my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files
 
+# IPP configuration (including nebulous)
+my $ipprc = PS::IPP::Config->new( $camera ) or my_die("Unable to set up");
+
+$ipprc->redirect_output($logfile) if $logfile;
+
+# Determine the value of a "good" burntool run.
+my $config_cmd = "$ppConfigDump -camera $camera -dump-camera - | grep BURNTOOL | uniq";
+my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+    run ( command => $config_cmd, verbose => $verbose);
+unless ($success) {
+    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+    &my_die("Unable to perform ppConfigDump: $error_code", 0, 0, $class_id, $PS_EXIT_SYS_ERROR);
+}
+
+my $recipeData = $mdcParser->parse(join "", @$stdout_buf) or
+    &my_die("Unable to parse metadata config doc", 0, 0, $class_id, $PS_EXIT_SYS_ERROR);
+
+my $burntoolStateGood = 999;
+foreach my $cfg (@$recipeData) {
+    if ($cfg->{name} eq 'BURNTOOL.STATE.GOOD') {
+	$burntoolStateGood = $cfg->{value};
+    }
+}
+if ($burntoolStateGood == 999) {
+    &my_die("Failed to determine BURNTOOL.STATE.GOOD", $burntoolStateGood, $class_id, 0, $PS_EXIT_SYS_ERROR);
+}
+my $outState = -1 * abs($burntoolStateGood);
+
+print ">>$burntoolStateGood<<\n";
+
+# Define list of images to examine.
 my $command = "$regtool -processedimfile";
 $command .= " -class_id $class_id";
@@ -64,140 +99,117 @@
 $command .= " -dbname $dbname" if defined $dbname;
 
-my @command = split /\s+/, $command;
-my ( $stdin, $stdout, $stderr ); # Buffers for running program
-print "Running [$command]...\n" if $verbose;
-if (not run(\@command, \$stdin, \$stdout, \$stderr)) {
-    &my_die("Unable to perform regtool -processedimfile");
-}
-print $stdout . "\n" if $verbose;
-
-my @files;
-my @whole = split /\n/, $stdout;
-my @single = ();
-while ( scalar @whole > 0 ) {
-    my $value = shift @whole;
-    push @single, $value;
-    if ($value =~ /^\s*END\s*$/) {
-	push @single, "\n";
-
-	my $list = parse_md_list( $mdcParser->parse( join( "\n", @single ) ) );
-	&my_die("Unable to parse output from regtool") unless defined $list;
-	push @files, @$list;
-	@single = ();
-    }
-}
-
-# IPP configuration (including nebulous)
-my $ipprc = PS::IPP::Config->new() or my_die("Unable to set up");
-
-$ipprc->redirect_output($logfile) if $logfile;
-
-my $Nfiles = @files;
-print "files: $Nfiles\n";
+( $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 regtool: $error_code", $class_id, $dateobs_begin, $dateobs_end, $PS_EXIT_SYS_ERROR);
+}
+
+my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
+    &my_die("Unable to parse metadata", $class_id, $dateobs_begin, $dateobs_end, $PS_EXIT_SYS_ERROR);
+
+my $files = parse_md_list($metadata) or
+    &my_die("Unable to parse metadata list", $class_id, $dateobs_begin, $dateobs_end, $PS_EXIT_SYS_ERROR);
 
 my $REALRUN = 1;
-my $RAWTABLES = 1;
-# XXX if we want to avoid using the raw tables in this script, we need to delay deletion of the tempfile until the next pass.
-
-# first pass: mark the db entries to catch failures
-# these will not be identified as burned by chip processing (user_1 > 0.5)
-if (! $skip_burned)  {
-    foreach my $file (@files) {
-	
-	# rerun_from_first treats the first image as already burned (if it is already burned)
-	# the artifact table from the first file is used for the rest of the sequence.
-	if ($rerun_from_first) {
-	    $skip_burned = 1;
-	    $rerun_from_first = 0;
-	    next;
-	}
-	my $exp_id = $file->{exp_id};
-
-	my $status;
-	$status = vsystem ("$regtool -dbname $dbname -updateprocessedimfile -exp_id $exp_id -class_id $class_id -user_1 0.1", 1);
+
+# Process each file in turn, checking to see if it needs processing, and doing it all in a single pass
+my $processNext = 0;
+my $previousTable = '';
+
+foreach my $file (@$files) {
+    my $exp_id = $file->{exp_id};
+    my $state = $file->{burntool_state};
+
+    my $rawImfile = $file->{uri};
+    my $rawImfileReal = $ipprc->file_resolve($rawImfile, 0);
+    
+    my $outTable  = $file->{uri};
+    $outTable  =~ s/fits$/burn.tbl/;
+    my $outTableReal = $ipprc->file_resolve($outTable, 1);
+    
+    my $process = 0;
+    my $previousTableStyle = 0;
+
+    if ($state == 0) {
+	$process = 1;
+    }
+    elsif ($state == -1) {
+	$process = 1;
+    }
+    elsif ($state == -3) {
+	$process = 1;
+    }
+    elsif ($state == -2) {
+	&my_die("Aborting as $rawImfile has modified pixel data!");
+    }
+    elsif ($state == $burntoolStateGood) {
+	$process = 0;
+	$previousTableStyle = 1;
+    }
+    elsif ($state == -1 * $burntoolStateGood) {
+	$process = 0;
+#	$previousTable = "in=$outTableReal";
+	$previousTableStyle = -1;
+    }
+    else {
+	$process = 1;
+    }
+    if ($REALRUN == 0) {
+	print "##Pretending to process as instructed!\n";
+	$process = 1;
+    }
+    if (($process == 1)||($processNext == 1)) {
+	$processNext = 1;
+	# Set state to processing
+	my $status = vsystem ("$regtool -dbname $dbname -updateprocessedimfile -exp_id $exp_id -class_id $class_id -burntool_state -1", $REALRUN);
 	if ($status) {
 	    &my_die("failed to update imfile");
 	}
-	$file->{user_1} = 0.1;
-    }
-}
-
-my $prevFileOpt = "";
-foreach my $file (@files) {
-    my $exp_id = $file->{exp_id};
-
-    my $rawImfile = $file->{uri};
-    my $rawImfileReal;
-    if ($REALRUN) {
-	$rawImfileReal = $ipprc->file_resolve($rawImfile, 0);
-    } else {
-	($rawImfileReal) = $rawImfile =~ m|^neb:/(.*)|;
-    }
-    print "rawImfile: $rawImfile -> $rawImfileReal\n";
-
-    # mangle name, create tmp file (always a UNIX file)
-    my $basename = `basename $rawImfile`; chomp $basename;
-    my $tempfile = new File::Temp ( TEMPLATE => "$basename.XXXX", 
-				    DIR => '/tmp',
-				    UNLINK => !$save_temps);
-    my $tmpImfileReal = $tempfile->filename;
-    # print "tmpImfile: $tmpImfile -> $tmpImfileReal\n";
-    
-    # destination for the burntool-applied image file (may be a NEB file)
-    my $outImfile = $rawImfile;
-    $outImfile =~ s/fits$/burn.fits/;
-    my $outImfileReal = $ipprc->file_resolve($outImfile, 1);
-    # print "outImfile: $outImfile -> $outImfileReal\n";
-
-    # burntool now can write the artifacts to the fits file.
-    # destination for the burntool artifacts.  use this if RAWTABLES is set.
-    my $artImfile;
-    my $artImfileReal;
-    if ($RAWTABLES) {
-	$artImfile = $rawImfile;
-	$artImfile =~ s/fits$/burn.tbl/;
-	$artImfileReal = $ipprc->file_resolve($artImfile, 1);
-	# print "artImfile: $artImfile -> $artImfileReal\n";
-    }
-
-    print "$rawImfile : $skip_burned, $file->{user_1}\n";
-
-    if (! ($skip_burned and ($file->{user_1} > 0.5))) {
-	print "running on: $rawImfile\n";
-        # uncompress the image (do we need to check if it is compressed?)
-        my $status = vsystem ("$funpack -S $rawImfileReal > $tmpImfileReal", $REALRUN);
-        if ($status) {
-            &my_die("failed on funpack");
-        }
-
-        if ($RAWTABLES) {
-            $status = vsystem ("$burntool $tmpImfileReal out=$artImfileReal $prevFileOpt", $REALRUN);
-        } else {
-            $status = vsystem ("$burntool $tmpImfileReal $prevFileOpt", $REALRUN);
-        }
-        if ($status) {
-            &my_die("failed on burntool");
-        }
-
-        # compress the image (do we need to check if it is compressed?)
-        $status = vsystem ("$fpack -S $tmpImfileReal > $outImfileReal", $REALRUN);
-        if ($status) {
-            &my_die("failed on fpack");
-        }
-
-        $status = vsystem ("$regtool -dbname $dbname -updateprocessedimfile -exp_id $exp_id -class_id $class_id -user_1 1.0", 1);
-        if ($status) {
-            &my_die("failed to update imfile");
-        }
-        print "\n";
-    }
-    # save the artifact file for the next image
-    if ($RAWTABLES) {
-	$prevFileOpt = "in=$artImfileReal";
-    } else {
-	$prevFileOpt = "infits=$artImfileReal";
-    }
-}
-
+	$file->{burntool_state} = -1;
+	
+	my $tempfile = new File::Temp ( TEMPLATE => "$file->{exp_name}.XXXX",
+					DIR => '/tmp/',
+					UNLINK => !$save_temps,
+					SUFFIX => '.fits');
+	my $tempPixels = $tempfile->filename;
+	
+	# Run burntool
+	$status = vsystem ("$funpack -S $rawImfileReal > $tempPixels", $REALRUN);
+	if ($status) {
+	    &my_die("failed on funpack",$exp_id,$class_id);
+	}
+	if ($previousTable ne '') {
+	    $status = vsystem ("$burntool $tempPixels $previousTable out=$outTableReal tableonly=t persist=t", $REALRUN);
+	}
+	else {
+	    $status = vsystem ("$burntool $tempPixels out=$outTableReal tableonly=t persist=t", $REALRUN);
+	}
+	if ($status) {
+	    &my_die("failed on burntool",$exp_id,$class_id);
+	}
+	
+	$status = vsystem ("$regtool -dbname $dbname -updateprocessedimfile -exp_id $exp_id -class_id $class_id -burntool_state $outState", $REALRUN);
+	if ($status) {
+	    &my_die("failed to update imfile");
+	}
+
+	$previousTableStyle = -1;
+	
+	print "\n";
+    }
+    
+    if ($previousTableStyle == 1) {
+	$previousTable = "infits=$rawImfileReal";
+    }
+    elsif ($previousTableStyle == -1) {
+	$previousTable = "in=$outTableReal";
+    }
+    else {
+	die "previousTableStyle undefined!\n";
+    }
+    
+}
+    
 exit 0;
 
@@ -218,5 +230,9 @@
 sub my_die {
     my $message = shift;
-
+    if ($#_ != -1) {
+	my $exp_id = shift;
+	my $class_id = shift;
+	vsystem("$regtool -dbname $dbname -updateprocessedimfile -exp_id $exp_id -class_id $class_id -burntool_state -3",1);
+    }
     printf STDERR "$message\n";
     exit 1;
Index: branches/eam_branches/20090820/tools/make_burntool_pcontrol.pl
===================================================================
--- branches/eam_branches/20090820/tools/make_burntool_pcontrol.pl	(revision 25766)
+++ branches/eam_branches/20090820/tools/make_burntool_pcontrol.pl	(revision 25766)
@@ -0,0 +1,407 @@
+#!/usr/bin/perl -w
+# script to generate a pcontrol.pro file to run burntool on a set of data.
+
+use DBI;
+use DateTime;
+use Getopt::Std;
+
+use constant DB_SOCKET => '/var/run/mysqld/mysqld.sock';
+
+getopts('hbPQ:d:',\%opt);
+if (exists($opt{h})) {
+    print STDERR "Usage: make_burntool_pcontrol.pl -b {-Q <SQL_WHERE> | -d <DATE> | DATE_MIN0 DATE_MAX0 DATE_MIN1 DATE_MAX1 [...]}\n";
+    print STDERR "         -Q SQL_WHERE      Generate pcontrol from a SQL WHERE query.\n";
+    print STDERR "                           (enclose in single quotes, and use double quotes inside to\n";
+    print STDERR "                            protect from the shell)\n";
+    print STDERR "         -d DATE           Specify a single day to look for.\n";
+    print STDERR "         -b                Only print burntool lines.\n";
+    print STDERR "         -P                PR images have bad obs_mode values. Work around that.\n";
+    print STDERR "\n";
+    print STDERR "         Scans the GPC1 database, and identifies \"science\" observations based on the obs_mode.\n";
+    print STDERR "         Use a 30 minute safety prelude before the first science data to make sure burntool works.\n";
+    
+    exit(1);
+}
+
+# Load database
+$dbname = 'gpc1';
+$dbserver = 'ippdb01';
+$dbuser = 'ipp';
+$dbpass = 'ipp';
+$db = DBI->connect("DBI:mysql:database=${dbname};host=${dbserver};" .
+                   "mysql_socket=" . DB_SOCKET(),
+                   ${dbuser},${dbpass}, 
+		   { RaiseError => 1, AutoCommit => 1}
+		   ) or die "Unable to connect to database $DBI::errstr\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' => 0, ' ' => 0);
+if (exists($opt{P})) {
+    $science{Unknown} = 1;
+}
+# Zero the arrays.
+@dates_min = ();
+@dates_max = ();
+
+# Parse SQL query and fill any valid dates to the arrays
+if (exists($opt{Q})) {
+    $opt{Q} =~ s/\"/\'/g;
+    $sth = "SELECT dateobs FROM rawExp WHERE $opt{Q}";
+    $data_ref = $db->selectall_arrayref( $sth );
+
+    %day_keys = ();
+    foreach $row_ref (@{ $data_ref }) {
+	($day,$time) = split /\s+/, ${ $row_ref }[0];
+
+	unless (exists($day_keys{$day})) {
+	    push @dates_min, $day;
+	    
+	    ($year,$mon,$date) = split /-/, $day;
+	    $date++;
+	    push @dates_max, sprintf("%04d-%02d-%02d",$year,$mon,$date);
+	    $day_keys{$day} = 1;
+#	    print ">>>D $day $#dates_min\n";
+	}
+    }
+}
+# Read a single date, and calculate the end and insert
+elsif (exists($opt{d})) {
+    push @dates_min, $opt{d};
+    ($year,$mon,$date) = split /-/, $opt{d};
+    $date++;
+    push @dates_max, sprintf("%04d-%02d-%02d",$year,$mon,$date);
+}
+# Just shift the supplied values into the arrays.
+else {
+    if ($#ARGV == -1) {
+	system("$0 -h");
+	exit(-1);
+    }
+	
+    while ($#ARGV > -1) {
+	push @dates_min, shift(@ARGV);
+	push @dates_max, shift(@ARGV);
+    }
+}
+unless(exists($opt{b})) {
+    print_prologue();
+}
+# Save the query used in the pcontrol to be safe.
+if (exists($opt{Q})) {
+    print "##query: SELECT dateobs FROM rawExp WHERE $opt{Q}\n";
+}
+#for ($d = 0; $d <= $#dates_min; $d++) {
+while ($#dates_min > -1) {
+    $date_min = shift(@dates_min);
+    $date_max = shift(@dates_max);
+    
+    # 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 " .
+	"dateobs >= '${date_min}' AND dateobs <= '${date_max}' order by dateobs";
+
+    $data_ref = $db->selectall_arrayref( $sth );
+
+    $seq = 0;
+    
+    # Identify the science observations, and make a window earlier for burntool.
+    @start_s  = (0);
+    @end_s  = (0);
+    @skips = (0);
+
+    foreach $row_ref (@{ $data_ref }) {
+
+	($exp_id,$dateobs,$pontime,$exp_type,$obs_mode,$comment) = @{ $row_ref };
+	# Fix nulls in the database
+	if (!defined($obs_mode)) {
+	    $obs_mode = ' ';
+	}
+	if (!defined($comment)) {
+	    $comment = ' ';
+	}
+	
+	($date,$time) = split / /, $dateobs;
+	($year,$month,$day) = split /-/, $date;
+	($hour,$minute,$second) = split /:/, $time;
+	
+	$dt = DateTime->new( year   => $year, month  => $month, day    => $day,
+			     hour   => $hour, minute => $minute, second => $second,
+			     nanosecond => 0, time_zone => 'Pacific/Honolulu');
+	
+	$st = DateTime->new( year   => $year, month  => $month, day    => $day,
+			     hour   => $hour, minute => $minute, second => $second,
+			     nanosecond => 0, time_zone => 'Pacific/Honolulu')->subtract(minutes => 30);
+	$et = $dt->epoch();
+
+
+	if (!exists($science{$obs_mode})) {
+	    $science{$obs_mode} = 0;
+	}
+#%science = ('MD' => 1, '3PI' => 1, 'STS' => 1, 'CAL' => 1, 'M31' => 1, 'SS' => 1,
+#	    'ENGINEERING' => 0, 'NULL' => 0, 'Unknown' => 0, ' ' => 0);
+# I don't like this bit, but we need to work around the bad values of obs_mode that periodically crop up.
+# This isn't the most robust solution (which would of course be "having trustworthy obs_mode values"), but
+# it'll probably work for now.
+	if ((($science{$obs_mode} == 1)&&($comment !~ /Daytime/))||
+	    (($science{$obs_mode} == 0)&&(
+					  ($comment =~ /MD/)||($comment =~ /ThreePi/)||
+					  ($comment =~ /STS/)||($comment =~ /M31/)||
+					  ($comment =~ /CAL/)||($comment =~ /SS/))))					  
+	{
+	    if ($start_s[-1] == 0) {
+		$start_s[-1] = $et - 1800;
+		$end_s[-1] = $et + 1;
+	    }
+	    else {
+		if ($et > $end_s[-1] + 1800) {
+		    push @start_s, $et - 1800;
+		    push @end_s, $et + 1;
+		    push @skips, 0;
+		}
+		else {
+		    $end_s[-1] = $et + 1;
+		}
+	    }
+	}
+	
+	$seq++;
+
+    }
+
+    # If this night has no science exposures, skip to the next one.
+    if (($#start_s == 0) && ($start_s[0] == 0)) {
+	next;
+    }
+    # 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 };
+	if (!defined($obs_mode)) {
+	    $obs_mode = ' ';
+	}
+	if (!defined($comment)) {
+	    $comment = ' ';
+	}
+
+	($date,$time) = split / /, $dateobs;
+	($year,$month,$day) = split /-/, $date;
+	($hour,$minute,$second) = split /:/, $time;
+	
+	$dt = DateTime->new( year   => $year, month  => $month, day    => $day,
+			     hour   => $hour, minute => $minute, second => $second,
+			     nanosecond => 0, time_zone => 'Pacific/Honolulu');
+	
+	$st = DateTime->new( year   => $year, month  => $month, day    => $day,
+			     hour   => $hour, minute => $minute, second => $second,
+			     nanosecond => 0, time_zone => 'Pacific/Honolulu')->subtract(minutes => 30);
+	$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 ($i == 0) {
+		    $skips[$i]++;
+		}
+		else {
+		    if ($et > $end_s[$i-1]) {
+			$skips[$i]++;
+		    }
+		}
+	    }
+#	    print ">>>$i $start_s[$i] $skips[$i]\n";
+	}
+#	print ">>> $dateobs\n";
+    }
+
+    # Clear out windows that overlap with previous ones so we have the minimum set
+    for ($i = $#start_s; $i > 0; $i--) {
+	if ($skips[$i] == 0) {
+	    $trash = pop(@start_s);
+	    $end = pop(@end_s);
+	    $trash = pop(@skips);
+	    $end_s[-1] = $end;
+	}
+    }
+    # Print out the end points in the format burntool wants.
+    for ($i = 0; $i <= $#start_s; $i++) {
+	@start_t = localtime($start_s[$i]);
+	@end_t = localtime($end_s[$i]);
+	printf(" burntool %04d-%02d-%02dT%02d:%02d:%02d %04d-%02d-%02dT%02d:%02d:%02d\n",
+	       $start_t[5] + 1900,$start_t[4] + 1,$start_t[3],
+	       $start_t[2],$start_t[1],$start_t[0],
+	       $end_t[5] + 1900,$end_t[4] + 1,$end_t[3],
+	       $end_t[2],$end_t[1],$end_t[0]);
+    }
+    print "\n";
+}
+
+unless(exists($opt{b})) { 
+    print_epilogue();
+}
+
+##
+## These functions print out the remaining text of the pcontrol.pro script.  I've removed things
+##  that seemed superfluous.
+##
+
+sub print_prologue {
+
+    print << 'END_PROLOGUE';
+# this script sets up a series of burntool runs targetted to the appropriate machine
+
+# use the following sql to get the host table match:
+# select exp_id, exp_name, class_id, dateobs, user_1, obs_mode, uri from rawImfile where exp_id = 33750 limit 100;
+
+macro burntool
+  if ($0 != 3)
+    echo "USAGE: burntool (dateobs_begin) (dateobs_end)"
+    break
+  end
+
+  for i 0 $hostmatch:n
+    list word -split $hostmatch:$i
+    $class_id = $word:0
+    $logfile = "burntool_logs/$class_id.$1.log"
+    job -host $word:1 ipp_apply_burntool.pl --class_id $class_id --dateobs_begin $1 --dateobs_end $2 --dbname gpc1 --logfile $logfile
+  end
+end
+
+macro go
+END_PROLOGUE
+
+return(0);
+}
+
+sub print_epilogue {
+    print << 'END_EPILOGUE';
+    
+end
+
+macro setnames
+ $burntool_range:20081001 = 2008-10-01T07:50:00 2008-10-01T15:05:00
+end
+
+# for a re-run add --skip_burned:
+# job -host $word:1 ipp_apply_burntool.pl --class_id $word:0 --dateobs_begin $1 --dateobs_end $2 --dbname gpc1 --skip_burned
+
+macro loadhosts
+  for i 0 $allhosts:n
+    host add $allhosts:$i
+  end
+end
+
+# this macro may be used to complete a burntool run that exited due to error
+macro burntool_skip_burned
+  if ($0 != 3)
+    echo "USAGE: burntool (dateobs_begin) (dateobs_end)"
+    break
+  end
+
+  for i 0 $hostmatch:n
+    list word -split $hostmatch:$i
+    $class_id = $word:0
+    $logfile = "burntool_logs/$class_id.$1.log"
+    job -host $word:1 ipp_apply_burntool.pl --class_id $class_id --dateobs_begin $1 --dateobs_end $2 --dbname gpc1 --skip_burned --logfile $logfile
+  end
+end
+
+list hostmatch
+  XY01    ipp014
+  XY02    ipp014
+  XY03    ipp038
+  XY04    ipp038
+  XY05    ipp023
+  XY06    ipp023
+  XY10    ipp039
+  XY11    ipp039
+  XY12    ipp024
+  XY13    ipp024
+  XY14    ipp040
+  XY15    ipp040
+  XY16    ipp026
+  XY17    ipp026
+  XY20    ipp041
+  XY21    ipp041
+  XY22    ipp042
+  XY23    ipp042
+  XY24    ipp043 
+  XY25    ipp043
+  XY26    ipp028
+  XY27    ipp028
+  XY30    ipp044
+  XY31    ipp044
+  XY32    ipp029
+  XY33    ipp029
+  XY34    ipp045
+  XY35    ipp045
+  XY36    ipp030
+  XY37    ipp030
+  XY40    ipp046
+  XY41    ipp046
+  XY42    ipp031
+  XY43    ipp031
+  XY44    ipp047
+  XY45    ipp047
+  XY46    ipp032
+  XY47    ipp032
+  XY50    ipp048
+  XY51    ipp048
+  XY52    ipp033
+  XY53    ipp033
+  XY54    ipp049
+  XY55    ipp049
+  XY56    ipp034
+  XY57    ipp034
+  XY60    ipp050
+  XY61    ipp050
+  XY62    ipp035
+  XY63    ipp035
+  XY64    ipp051
+  XY65    ipp051
+  XY66    ipp036
+  XY67    ipp036
+  XY71    ipp052
+  XY72    ipp052
+  XY73    ipp015
+  XY74    ipp015
+  XY75    ipp053
+  XY76    ipp053
+end
+list allhosts
+  ipp043
+  ipp014
+  ipp015
+  ipp023
+  ipp024
+  ipp026
+  ipp028
+  ipp029
+  ipp030
+  ipp031
+  ipp032
+  ipp033
+  ipp034
+  ipp035
+  ipp036
+  ipp038
+  ipp039
+  ipp040
+  ipp041
+  ipp042
+  ipp044
+  ipp045
+  ipp046
+  ipp047
+  ipp048
+  ipp049
+  ipp050
+  ipp051
+  ipp052
+  ipp053
+end
+
+END_EPILOGUE
+return(0);
+}
Index: branches/eam_branches/20090820/tools/warp_inputs.pl
===================================================================
--- branches/eam_branches/20090820/tools/warp_inputs.pl	(revision 25206)
+++ branches/eam_branches/20090820/tools/warp_inputs.pl	(revision 25766)
@@ -23,4 +23,5 @@
 my ($skycell_id);               # Skycell of interest
 my ($image, $mask, $variance); # Files to contain input lists
+my ($muggle);                   # No magicked inputs?
 
 GetOptions(
@@ -34,4 +35,5 @@
            'mask=s' => \$mask,  # File with masks
            'variance=s' => \$variance, # File with variances
+           'muggle'   => \$muggle, # No magicked inputs?
            ) or die "Unable to parse arguments.\n";
 die "Unknown option: @ARGV\n" if @ARGV;
@@ -108,4 +110,11 @@
     my $file = shift;           # File to copy
 
+    if (defined $muggle) {
+        my @file = split /\//, $file;
+        my $last = pop @file;
+        push @file, "SR_$last";
+        $file = join '/', @file;
+    }
+
     my $source = `ipp_datapath.pl $file` or die "Unable to locate $file\n"; # Actual file
     chomp $source;
