Index: /branches/sc_branches/trunkTest/Ohana/src/addstar/include/addstar.h
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/addstar/include/addstar.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/addstar/include/addstar.h	(revision 29060)
@@ -209,5 +209,5 @@
 Stars     *ReadStarsSDSS          PROTO((FILE *f, char *name, Header *header, Header *in_theader, Image *images, off_t *nimages, unsigned int *nstars));
 int        ReadImageHeader        PROTO((Header *header, Image *image, int photcode));
-Stars     *FilterStars            PROTO((Stars *instars, Image *image, unsigned int imageID));
+Stars     *FilterStars            PROTO((Stars *instars, Image *image, unsigned int imageID, const AddstarClientOptions *options));
 Stars     *MergeStars             PROTO((Stars *stars, unsigned int *Nstars, Stars *instars, unsigned int Ninstars));
 double     scat_subpix            PROTO((double x, double y));
Index: /branches/sc_branches/trunkTest/Ohana/src/addstar/src/ConfigInit.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/addstar/src/ConfigInit.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/addstar/src/ConfigInit.c	(revision 29060)
@@ -212,4 +212,10 @@
   }
 
+  /* get detection filtering mask */
+  if(!ScanConfig (config, "DETECTIONFILTER", "%d", 0, &options.detectionFilter)) {
+      options.detectionFilter = 0;
+      fprintf (stderr, "Could not find 'DETECTIONFILTER' in config, using '%x'\n", options.detectionFilter);
+  }
+
   free (config);
   free (file);
Index: /branches/sc_branches/trunkTest/Ohana/src/addstar/src/FilterStars.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/addstar/src/FilterStars.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/addstar/src/FilterStars.c	(revision 29060)
@@ -10,5 +10,5 @@
 // the imageID supplied here is the sequence **within this set**
 // this value is updated based on the image table later
-Stars *FilterStars (Stars *instars, Image *image, unsigned int imageID) {
+Stars *FilterStars (Stars *instars, Image *image, unsigned int imageID, const AddstarClientOptions *options) {
 
   int j, N;
@@ -28,4 +28,6 @@
   ALLOCATE (stars, Stars, image[0].nstar);
   for (N = j = 0; j < image[0].nstar; j++) {
+
+    if (instars[j].measure.photFlags & options->detectionFilter) continue;
 
     /* allow for some dynamic filtering of star list */
@@ -100,4 +102,7 @@
     N ++;
   }
+
+  // DEBUG printf("N stars orig = %d after filter = %d\n", image[0].nstar, N);
+  
   image[0].nstar = N;
   REALLOCATE (stars, Stars, image[0].nstar);
Index: /branches/sc_branches/trunkTest/Ohana/src/addstar/src/LoadData.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/addstar/src/LoadData.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/addstar/src/LoadData.c	(revision 29060)
@@ -80,5 +80,9 @@
 	 
     inStars = ReadStarsFITS (f, headers[Nhead], headers[Ndata], &images[0][Nvalid].nstar);
-    inStars = FilterStars (inStars, &images[0][Nvalid], Nvalid);
+    if (!inStars) {
+      // XXX need to free the data here or in ReadStarsFITS on error
+      continue;
+    }
+    inStars = FilterStars (inStars, &images[0][Nvalid], Nvalid, options);
     *stars = MergeStars (*stars, Nstars, inStars, images[0][Nvalid].nstar);
     Nvalid++;
Index: /branches/sc_branches/trunkTest/Ohana/src/addstar/src/ReadStarsFITS.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/addstar/src/ReadStarsFITS.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/addstar/src/ReadStarsFITS.c	(revision 29060)
@@ -49,5 +49,5 @@
   if (stars == NULL) {
     fprintf (stderr, "ERROR: invalid table type %s\n", type);
-    exit (1);
+    return (NULL);
   }
   // Nstars is not necessarily == *nstars (The former is the number of detections, the
@@ -69,4 +69,8 @@
   swapped = FALSE;
   smpdata = gfits_table_get_SMPData (table, &Nstars, &swapped);
+  if (!smpdata) {
+    fprintf (stderr, "skipping inconsistent entry\n");
+    return (NULL);
+  }
   ZeroPt = GetZeroPoint();
 
@@ -108,4 +112,8 @@
 
   ps1data = gfits_table_get_PS1_DEV_0 (table, &Nstars, NULL);
+  if (!ps1data) {
+    fprintf (stderr, "skipping inconsistent entry\n");
+    return (NULL);
+  }
   ZeroPt = GetZeroPoint();
 
@@ -153,4 +161,8 @@
 
   ps1data = gfits_table_get_PS1_DEV_1 (table, &Nstars, NULL);
+  if (!ps1data) {
+    fprintf (stderr, "skipping inconsistent entry\n");
+    return (NULL);
+  }
   ZeroPt = GetZeroPoint();
 
@@ -212,4 +224,8 @@
 
   ps1data = gfits_table_get_CMF_PS1_V1 (table, &Nstars, NULL);
+  if (!ps1data) {
+    fprintf (stderr, "skipping inconsistent entry\n");
+    return (NULL);
+  }
   ZeroPt = GetZeroPoint();
 
@@ -284,4 +300,8 @@
 
   ps1data = gfits_table_get_CMF_PS1_V1_Alt (table, &Nstars, NULL);
+  if (!ps1data) {
+    fprintf (stderr, "skipping inconsistent entry\n");
+    return (NULL);
+  }
   ZeroPt = GetZeroPoint();
 
@@ -348,4 +368,8 @@
 
   ps1data = gfits_table_get_CMF_PS1_V2 (table, &Nstars, NULL);
+  if (!ps1data) {
+    fprintf (stderr, "skipping inconsistent entry\n");
+    return (NULL);
+  }
   ZeroPt = GetZeroPoint();
 
Index: /branches/sc_branches/trunkTest/Ohana/src/addstar/src/find_matches_refstars.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/addstar/src/find_matches_refstars.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/addstar/src/find_matches_refstars.c	(revision 29060)
@@ -218,5 +218,5 @@
     }
 
-    N = N1[i];
+    N = i;
     if (stars[N][0].found > -1) continue;
     if (!IN_REGION (stars[N][0].average.R, stars[N][0].average.D)) continue;
@@ -286,5 +286,5 @@
 
     for (j = 0; j < NREFSTAR_GROUP; j++) {
-      N = N1[i + j];
+      N = i + j;
 
       catalog[0].measure[Nmeas]          = stars[N][0].measure;
Index: /branches/sc_branches/trunkTest/Ohana/src/addstar/test/dvomerge.dvo
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/addstar/test/dvomerge.dvo	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/addstar/test/dvomerge.dvo	(revision 29060)
@@ -95,5 +95,5 @@
     subset T = t if (id == imageID[$i])
     set dT = T - time[$i]
-    vstat -q dT 
+    vstat dT 
     tapOK {abs($MEAN)  < 0.00001} "time for measure ID $i (MEAN)"
     tapOK {abs($SIGMA) < 0.00001} "time for measure ID $i (SIGMA)"
Index: /branches/sc_branches/trunkTest/Ohana/src/delstar/src/delete_imagename.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/delstar/src/delete_imagename.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/delstar/src/delete_imagename.c	(revision 29060)
@@ -19,4 +19,8 @@
 
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
 
   /* find image in db by name */
Index: /branches/sc_branches/trunkTest/Ohana/src/delstar/src/delete_times.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/delstar/src/delete_times.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/delstar/src/delete_times.c	(revision 29060)
@@ -26,4 +26,8 @@
 
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
 
   /* find images for time range, delete each image */ 
Index: /branches/sc_branches/trunkTest/Ohana/src/delstar/src/find_image_db.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/delstar/src/find_image_db.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/delstar/src/find_image_db.c	(revision 29060)
@@ -17,4 +17,8 @@
 
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
 
   Nlist = 0;
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/Makefile
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/Makefile	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/Makefile	(revision 29060)
@@ -20,5 +20,5 @@
 dvomerge     : $(BIN)/dvoconvert.$(ARCH)
 
-all: dvomerge dvoconvert
+all: dvomerge dvoconvert dvosecfilt
 
 DVOMERGE = \
@@ -58,5 +58,17 @@
 $(BIN)/dvoconvert.$(ARCH) : $(DVOCONVERT)
 
-INSTALL = dvomerge dvoconvert
+DVOSECFILT = \
+$(SRC)/dvosecfilt.$(ARCH).o \
+$(SRC)/SetSignals.$(ARCH).o \
+$(SRC)/ConfigInit.$(ARCH).o \
+$(SRC)/Shutdown.$(ARCH).o \
+$(SRC)/help.$(ARCH).o \
+$(SRC)/args.$(ARCH).o
+
+$(DVOSECFILT)  : $(INC)/dvomerge.h
+
+$(BIN)/dvosecfilt.$(ARCH) : $(DVOSECFILT)
+
+INSTALL = dvomerge dvoconvert dvosecfilt
 
 # dependancy rules for binary code #########################
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/include/dvomerge.h
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/include/dvomerge.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/include/dvomerge.h	(revision 29060)
@@ -55,5 +55,10 @@
 int  	   dvoconvert_args	  PROTO((int *argc, char **argv));
 
+void       dvosecfilt_usage       PROTO((void));
+void 	   dvosecfilt_help 	  PROTO((int argc, char **argv));
+int  	   dvosecfilt_args	  PROTO((int *argc, char **argv));
+
 int        SkyTablePopulatedRange PROTO((off_t *ns, off_t *ne, SkyTable *sky, off_t Nstart));
+int        SkyListPopulatedRange  PROTO((off_t *ns, off_t *ne, SkyList *sky, off_t Nstart));
 
 SkyList   *SkyTablePopulatedList  PROTO((SkyTable *sky));
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/SkyTablePopulatedRange.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/SkyTablePopulatedRange.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/SkyTablePopulatedRange.c	(revision 29060)
@@ -12,4 +12,27 @@
     Ns = sky[0].regions[Nstart].childS;
     Ne = sky[0].regions[Nstart].childE;
+    if (Ns == 0) {
+      fprintf (stderr, "no populated tables at an appropriate depth\n");
+      exit (1);
+    }
+    Nstart = Ns;
+  }
+
+  *ns = Ns;
+  *ne = Ne;
+  return (TRUE);
+}
+
+int SkyListPopulatedRange (off_t *ns, off_t *ne, SkyList *sky, off_t Nstart) {
+
+  off_t Ns, Ne;
+
+  // given the starting sky region, find the populated range at or below this region
+
+  Ns = Nstart;
+  Ne = Nstart + 1;
+  while (!sky[0].regions[Nstart][0].table) {
+    Ns = sky[0].regions[Nstart][0].childS;
+    Ne = sky[0].regions[Nstart][0].childE;
     if (Ns == 0) {
       fprintf (stderr, "no populated tables at an appropriate depth\n");
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/args.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/args.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/args.c	(revision 29060)
@@ -15,4 +15,22 @@
     remove_argument (N, argc, argv);
     ALTERNATE_PHOTCODE_FILE = strdup(argv[N]);
+    remove_argument (N, argc, argv);
+  }
+
+  /*** provide additional data ***/ 
+  /* restrict to a portion of the sky? */
+  UserPatch.Rmin = 0;
+  UserPatch.Rmax= 360;
+  UserPatch.Dmin = -90;
+  UserPatch.Dmax = +90;
+  if ((N = get_argument (*argc, argv, "-region"))) {
+    remove_argument (N, argc, argv);
+    UserPatch.Rmin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Rmax = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Dmin = atof (argv[N]);
+    remove_argument (N, argc, argv);
+    UserPatch.Dmax = atof (argv[N]);
     remove_argument (N, argc, argv);
   }
@@ -37,2 +55,18 @@
   return TRUE;
 }
+
+/*** check for command line options ***/
+int dvosecfilt_args (int *argc, char **argv) {
+  
+  int N;
+
+  /* extra error messages */
+  VERBOSE = FALSE;
+  if ((N = get_argument (*argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, argc, argv);
+  }
+
+  if (*argc != 3) dvosecfilt_usage();
+  return TRUE;
+}
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvo_image_merge_dbs.c	(revision 29060)
@@ -13,4 +13,9 @@
  
   images = gfits_table_get_Image (&in[0].ftable, &Nimages, &in[0].swapped);
+  if (!images) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
+
   ALLOCATE (IDmap->old, off_t, Nimages);
   ALLOCATE (IDmap->new, off_t, Nimages);
@@ -59,4 +64,6 @@
 
   off_t Nlo, Nhi, N;
+
+  if (!IDmap->Nmap) return 0;
 
   // find the a close entry below desired ID
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvoconvert.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvoconvert.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvoconvert.c	(revision 29060)
@@ -148,4 +148,8 @@
   // convert the raw image table to Image type (byteswap if needed)
   images = gfits_table_get_Image (&inDB.ftable, &Nimages, &inDB.swapped);
+  if (!images) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
 
   // update additional metadata
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvomergeUpdate.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvomergeUpdate.c	(revision 29060)
@@ -6,5 +6,5 @@
   off_t i, j, Ns, Ne;
   SkyTable *outsky, *insky;
-  SkyList *inlist;
+  SkyList *outlist, *inlist;
   Catalog incatalog, outcatalog;
   char filename[256], *input, *output;
@@ -70,4 +70,7 @@
   SkyTableSetFilenames (insky, input, "cpt");
 
+  // XXX apply this...generate the subset matching the user-selected region
+  inlist = SkyListByPatch (insky, -1, &UserPatch);
+
   // generate an output table populated at the desired depth
   outsky = SkyTableLoadOptimal (output, NULL, GSCFILE, TRUE, SKY_DEPTH, VERBOSE);
@@ -79,15 +82,21 @@
   // loop over the populatable output tables; check for data in input in the corresponding regions
 
-  SkyTablePopulatedRange (&Ns, &Ne, insky, 0);
-  depth = insky[0].regions[Ns].depth;
+  SkyListPopulatedRange (&Ns, &Ne, inlist, 0);
+  depth = inlist[0].regions[Ns][0].depth;
   
-  // loop over the populatable output regions
-  for (i = 0; i < outsky[0].Nregions; i++) {
-    if (!outsky[0].regions[i].table) continue;
-    if (VERBOSE) fprintf (stderr, "output: %s\n", outsky[0].regions[i].name);
+  // loop over the populated input regions
+  for (i = 0; i < inlist[0].Nregions; i++) {
+    if (!inlist[0].regions[i][0].table) continue;
+    if (VERBOSE) fprintf (stderr, "input: %s\n", inlist[0].regions[i][0].name);
 
-    SetPhotcodeTable(outputPhotcodes);
+    SetPhotcodeTable(inputPhotcodes);
     // load / create output catalog (if catalog does not exist, it will be created)
-    LoadCatalog (&outcatalog, &outsky[0].regions[i], outsky[0].filename[i], "w");
+    LoadCatalog (&incatalog, &inlist[0].regions[i][0], inlist[0].filename[i], "r");
+    // skip empty input catalogs
+    if (!incatalog.Naves_disk) {
+	dvo_catalog_unlock (&incatalog);
+	dvo_catalog_free (&incatalog);
+	continue;
+    }
 
     // combine only tables at equal or larger depth
@@ -97,31 +106,31 @@
     // compare to a slightly reduced footprint
     float dPos = 2.0/3600.0;
-    inlist = SkyListByBounds (insky, depth, outsky[0].regions[i].Rmin + dPos, outsky[0].regions[i].Rmax - dPos, outsky[0].regions[i].Dmin + dPos, outsky[0].regions[i].Dmax - dPos);
-    for (j = 0; j < inlist[0].Nregions; j++) {
-      if (VERBOSE) fprintf (stderr, "input : %s\n", inlist[0].regions[j][0].name);
+    outlist = SkyListByBounds (outsky, depth, inlist[0].regions[i][0].Rmin + dPos, inlist[0].regions[i][0].Rmax - dPos, inlist[0].regions[i][0].Dmin + dPos, inlist[0].regions[i][0].Dmax - dPos);
+    for (j = 0; j < outlist[0].Nregions; j++) {
+      if (VERBOSE) fprintf (stderr, "output : %s\n", outlist[0].regions[j][0].name);
 
       // load input catalog
-      SetPhotcodeTable(inputPhotcodes);
-      LoadCatalog (&incatalog, inlist[0].regions[j], inlist[0].filename[j], "r");
+      SetPhotcodeTable(outputPhotcodes);
+      LoadCatalog (&outcatalog, outlist[0].regions[j], outlist[0].filename[j], "w");
 
-      // skip empty input catalogs
-      if (!incatalog.Naves_disk) {
-	dvo_catalog_unlock (&incatalog);
-	dvo_catalog_free (&incatalog);
-	continue;
-      }
       dvo_update_image_IDs (&IDmap, &incatalog);
-      merge_catalogs_old (&outsky[0].regions[i], &outcatalog, &incatalog, RADIUS, secfiltMap);
-      dvo_catalog_unlock (&incatalog);
-      dvo_catalog_free (&incatalog);
+      merge_catalogs_old (&outsky[0].regions[j], &outcatalog, &incatalog, RADIUS, secfiltMap);
 
-      fprintf (stderr, "merged %s into %s\n", outsky[0].regions[i].name, inlist[0].regions[j][0].name);
+      outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
+
+      // if we receive a signal which would cause us to exit, wait until the full catalog is written
+      SetProtect (TRUE);
+      dvo_catalog_save (&outcatalog, VERBOSE);
+      SetProtect (FALSE);
+
+      dvo_catalog_unlock (&outcatalog);
+      dvo_catalog_free (&outcatalog);
+
+      fprintf (stderr, "merged %s into %s\n", inlist[0].regions[i][0].name, outlist[0].regions[j][0].name);
     }
-    SkyListFree (inlist);
+    SkyListFree (outlist);
 
-    outcatalog.catflags = LOAD_AVES | LOAD_MEAS | LOAD_MISS | LOAD_SECF;
-    dvo_catalog_save (&outcatalog, VERBOSE);
-    dvo_catalog_unlock (&outcatalog);
-    dvo_catalog_free (&outcatalog);
+    dvo_catalog_unlock (&incatalog);
+    dvo_catalog_free (&incatalog);
   }
 
@@ -153,5 +162,7 @@
   // load the image table 
   if (inDB.dbstate == LCK_EMPTY) {
-    Shutdown ("can't find input image catalog %s", inDB.filename);
+    // Shutdown ("can't find input image catalog %s", inDB.filename);
+    IDmap->Nmap = 0;
+    return TRUE;
   }
   if (!dvo_image_load (&inDB, VERBOSE, TRUE)) {
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvosecfilt.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvosecfilt.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvosecfilt.c	(revision 29060)
@@ -0,0 +1,90 @@
+# include "dvomerge.h"
+
+// modify the number of average photcodes : change only secfilt tables in place
+int main (int argc, char **argv) {
+
+  char filename[256], *input;
+  off_t i, j, k, Nsecfilt, NsecInput, Nstart;
+  SkyTable *insky;
+  Catalog catalog;
+  SecFilt *insec, *outsec;
+
+  SetSignals ();
+  dvosecfilt_help (argc, argv);
+  ConfigInit (&argc, argv);
+  dvosecfilt_args (&argc, argv);
+
+  input = argv[1];
+  Nsecfilt = atoi(argv[2]);
+
+  // load the sky table for the existing database
+  insky = SkyTableLoadOptimal (input, NULL, NULL, FALSE, SKY_DEPTH_HST, VERBOSE);
+  SkyTableSetFilenames (insky, input, "cpt");
+
+  // loop over all input catalogs
+  for (i = 0; i < insky[0].Nregions; i++) {
+    if (!insky[0].regions[i].table) continue;
+    if (VERBOSE) fprintf (stderr, "table: %s\n", insky[0].regions[i].name);
+
+    // set the parameters which guide catalog open/load/create
+    catalog.filename  = insky[0].filename[i];
+    catalog.Nsecfilt  = 0;
+
+    // always load all of the data (if any exists)
+    catalog.catflags  = LOAD_SECF;
+    catalog.catformat = dvo_catalog_catformat (CATFORMAT);  // set the default catformat from config data
+    catalog.catmode   = dvo_catalog_catmode (CATMODE);      // set the default catmode from config data
+
+    if (!dvo_catalog_open (&catalog, &insky[0].regions[i], VERBOSE, "w")) {
+	fprintf (stderr, "ERROR: failure to open catalog file %s\n", filename);
+	exit (2);
+    }
+
+    if (catalog.Naves_disk == 0) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    if (Nsecfilt == catalog.Nsecfilt) {
+      dvo_catalog_unlock (&catalog);
+      dvo_catalog_free (&catalog);
+      continue;
+    }
+
+    NsecInput = catalog.Nsecfilt;
+    Nstart = MIN(Nsecfilt, NsecInput);
+
+    insec = catalog.secfilt;
+    ALLOCATE (outsec, SecFilt, catalog.Naves_disk * Nsecfilt);
+
+    for (k = 0; k < catalog.Naves_disk; k++) {
+      for (j = 0; (j < catalog.Nsecfilt) && (j < Nsecfilt); j++) {
+	outsec[k*Nsecfilt + j].M  = insec[k*NsecInput + j].M;
+	outsec[k*Nsecfilt + j].dM = insec[k*NsecInput + j].dM;
+	outsec[k*Nsecfilt + j].Xm = insec[k*NsecInput + j].Xm;
+	outsec[k*Nsecfilt + j].flags  = insec[k*NsecInput + j].flags;
+	outsec[k*Nsecfilt + j].Ncode  = insec[k*NsecInput + j].Ncode;
+	outsec[k*Nsecfilt + j].Nused  = insec[k*NsecInput + j].Nused;
+	outsec[k*Nsecfilt + j].M_20   = insec[k*NsecInput + j].M_20;
+	outsec[k*Nsecfilt + j].M_80   = insec[k*NsecInput + j].M_80;
+      }
+      for (j = Nstart; j < Nsecfilt; j++) {
+	outsec[k*Nsecfilt + j].M  = NAN;
+	outsec[k*Nsecfilt + j].dM = NAN;
+	outsec[k*Nsecfilt + j].Xm = NAN_S_SHORT;
+      }
+    }
+    free (catalog.secfilt);
+    catalog.secfilt = outsec;
+    catalog.Nsecfilt = Nsecfilt;
+    catalog.Nsecf_mem = Nsecfilt * catalog.Naves_disk;
+    catalog.Nsecf_disk = Nsecfilt * catalog.Naves_disk;
+
+    dvo_catalog_save (&catalog, VERBOSE);
+    dvo_catalog_unlock (&catalog);
+    dvo_catalog_free (&catalog);
+  }
+
+  exit (0);
+}
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvoverify.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvoverify.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/dvoverify.c	(revision 29060)
@@ -154,4 +154,8 @@
   // convert the raw image table to Image type (byteswap if needed)
   images = gfits_table_get_Image (&inDB.ftable, &Nimages, &inDB.swapped);
+  if (!images) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
 
   // update additional metadata
Index: /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/help.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/help.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/dvomerge/src/help.c	(revision 29060)
@@ -4,4 +4,5 @@
   fprintf (stderr, "USAGE: dvomerge (input1) and (input2) to (output)\n");
   fprintf (stderr, "   OR: dvomerge (input) into (output)\n");
+  fprintf (stderr, "   [-region Rmin Rmax Dmin Dmax]\n");
   exit (2);
 }
@@ -10,4 +11,11 @@
 
   fprintf (stderr, "USAGE: dvoconvert (input) to (output)\n");
+
+  exit (2);
+}
+
+void dvosecfilt_usage(void) {
+
+  fprintf (stderr, "USAGE: dvosecfilt (input) -photcodes (photcodes.txt)\n");
 
   exit (2);
@@ -57,2 +65,23 @@
 }
 
+void dvosecfilt_help (int argc, char **argv) {
+
+  /* check for help request */
+  if (get_argument (argc, argv, "-help")) goto show_help;
+  if (get_argument (argc, argv, "-h"))    goto show_help;
+  return;
+
+show_help:
+
+  fprintf (stderr, "USAGE\n");
+  fprintf (stderr, "  dvosecfilt (input) (Nsecfilt)\n\n");
+
+  fprintf (stderr, "  change number of secfilt entries in photcode table (updates secfilt tables only)\n");
+ 
+  fprintf (stderr, "  optional flags:\n");
+  fprintf (stderr, "  -v                    	  : verbose mode\n");
+  fprintf (stderr, "  -help                 	  : this list\n");
+  fprintf (stderr, "  -h                    	  : this list\n\n");
+  exit (2);
+}
+
Index: /branches/sc_branches/trunkTest/Ohana/src/gastro2/src/rfits.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/gastro2/src/rfits.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/gastro2/src/rfits.c	(revision 29060)
@@ -15,4 +15,8 @@
 
   stars = gfits_table_get_SMPData (&table, &Nstars, NULL);
+  if (!stars) {
+    fprintf (stderr, "ERROR: failed to read stars\n");
+    exit (2);
+  }
 
   ALLOCATE (stardata, StarData, Nstars);
Index: /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImageExtract.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImageExtract.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImageExtract.c	(revision 29060)
@@ -32,4 +32,8 @@
   // convert database table to internal structure
   images = gfits_table_get_Image (&db.ftable, &Nimages, &db.swapped);
+  if (!images) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
   
   matches = SelectImages (argv[1], images, Nimages, &Nmatches);
Index: /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImageOverlaps.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImageOverlaps.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImageOverlaps.c	(revision 29060)
@@ -35,4 +35,8 @@
   // convert database table to internal structure
   dbImages = gfits_table_get_Image (&db.ftable, &NdbImages, &db.swapped);
+  if (!dbImages) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
   
   // for (i = 1; i < 2; i++) {
Index: /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImagesAtCoords.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImagesAtCoords.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/getstar/src/dvoImagesAtCoords.c	(revision 29060)
@@ -55,4 +55,8 @@
     // convert database table to internal structure
     dbImages = gfits_table_get_Image (&db.ftable, &NdbImages, &db.swapped);
+    if (!dbImages) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+    }
   }
   
Index: /branches/sc_branches/trunkTest/Ohana/src/imregister/src/detsearch.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/imregister/src/detsearch.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/imregister/src/detsearch.c	(revision 29060)
@@ -36,4 +36,8 @@
   if (!output.Modify && !output.Delete && !output.Altpath) gfits_db_close (&db);
   detrend = gfits_table_get_DetReg (&db.ftable, &Ndetrend, &db.swapped);
+  if (!detrend) {
+    fprintf (stderr, "ERROR: failed to read detrend info\n");
+    exit (2);
+  }
   
   match = MatchCriteria (detrend, Ndetrend, &Nmatch);          /* match basic criteria */
Index: /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imphotsearch.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imphotsearch.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imphotsearch.c	(revision 29060)
@@ -33,4 +33,8 @@
 
   image = gfits_table_get_Image (&db.ftable, &Nimage, &db.swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
 
   match = subset (image, Nimage, &Nmatch);
Index: /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imregtable.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imregtable.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imregtable.c	(revision 29060)
@@ -34,4 +34,8 @@
 
   image = gfits_table_get_RegImage (&ftable, &Nimage, NULL);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
 
   /* load database table */
Index: /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imsearch.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imsearch.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imsearch.c	(revision 29060)
@@ -30,4 +30,8 @@
 
   image = gfits_table_get_RegImage (&db.ftable, &Nimage, &db.swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
   
   match = match_criteria (image, Nimage, &Nmatch);
Index: /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imstatreg.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imstatreg.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/imregister/src/imstatreg.c	(revision 29060)
@@ -67,4 +67,8 @@
     }
     subset = gfits_table_get_RegImage (&temp_db.ftable, &Nsubset, &temp_db.swapped);
+    if (!subset) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+    }
     fprintf (stderr, "temporary database read\n");
 
@@ -93,4 +97,8 @@
     }
     image = gfits_table_get_RegImage (&image_db.ftable, &Nimage, &image_db.swapped);
+    if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+    }
     fprintf (stderr, "main database read\n");
 
Index: /branches/sc_branches/trunkTest/Ohana/src/imregister/src/photsearch.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/imregister/src/photsearch.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/imregister/src/photsearch.c	(revision 29060)
@@ -42,7 +42,15 @@
   if (output.convert) {
     photpars_old = gfits_table_get_PhotParsOld (&db.ftable, &Nphotpars, &db.swapped);
+    if (!photpars_old) {
+      fprintf (stderr, "ERROR: failed to read photometry parameters\n");
+      exit (2);
+    }
     photpars = PhotParsOld_to_PhotPars (photpars_old, Nphotpars);
   } else {
     photpars = gfits_table_get_PhotPars (&db.ftable, &Nphotpars, &db.swapped);
+    if (!photpars) {
+      fprintf (stderr, "ERROR: failed to read photometry parameters\n");
+      exit (2);
+    }
   }
 
Index: /branches/sc_branches/trunkTest/Ohana/src/imregister/src/spsearch.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/imregister/src/spsearch.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/imregister/src/spsearch.c	(revision 29060)
@@ -30,4 +30,8 @@
 
   spectrum = gfits_table_get_Spectrum (&db.ftable, &Nspectrum, &db.swapped);
+  if (!spectrum) {
+    fprintf (stderr, "ERROR: failed to read spectrum\n");
+    exit (2);
+  }
   
   match = match_criteria (spectrum, Nspectrum, &Nmatch);
Index: /branches/sc_branches/trunkTest/Ohana/src/kapa2/src/DrawFrame.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/kapa2/src/DrawFrame.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/kapa2/src/DrawFrame.c	(revision 29060)
@@ -134,6 +134,6 @@
     *minor = 0.1 * power;
     if (axis[0].areticks == 1) {
-      *major = 1.0 * power;
-      *minor = 0.2 * power;
+      *major = 0.25 * power;
+      *minor = 0.05 * power;
     }	  
   }
@@ -142,6 +142,6 @@
     *minor = 0.2 * power;
     if (axis[0].areticks == 1) {
-      *major = 2.0 * power;
-      *minor = 0.5 * power;
+      *major = 0.5 * power;
+      *minor = 0.1 * power;
     }	  
   }
@@ -150,6 +150,6 @@
     *minor = 0.5 * power;
     if (axis[0].areticks == 1) {
-      *major = 2.0 * power;
-      *minor = 0.5 * power;
+      *major = 1.0 * power;
+      *minor = 0.2 * power;
     }	  
   }
@@ -158,5 +158,5 @@
     *minor = 0.5 * power;
     if (axis[0].areticks == 1) {
-      *major = 2.5 * power;
+      *major = 1.0 * power;
       *minor = 0.5 * power;
     }	  
@@ -166,6 +166,6 @@
     *minor = 0.5 * power;
     if (axis[0].areticks == 1) {
-      *major = 5.0 * power;
-      *minor = 1.0 * power;
+      *major = 2.0 * power;
+      *minor = 0.5 * power;
     }	  
   }
@@ -215,4 +215,7 @@
   //   }
   // }
+
+  // XXX need to fix first and last value for printing label: currently prints first label
+  // too early & fails to do last label if too close
 
   // loop to find the ticks
Index: /branches/sc_branches/trunkTest/Ohana/src/libautocode/def/AddstarClientOptions.d
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libautocode/def/AddstarClientOptions.d	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libautocode/def/AddstarClientOptions.d	(revision 29060)
@@ -2,5 +2,5 @@
 EXTNAME OPTIONS
 TYPE    BINTABLE
-SIZE    80
+SIZE    84
 
 FIELD     Nsigma,           NSIGMA,               double,         match radius in terms of astrometric error 
@@ -22,2 +22,3 @@
 FIELD  	  timeref,          TIMEREF,              e_time,  	  time/date of input data (REFLIST only?)
 FIELD  	  imageID,          IMAGE_ID,             unsigned int,   reference to image
+FIELD  	  detectionFilter,  DETECTIONFILTER,      unsigned int,   filter mask for detections from smf file
Index: /branches/sc_branches/trunkTest/Ohana/src/libautocode/def/autocode.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libautocode/def/autocode.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libautocode/def/autocode.c	(revision 29060)
@@ -66,5 +66,5 @@
   if (Ncols != $SIZE) {
     fprintf (stderr, "ERROR: mis-match in table size: width is %d but should be %d bytes\n", Ncols, $SIZE);
-    exit (1);
+    return NULL;
   }
 
Index: /branches/sc_branches/trunkTest/Ohana/src/libdvo/include/dvo.h
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libdvo/include/dvo.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libdvo/include/dvo.h	(revision 29060)
@@ -85,29 +85,36 @@
 # define PHOT_MAG 0x06  /* generic magnitude; never stored */
 
-/* Image.code values.  these are codes to note bad images */
-# define ID_IMAGE_NEW   0x0000  /* no nrphot attempted */
-# define ID_IMAGE_NOCAL 0x0001  /* used within nrphot to mean "don't apply fit" */
-# define ID_IMAGE_POOR  0x0002  /* relphot says image is bad */
-# define ID_IMAGE_SKIP  0x0004  /* external information image is bad */
-# define ID_IMAGE_FEW   0x0008  /* currently too few measurements for good value */
+/* Image.code values -- these values are 32 bit (as of PS1_V1) */
+typedef enum {
+  ID_IMAGE_NEW          = 0x00000000,  /* no calibrations yet attempted */
+  ID_IMAGE_PHOTOM_NOCAL = 0x00000001,  /* user-set value used within relphot: ignore */
+  ID_IMAGE_PHOTOM_POOR  = 0x00000002,  /* relphot says image is bad (dMcal > limit) */
+  ID_IMAGE_PHOTOM_SKIP  = 0x00000004,  /* user-set value: assert that this image has bad photometry */
+  ID_IMAGE_PHOTOM_FEW   = 0x00000008,  /* currently too few measurements for photometry */
+  ID_IMAGE_ASTROM_NOCAL = 0x00000010,  /* user-set value used within relastro: ignore */
+  ID_IMAGE_ASTROM_POOR  = 0x00000020,  /* relastro says image is bad (dR,dD > limit) */
+  ID_IMAGE_ASTROM_FAIL  = 0x00000040,  /* relastro fit diverged, fit not applied */
+  ID_IMAGE_ASTROM_SKIP  = 0x00000080,  /* user-set value: assert that this image has bad astrometry */
+  ID_IMAGE_ASTROM_FEW   = 0x00000100,  /* currently too few measurements for astrometry */
+} DVOImageFlags;
 
 /* Measure.flags values -- these values are 32 bit (as of PS1_V1) */
 typedef enum {
-  ID_MEAS_NOCAL        = 0x0001,  // detection ignored for this analysis (photcode, time range) -- internal only 
-  ID_MEAS_POOR_PHOTOM  = 0x0002,  // detection is photometry outlier					     	  
-  ID_MEAS_SKIP_PHOTOM  = 0x0004,  // detection was ignored for photometry measurement			     	  
-  ID_MEAS_AREA         = 0x0008,  // detection near image edge						     
-  ID_MEAS_POOR_ASTROM  = 0x0010,  // detection is astrometry outlier					     	  
-  ID_MEAS_SKIP_ASTROM  = 0x0020,  // detection was ignored for astrometry measurement			     	  
-  ID_MEAS_USED_OBJ     = 0x0040,  // detection was used during opdate objects				     
-  ID_MEAS_USED_CHIP    = 0x0080,  // detection was used during update chips					     
-  ID_MEAS_BLEND_MEAS   = 0x0100,  // detection is within radius of multiple objects				     
-  ID_MEAS_BLEND_OBJ    = 0x0200,  // multiple detections within radius of object				     
-  ID_MEAS_UNDEF_3      = 0x0400,  // unused									     
-  ID_MEAS_UNDEF_4      = 0x0800,  // unused									     
-  ID_MEAS_BLEND_MEAS_X = 0x1000,  // detection is within radius of multiple objects across catalogs		     
-  ID_MEAS_ARTIFACT     = 0x2000,  // detection is thought to be non-astronomical				     
-  ID_MEAS_UNDEF_5      = 0x4000,  // unused									     
-  ID_MEAS_UNDEF_6      = 0x8000,  // unused									     
+  ID_MEAS_NOCAL        = 0x00000001,  // detection ignored for this analysis (photcode, time range) -- internal only 
+  ID_MEAS_POOR_PHOTOM  = 0x00000002,  // detection is photometry outlier					     	  
+  ID_MEAS_SKIP_PHOTOM  = 0x00000004,  // detection was ignored for photometry measurement			     	  
+  ID_MEAS_AREA         = 0x00000008,  // detection near image edge						     
+  ID_MEAS_POOR_ASTROM  = 0x00000010,  // detection is astrometry outlier					     	  
+  ID_MEAS_SKIP_ASTROM  = 0x00000020,  // detection was ignored for astrometry measurement			     	  
+  ID_MEAS_USED_OBJ     = 0x00000040,  // detection was used during opdate objects				     
+  ID_MEAS_USED_CHIP    = 0x00000080,  // detection was used during update chips					     
+  ID_MEAS_BLEND_MEAS   = 0x00000100,  // detection is within radius of multiple objects				     
+  ID_MEAS_BLEND_OBJ    = 0x00000200,  // multiple detections within radius of object				     
+  ID_MEAS_UNDEF_3      = 0x00000400,  // unused									     
+  ID_MEAS_UNDEF_4      = 0x00000800,  // unused									     
+  ID_MEAS_BLEND_MEAS_X = 0x00001000,  // detection is within radius of multiple objects across catalogs		     
+  ID_MEAS_ARTIFACT     = 0x00002000,  // detection is thought to be non-astronomical				     
+  ID_MEAS_UNDEF_5      = 0x00004000,  // unused									     
+  ID_MEAS_UNDEF_6      = 0x00008000,  // unused									     
 } DVOMeasureFlags;
 
@@ -147,4 +154,8 @@
   ID_STAR_USE_PM  = 0x00100000, // proper motion used (not AVE or PAR)
   ID_STAR_USE_PAR = 0x00200000, // parallax used (not AVE or PM)
+  ID_OBJ_EXT      = 0x01000000, // extended in our data (eg, PS)
+  ID_OBJ_EXT_ALT  = 0x02000000, // extended in external data (eg, 2MASS)
+  ID_OBJ_GOOD     = 0x04000000, // good-quality measurement in our data (eg, PS)
+  ID_OBJ_GOOD_ALT = 0x08000000, // good-quality measurement in external data (eg, 2MASS)
 } DVOAverageFlags;
 
Index: /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/LoadPhotcodesFITS.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/LoadPhotcodesFITS.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/LoadPhotcodesFITS.c	(revision 29060)
@@ -43,4 +43,8 @@
   if (!strcmp (extname, "DVO_PHOTCODE")) {
     PhotCode_Elixir *photcode_elixir = gfits_table_get_PhotCode_Elixir (&db.ftable, &Ncode, &db.swapped);
+    if (!photcode_elixir) {
+      fprintf (stderr, "ERROR: failed to read photcodes\n");
+      exit (2);
+    }
     photcode = PhotCode_Elixir_To_Internal (photcode_elixir, Ncode);
     free (photcode_elixir);
@@ -49,4 +53,8 @@
   if (!strcmp (extname, "DVO_PHOTCODE_ELIXIR")) {
     PhotCode_Elixir *photcode_elixir = gfits_table_get_PhotCode_Elixir (&db.ftable, &Ncode, &db.swapped);
+    if (!photcode_elixir) {
+      fprintf (stderr, "ERROR: failed to read photcodes\n");
+      exit (2);
+    }
     photcode = PhotCode_Elixir_To_Internal (photcode_elixir, Ncode);
     free (photcode_elixir);
@@ -55,4 +63,8 @@
   if (!strcmp (extname, "DVO_PHOTCODE_PS1_DEV_1")) {
     PhotCode_PS1_DEV_1 *photcode_ps1_dev_1 = gfits_table_get_PhotCode_PS1_DEV_1 (&db.ftable, &Ncode, &db.swapped);
+    if (!photcode_ps1_dev_1) {
+      fprintf (stderr, "ERROR: failed to read photcodes\n");
+      exit (2);
+    }
     photcode = PhotCode_PS1_DEV_1_To_Internal (photcode_ps1_dev_1, Ncode);
     free (photcode_ps1_dev_1);
@@ -61,4 +73,8 @@
   if (!strcmp (extname, "DVO_PHOTCODE_PS1_DEV_2")) {
     PhotCode_PS1_DEV_2 *photcode_ps1_dev_2 = gfits_table_get_PhotCode_PS1_DEV_2 (&db.ftable, &Ncode, &db.swapped);
+    if (!photcode_ps1_dev_2) {
+      fprintf (stderr, "ERROR: failed to read photcodes\n");
+      exit (2);
+    }
     photcode = PhotCode_PS1_DEV_2_To_Internal (photcode_ps1_dev_2, Ncode);
     free (photcode_ps1_dev_2);
@@ -67,4 +83,8 @@
   if (!strcmp (extname, "DVO_PHOTCODE_PS1_DEV_3")) {
     PhotCode_PS1_DEV_3 *photcode_ps1_dev_3 = gfits_table_get_PhotCode_PS1_DEV_3 (&db.ftable, &Ncode, &db.swapped);
+    if (!photcode_ps1_dev_3) {
+      fprintf (stderr, "ERROR: failed to read photcodes\n");
+      exit (2);
+    }
     photcode = PhotCode_PS1_DEV_3_To_Internal (photcode_ps1_dev_3, Ncode);
     free (photcode_ps1_dev_3);
@@ -73,4 +93,8 @@
   if (!strcmp (extname, "DVO_PHOTCODE_PS1_V1")) {
     PhotCode_PS1_V1 *photcode_ps1_v1 = gfits_table_get_PhotCode_PS1_V1 (&db.ftable, &Ncode, &db.swapped);
+    if (!photcode_ps1_v1) {
+      fprintf (stderr, "ERROR: failed to read photcodes\n");
+      exit (2);
+    }
     photcode = PhotCode_PS1_V1_To_Internal (photcode_ps1_v1, Ncode);
     free (photcode_ps1_v1);
@@ -79,4 +103,8 @@
   if (!strcmp (extname, "DVO_PHOTCODE_PS1_V2")) {
     PhotCode_PS1_V2 *photcode_ps1_v2 = gfits_table_get_PhotCode_PS1_V2 (&db.ftable, &Ncode, &db.swapped);
+    if (!photcode_ps1_v2) {
+      fprintf (stderr, "ERROR: failed to read photcodes\n");
+      exit (2);
+    }
     photcode = PhotCode_PS1_V2_To_Internal (photcode_ps1_v2, Ncode);
     free (photcode_ps1_v2);
@@ -85,4 +113,8 @@
   if (!strcmp (extname, "DVO_PHOTCODE_PS1_REF")) {
     PhotCode_PS1_REF *photcode_ps1_ref = gfits_table_get_PhotCode_PS1_REF (&db.ftable, &Ncode, &db.swapped);
+    if (!photcode_ps1_ref) {
+      fprintf (stderr, "ERROR: failed to read photcodes\n");
+      exit (2);
+    }
     photcode = PhotCode_PS1_REF_To_Internal (photcode_ps1_ref, Ncode);
     free (photcode_ps1_ref);
Index: /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/cmf-ps1-v1-alt.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/cmf-ps1-v1-alt.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/cmf-ps1-v1-alt.c	(revision 29060)
@@ -14,5 +14,5 @@
   if (ftable[0].header[0].Naxis[0] != 136) { 
     fprintf (stderr, "ERROR: wrong format for CMF_PS1_V1_Alt: "OFF_T_FMT" vs %d\n",  ftable[0].header[0].Naxis[0], 136);
-    exit (2);
+    return (NULL);
   }
 
Index: /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/coordops.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/coordops.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/coordops.c	(revision 29060)
@@ -20,5 +20,10 @@
 int XY_to_LM (double *L, double *M, double x, double y, Coords *coords) {
 
+  OhanaProjection proj;
+  OhanaProjectionMode mode;
   double X, Y, X2, XY, Y2, X3, Y3;
+
+  proj = GetProjection (coords[0].ctype);
+  mode = GetProjectionMode (proj);
 
   /** convert pixel coordinates to cartesian system **/
@@ -45,4 +50,9 @@
   }
 
+  if (mode == PROJ_MODE_CARTESIAN) {
+    *L += coords[0].crval1;
+    *M += coords[0].crval2;
+  }
+
   return (TRUE);
 }
@@ -64,11 +74,8 @@
   /** Locally Cartesian Projections **/
   if (mode == PROJ_MODE_CARTESIAN) {
-    *ra  = L + coords[0].crval1;
-    *dec = M + coords[0].crval2;
-
     /* mosaic astrometry : WRP is chip astrometry; apply mosaic (DIS) term */
     if (proj == PROJ_WRP) {
       if (!gotMosaic) return (FALSE);
-      XY_to_RD (ra, dec, *ra, *dec, &mosaic);
+      XY_to_RD (ra, dec, L, M, &mosaic);
     }
     return (TRUE);
@@ -183,5 +190,4 @@
 
   double phi, theta;
-  double Lo, Mo;
   double sphi, cphi, stht, ctht;
   double salp, calp, sdel, cdel, sdp, cdp;
@@ -201,11 +207,9 @@
     if (proj == PROJ_WRP) {
       if (!gotMosaic) return (FALSE);
-      RD_to_XY (&Lo, &Mo, ra, dec, &mosaic);
-      *L = (Lo - coords[0].crval1);
-      *M = (Mo - coords[0].crval2);
+      RD_to_XY (L, M, ra, dec, &mosaic);
       return (TRUE);
     }
-    *L = (ra  - coords[0].crval1);
-    *M = (dec - coords[0].crval2);
+    *L = ra;
+    *M = dec;
     return (TRUE);
   }
@@ -310,7 +314,17 @@
   double dX, dY, Lo, Mo, dL, dM;
   double dLdX, dLdY, dMdX, dMdY, Do;
+  OhanaProjection proj;
+  OhanaProjectionMode mode;
+
+  proj = GetProjection (coords[0].ctype);
+  mode = GetProjectionMode (proj);
 
   *x = 0;
   *y = 0;
+
+  if (mode == PROJ_MODE_CARTESIAN) {
+    L -= coords[0].crval1;
+    M -= coords[0].crval2;
+  }
 
   /* start with linear solution for X,Y */
@@ -422,4 +436,6 @@
 }
 
+enum {COORD_TYPE_NONE, COORD_TYPE_PC, COORD_TYPE_ROT, COORD_TYPE_CD, COORD_TYPE_LIN};
+
 int GetCoords (Coords *coords, Header *header) {
   
@@ -428,4 +444,5 @@
   double equinox;
   char *ctype;
+  int mode;
   
   rotate = 0.0;
@@ -437,25 +454,45 @@
   strcpy (coords[0].ctype, "NONE");
   
-  status = FALSE; 
-  if (gfits_scan (header, "CTYPE2", "%s", 1, coords[0].ctype)) {
-    status  = gfits_scan (header, "CRVAL1", "%lf", 1, &coords[0].crval1);
-    status &= gfits_scan (header, "CRPIX1", "%f", 1, &coords[0].crpix1);
-    status &= gfits_scan (header, "CRVAL2", "%lf", 1, &coords[0].crval2);  
-    status &= gfits_scan (header, "CRPIX2", "%f", 1, &coords[0].crpix2);
-
-    if (gfits_scan (header, "CDELT1", "%f", 1, &coords[0].cdelt1)) {
-      status &= gfits_scan (header, "CDELT2", "%f", 1, &coords[0].cdelt2);
-      if (gfits_scan (header, "CROTA2", "%lf", 1, &rotate)) {
-	Lambda = coords[0].cdelt2 / coords[0].cdelt1;
-	coords[0].pc1_1 =  cos(rotate*RAD_DEG);
-	coords[0].pc1_2 = -sin(rotate*RAD_DEG) * Lambda;
-	coords[0].pc2_1 =  sin(rotate*RAD_DEG) / Lambda;
-	coords[0].pc2_2 =  cos(rotate*RAD_DEG);
-      }
-      if (gfits_scan (header, "PC001001", "%f", 1, &coords[0].pc1_1)) {
-	status &= gfits_scan (header, "PC001002", "%f", 1, &coords[0].pc1_2);
-	status &= gfits_scan (header, "PC002001", "%f", 1, &coords[0].pc2_1);
-	status &= gfits_scan (header, "PC002002", "%f", 1, &coords[0].pc2_2);
-      }
+  mode = COORD_TYPE_NONE;
+  {    
+    int haveCTYPE, haveCDELT, haveCROTA, haveCDij, havePCij, haveRAo;
+    float tmp;
+    char stmp[80];
+    
+    // there are a few different representations for scale and rotation.  choose an appropriate
+    // set: (CDELTi + CROTAi), (CDELTi + PCij), (CDij), 
+
+    haveCTYPE = gfits_scan (header, "CTYPE2",   "%s", 1, stmp);
+    haveCDELT = gfits_scan (header, "CDELT1",   "%f", 1, &tmp);
+    haveCROTA = gfits_scan (header, "CROTA1",   "%f", 1, &tmp);
+    haveCDij  = gfits_scan (header, "CD1_1",    "%f", 1, &tmp);
+    havePCij  = gfits_scan (header, "PC001001", "%f", 1, &tmp);
+    haveRAo   = gfits_scan (header, "RA_O",     "%f", 1, &tmp);
+    
+    if (haveCTYPE && havePCij  && haveCDELT) { mode = COORD_TYPE_PC;   goto gotit; }
+    if (haveCTYPE && haveCROTA && haveCDELT) { mode = COORD_TYPE_ROT;  goto gotit; }
+    if (haveCTYPE && haveCDij)               { mode = COORD_TYPE_CD;   goto gotit; }
+    if (haveRAo)                             { mode = COORD_TYPE_LIN;  goto gotit; }
+    // fprintf (stderr, "no valid WCS keywords\n");
+    return (FALSE);
+  }
+  
+gotit:
+
+  status = TRUE; 
+  switch (mode) {
+    case COORD_TYPE_PC:
+      status &= gfits_scan (header, "CTYPE2", 	"%s",  1, coords[0].ctype);
+      status &= gfits_scan (header, "CRVAL1", 	"%lf", 1, &coords[0].crval1);
+      status &= gfits_scan (header, "CRPIX1", 	"%f",  1, &coords[0].crpix1);
+      status &= gfits_scan (header, "CRVAL2", 	"%lf", 1, &coords[0].crval2);  
+      status &= gfits_scan (header, "CRPIX2", 	"%f",  1, &coords[0].crpix2);
+
+      status &= gfits_scan (header, "CDELT1", 	"%f",  1, &coords[0].cdelt1);
+      status &= gfits_scan (header, "CDELT2", 	"%f",  1, &coords[0].cdelt2);
+      status &= gfits_scan (header, "PC001001", "%f",  1, &coords[0].pc1_1);
+      status &= gfits_scan (header, "PC001002", "%f",  1, &coords[0].pc1_2);
+      status &= gfits_scan (header, "PC002001", "%f",  1, &coords[0].pc2_1);
+      status &= gfits_scan (header, "PC002002", "%f",  1, &coords[0].pc2_2);
 
       /* set NPLYTERM based on header.  if NPLYTERM is missing, it should have a 
@@ -491,24 +528,48 @@
 	  break;
       }
-    } else {
-      if (gfits_scan (header, "CD1_1", "%f", 1, &coords[0].pc1_1)) {
-	status &= gfits_scan (header, "CD1_2", "%f", 1, &coords[0].pc1_2);
-	status &= gfits_scan (header, "CD2_1", "%f", 1, &coords[0].pc2_1);
-	status &= gfits_scan (header, "CD2_2", "%f", 1, &coords[0].pc2_2);
-	/* renormalize */
-	scale = hypot (coords[0].pc1_1, coords[0].pc1_2);
-	coords[0].cdelt1 = coords[0].cdelt2 = scale;
-	coords[0].pc1_1 /= scale;
-	coords[0].pc1_2 /= scale;
-	coords[0].pc2_1 /= scale;
-	coords[0].pc2_2 /= scale;
-      } else {
-	status = FALSE;
-      }
-    }
-  } else {
-    /* some of my thesis data uses this simple linear model - convert on read? */
-    if (gfits_scan (header, "RA_O", "%lf", 1, &coords[0].crval1)) {
-      status  = gfits_scan (header, "RA_X", "%f", 1, &coords[0].pc1_1);
+      break;
+
+    case COORD_TYPE_ROT:
+      status &= gfits_scan (header, "CTYPE2", "%s",  1, coords[0].ctype);
+      status &= gfits_scan (header, "CRVAL1", "%lf", 1, &coords[0].crval1);
+      status &= gfits_scan (header, "CRPIX1", "%f",  1, &coords[0].crpix1);
+      status &= gfits_scan (header, "CRVAL2", "%lf", 1, &coords[0].crval2);  
+      status &= gfits_scan (header, "CRPIX2", "%f",  1, &coords[0].crpix2);
+
+      status &= gfits_scan (header, "CDELT1", "%f", 1, &coords[0].cdelt1);
+      status &= gfits_scan (header, "CDELT2", "%f", 1, &coords[0].cdelt2);
+
+      status &= gfits_scan (header, "CROTA2", "%lf", 1, &rotate);
+      Lambda = coords[0].cdelt2 / coords[0].cdelt1;
+      coords[0].pc1_1 =  cos(rotate*RAD_DEG);
+      coords[0].pc1_2 = -sin(rotate*RAD_DEG) * Lambda;
+      coords[0].pc2_1 =  sin(rotate*RAD_DEG) / Lambda;
+      coords[0].pc2_2 =  cos(rotate*RAD_DEG);
+      break;
+
+    case COORD_TYPE_CD:
+      status &= gfits_scan (header, "CTYPE2", "%s",  1, coords[0].ctype);
+      status &= gfits_scan (header, "CRVAL1", "%lf", 1, &coords[0].crval1);
+      status &= gfits_scan (header, "CRPIX1", "%f",  1, &coords[0].crpix1);
+      status &= gfits_scan (header, "CRVAL2", "%lf", 1, &coords[0].crval2);  
+      status &= gfits_scan (header, "CRPIX2", "%f",  1, &coords[0].crpix2);
+
+      status &= gfits_scan (header, "CD1_1", "%f", 1, &coords[0].pc1_1);
+      status &= gfits_scan (header, "CD1_2", "%f", 1, &coords[0].pc1_2);
+      status &= gfits_scan (header, "CD2_1", "%f", 1, &coords[0].pc2_1);
+      status &= gfits_scan (header, "CD2_2", "%f", 1, &coords[0].pc2_2);
+      /* renormalize */
+      scale = hypot (coords[0].pc1_1, coords[0].pc1_2);
+      coords[0].cdelt1 = coords[0].cdelt2 = scale;
+      coords[0].pc1_1 /= scale;
+      coords[0].pc1_2 /= scale;
+      coords[0].pc2_1 /= scale;
+      coords[0].pc2_2 /= scale;
+      break;
+
+    case COORD_TYPE_LIN:
+      /* some of my thesis data uses this simple linear model - convert on read? */
+      status &= gfits_scan (header, "RA_O", "%lf", 1, &coords[0].crval1);
+      status &= gfits_scan (header, "RA_X", "%f", 1, &coords[0].pc1_1);
       status &= gfits_scan (header, "RA_Y", "%f", 1, &coords[0].pc1_2);
       status &= gfits_scan (header, "DEC_O", "%lf", 1, &coords[0].crval2);  
@@ -518,6 +579,7 @@
       coords[0].cdelt1 = coords[0].cdelt2 = 1.0;
       strcpy (coords[0].ctype, "GENE");
-    }
-  }
+      break;
+  }
+
   if (status) {
     if (!gfits_scan (header, "EQUINOX", "%lf", 1, &equinox)) {
@@ -530,6 +592,7 @@
     } 
   }
+
   if (!status) {
-    fprintf (stderr, "error getting all elements for coordinate mode %s\n", coords[0].ctype);
+    // fprintf (stderr, "error getting all elements for coordinate mode %s\n", coords[0].ctype);
     coords[0].crval1 = coords[0].crpix1 = coords[0].cdelt1 = 0.0;
     coords[0].crval2 = coords[0].crpix2 = coords[0].cdelt2 = 0.0;
Index: /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_catalog_mef.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_catalog_mef.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_catalog_mef.c	(revision 29060)
@@ -125,4 +125,8 @@
     /* no conversions currently defined */
     catalog[0].missing = gfits_table_get_Missing (&ftable, &catalog[0].Nmissing, NULL);
+    if (!catalog[0].missing) {
+      fprintf (stderr, "ERROR: failed to read missing\n");
+      exit (2);
+    }
     if (Nmissing != catalog[0].Nmiss_disk) {
       fprintf (stderr, "Warning: mismatch between Nmissing in PHU and Table headers ("OFF_T_FMT" vs "OFF_T_FMT")\n",  Nmissing,  catalog[0].Nmiss_disk);
Index: /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_catalog_split.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_catalog_split.c	(revision 29060)
@@ -285,4 +285,8 @@
     /* no conversions currently defined : this just does the byte swap */
     catalog[0].missing = gfits_table_get_Missing (&ftable, &Nmissing, NULL);
+    if (!catalog[0].missing) {
+      fprintf (stderr, "ERROR: failed to read missing\n");
+      exit (2);
+    }
     if (Nmissing != catalog[0].Nmiss_disk) {
       fprintf (stderr, "Warning: mismatch between Nmissing in PHU and Table headers ("OFF_T_FMT" vs "OFF_T_FMT")\n",  Nmissing,  catalog[0].Nmiss_disk);
@@ -473,4 +477,8 @@
     /* no conversions currently defined : this just does the byte swap */
     catalog[0].missing = gfits_table_get_Missing (&ftable, &Nmissing, NULL);
+    if (!catalog[0].missing) {
+      fprintf (stderr, "ERROR: failed to read missing\n");
+      exit (2);
+    }
     if (Nmissing != Nrows) {
       fprintf (stderr, "Warning: mismatch between Nmissing in PHU and Table headers ("OFF_T_FMT" vs "OFF_T_FMT")\n",  Nmissing,  Nrows);
Index: /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_convert.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_convert.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/dvo_convert.c	(revision 29060)
@@ -32,4 +32,8 @@
     Average_##TYPE *tmpAverage; \
     tmpAverage = gfits_table_get_Average_##TYPE (ftable, Naverage, NULL); \
+    if (!tmpAverage) { \
+      fprintf (stderr, "ERROR: failed to read averages\n"); \
+      exit (2); \
+    } \
     average = Average_##TYPE##_ToInternal (tmpAverage, *Naverage, primary); \
     free (tmpAverage); \
@@ -39,4 +43,8 @@
   if (!strcmp (extname, "DVO_AVERAGE")) {
     average = gfits_table_get_Average (ftable, Naverage, NULL);
+    if (!average) {
+      fprintf (stderr, "ERROR: failed to read averages\n");
+      exit (2);
+    }
     *format = DVO_FORMAT_INTERNAL;
     return (average);
@@ -111,4 +119,8 @@
     Measure_##TYPE *tmpMeasure; \
     tmpMeasure = gfits_table_get_Measure_##TYPE (ftable, Nmeasure, NULL); \
+    if (!tmpMeasure) { \
+      fprintf (stderr, "ERROR: failed to read measures\n"); \
+      exit (2); \
+    } \
     measure = Measure_##TYPE##_ToInternal (tmpMeasure, *Nmeasure); \
     free (tmpMeasure); \
@@ -118,4 +130,8 @@
   if (!strcmp (extname, "DVO_MEASURE")) {
     measure = gfits_table_get_Measure (ftable, Nmeasure, NULL);
+    if (!measure) {
+      fprintf (stderr, "ERROR: failed to read measures\n");
+      exit (2);
+    }
     *format = DVO_FORMAT_INTERNAL;
     return (measure);
@@ -190,4 +206,8 @@
     SecFilt_##TYPE *tmpSecFilt; \
     tmpSecFilt = gfits_table_get_SecFilt_##TYPE (ftable, Nsecfilt, NULL); \
+    if (!tmpSecFilt) { \
+      fprintf (stderr, "ERROR: failed to read secfilts\n"); \
+      exit (2); \
+    } \
     secfilt = SecFilt_##TYPE##_ToInternal (tmpSecFilt, *Nsecfilt); \
     free (tmpSecFilt); \
@@ -197,4 +217,8 @@
   if (!strcmp (extname, "DVO_SECFILT")) {
     secfilt = gfits_table_get_SecFilt (ftable, Nsecfilt, NULL);
+    if (!secfilt) {
+      fprintf (stderr, "ERROR: failed to read secfilts\n");
+      exit (2);
+    }
     *format = DVO_FORMAT_INTERNAL;
     return (secfilt);
@@ -263,4 +287,8 @@
     Image_Elixir *tmpimage;
     tmpimage = gfits_table_get_Image_Elixir (ftable, &Nimage, NULL);
+    if (!tmpimage) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+    }
     ftable[0].buffer = (char *) Image_Elixir_ToInternal (tmpimage, Nimage);
     free (tmpimage);
@@ -284,4 +312,8 @@
     *format = DVO_FORMAT_##FORMAT; \
     tmpimage = gfits_table_get_Image_##TYPE (ftable, &Nimage, NULL); \
+    if (!tmpimage) { \
+      fprintf (stderr, "ERROR: failed to read images\n"); \
+      exit (2); \
+    } \
     ftable[0].buffer = (char *) Image_##TYPE##_ToInternal (tmpimage, Nimage); \
     free (tmpimage); \
@@ -296,4 +328,8 @@
     Image *image;
     image = gfits_table_get_Image (ftable, &Nimage, NULL);
+    if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+    }
     *format = DVO_FORMAT_INTERNAL;
     return (TRUE);
Index: /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/skyregion_io.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/skyregion_io.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/libdvo/src/skyregion_io.c	(revision 29060)
@@ -40,4 +40,9 @@
   ALLOCATE (skytable, SkyTable, 1);
   skytable[0].regions = gfits_table_get_SkyRegion (&ftable, &skytable[0].Nregions, NULL);
+  if (!skytable[0].regions) {
+    fprintf (stderr, "ERROR: failed to read sky regions\n");
+    exit (2);
+  }
+
   ALLOCATE (skytable[0].filename, char *, skytable[0].Nregions);
   for (i = 0; i < skytable[0].Nregions; i++) {
Index: /branches/sc_branches/trunkTest/Ohana/src/markstar/src/find_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/markstar/src/find_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/markstar/src/find_images.c	(revision 29060)
@@ -26,4 +26,8 @@
 
   timage = gfits_table_get_Image (&db[0].ftable, &Ntimage, &db[0].swapped);
+  if (!timage) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    exit (2);
+  }
 
   /* set up buffers for images, temporary storage */
Index: /branches/sc_branches/trunkTest/Ohana/src/mosastro/src/rfits.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/mosastro/src/rfits.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/mosastro/src/rfits.c	(revision 29060)
@@ -32,4 +32,9 @@
   off_t Nstars;
   stars = gfits_table_get_SMPData (&table, &Nstars, NULL);
+  if (!stars) {
+    fprintf (stderr, "ERROR: failed to read stars\n");
+    exit (2);
+  }
+
   mychip[0].Nstars = Nstars;
   gfits_scan (table.header, "NAXIS1", "%d", 1, &Nx);
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.astro/cgrid.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.astro/cgrid.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.astro/cgrid.c	(revision 29060)
@@ -153,4 +153,12 @@
   SetVector (&Yvec, OPIHI_FLT, NELEMENTS);
   
+  { // sanity check
+    float Nelem;
+    Nelem = 180.0 / minorRA;
+    if (!isfinite(Nelem) || (fabs(Nelem) > 10000)) { fprintf (stderr, "absurd cgrid spacing %f\n", minorRA); return FALSE; }
+    Nelem = 180.0 / minorDEC;
+    if (!isfinite(Nelem) || (fabs(Nelem) > 10000)) { fprintf (stderr, "absurd cgrid spacing %f\n", minorDEC); return FALSE; }
+  }
+
   /***  do consecutive RA lines, first increasing **/
   OnPic = TRUE;
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/Makefile	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/Makefile	(revision 29060)
@@ -19,6 +19,7 @@
 $(SRC)/init.$(ARCH).o          \
 $(SRC)/accum.$(ARCH).o		\
+$(SRC)/applyfit1d.$(ARCH).o	\
 $(SRC)/applyfit2d.$(ARCH).o	\
-$(SRC)/applyfit1d.$(ARCH).o	\
+$(SRC)/applyfit3d.$(ARCH).o	\
 $(SRC)/box.$(ARCH).o		\
 $(SRC)/book.$(ARCH).o		\
@@ -46,4 +47,5 @@
 $(SRC)/fit1d.$(ARCH).o		\
 $(SRC)/fit2d.$(ARCH).o		\
+$(SRC)/fit3d.$(ARCH).o		\
 $(SRC)/gaussj.$(ARCH).o	\
 $(SRC)/gaussdeviate.$(ARCH).o	\
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/applyfit2d.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/applyfit2d.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/applyfit2d.c	(revision 29060)
@@ -10,5 +10,5 @@
 
   if (argc != 4) {
-    gprint (GP_ERR, "USAGE: applyfit x y z\n");
+    gprint (GP_ERR, "USAGE: applyfit2d x y z\n");
     return (FALSE);
   }
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/applyfit3d.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/applyfit3d.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/applyfit3d.c	(revision 29060)
@@ -0,0 +1,94 @@
+# include "data.h"
+
+int applyfit3d (int argc, char **argv) {
+  
+  int i, j, k, io, jo, n, order, nterm;
+  char *c, name[64];
+  double ***C, X, Y, Z;
+  opihi_flt *F;
+  Vector *xvec, *yvec, *zvec, *Fvec;
+
+  if (argc != 5) {
+    gprint (GP_ERR, "USAGE: applyfit x y z F\n");
+    return (FALSE);
+  }
+
+  c = get_variable ("Cnnn");
+  if (c == NULL) {
+    gprint (GP_ERR, "no fit available\n");
+    return (FALSE);
+  }
+  order = atof (c);
+  free (c);
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((Fvec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  // this is a bit crude, but perhaps needed
+  CastVector (xvec, OPIHI_FLT);
+  CastVector (yvec, OPIHI_FLT);
+  CastVector (zvec, OPIHI_FLT);
+  CastVector (Fvec, OPIHI_FLT);
+
+  nterm = order + 1;
+  ALLOCATE (C, double **, nterm);
+  for (i = 0; i < order + 1; i++) {
+    ALLOCATE (C[i], double *, nterm);
+    for (j = 0; j < nterm - i; j++) {
+      ALLOCATE (C[i][j], double, nterm);
+      for (k = 0; k < nterm - i - j; k++) {
+	sprintf (name, "CX%dY%dZ%d", i, j, k);
+	c = get_variable (name);
+	if (c == NULL) {
+	  gprint (GP_ERR, "missing fit term %d,%d,%d\n", i, j, k);
+	  for (io = 0; io < i; io++) {
+	    for (jo = 0; jo < j; jo++) {
+	      free (C[io][jo]);
+	    }
+	    free (C[io]);
+	  }
+	  free (C);
+	  return (FALSE);
+	}
+	C[i][j][k] = atof (c);
+	free (c);
+      }
+    }
+  }
+
+  ResetVector (Fvec, OPIHI_FLT, xvec[0].Nelements);
+  bzero (Fvec[0].elements.Flt, sizeof(opihi_flt)*zvec[0].Nelements);
+  F = Fvec[0].elements.Flt;
+
+  opihi_flt *x = xvec[0].elements.Flt;
+  opihi_flt *y = yvec[0].elements.Flt;
+  opihi_flt *z = zvec[0].elements.Flt;
+
+  for (n = 0; n < xvec[0].Nelements; n++, x++, y++, z++, F++) {
+    Z = Y = X = 1;
+    for (k = 0; k < nterm; k++) {
+      Y = Z;
+      for (j = 0; j < nterm - k; j++) {
+	X = Y;
+	for (i = 0; i < nterm - k - j; i++) {
+	  *F += C[i][j][k]*X;
+	  X = X * (*x);
+	}
+	Y = Y * (*y);
+      }
+      Z = Z * (*z);
+    }
+  }
+
+  for (i = 0; i < nterm; i++) {
+    for (j = 0; j < nterm - i; j++) {
+      free (C[i][j]);
+    }
+    free (C[i]);
+  }
+  free (C);
+
+  return (TRUE);
+}
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/fit2d.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/fit2d.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/fit2d.c	(revision 29060)
@@ -168,4 +168,15 @@
     }
 
+    /** test print **/
+    if (VERBOSE) {
+      for (i = 0; i < wterm; i++) {
+	for (j = 0; j < wterm; j++) {
+	  gprint (GP_ERR, "%g  ", c[i][j]);
+	}
+	gprint (GP_ERR, "\n");
+      }
+      gprint (GP_ERR, "-----\n");
+    }
+
     dgaussjordan (c, b, wterm, 1);
 
@@ -176,4 +187,14 @@
 	  gprint (GP_ERR, "x^%d y^%d: %g\n", nx, ny, b[i][0]);
 	}
+      }
+    }
+
+    /** test print **/
+    if (VERBOSE) {
+      for (i = 0; i < wterm; i++) {
+	for (j = 0; j < wterm; j++) {
+	  gprint (GP_ERR, "%g  ", c[i][j]);
+	}
+	gprint (GP_ERR, "\n");
       }
     }
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/fit3d.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/fit3d.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/fit3d.c	(revision 29060)
@@ -0,0 +1,352 @@
+# include "data.h"
+
+int fit3d (int argc, char **argv) {
+  
+  double **c, **b, ***s, X, Y, Z, dF1, dF2;
+  double ClipNSigma, mean, sigma, maxsigma;
+  int ix, iy, i, j, k, n, Npt, Nmask, nx, ny, nz, nterm, mterm, wterm, order;
+  int N, Weight, Quiet, ClipNiter, VERBOSE;
+  opihi_flt *x, *y, *z, *F, *dFv, *Ffit, *Ff; 
+  char name[64], *mask;
+  Vector *xvec, *yvec, *zvec, *Fvec, *dFvec;
+
+  VERBOSE = FALSE;
+  if ((N = get_argument (argc, argv, "-v"))) {
+    VERBOSE = TRUE;
+    remove_argument (N, &argc, argv);
+  }
+
+  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);
+  }
+
+  ClipNSigma = 0;
+  ClipNiter  = 1;
+  if ((N = get_argument (argc, argv, "-clip"))) {
+    remove_argument (N, &argc, argv);
+    ClipNSigma = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+    ClipNiter  = atof(argv[N]);
+    remove_argument (N, &argc, argv);
+  }
+
+  dFv = NULL;
+  dFvec = NULL;
+  Weight = FALSE;
+  if ((N = get_argument (argc, argv, "-dF"))) {
+    remove_argument (N, &argc, argv);
+    if ((dFvec = SelectVector (argv[N], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+    remove_argument (N, &argc, argv);
+    Weight = TRUE;
+  }
+
+  if (argc != 6) {
+    gprint (GP_ERR, "USAGE: fit x y z F order [-dF wt]\n");
+    return (FALSE);
+  }
+
+  if ((xvec = SelectVector (argv[1], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((yvec = SelectVector (argv[2], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((zvec = SelectVector (argv[3], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+  if ((Fvec = SelectVector (argv[4], OLDVECTOR, TRUE)) == NULL) return (FALSE);    
+
+  if (xvec[0].Nelements != yvec[0].Nelements) {
+    gprint (GP_ERR, "vectors must have same length\n");
+    return (FALSE);
+  }
+  if (xvec[0].Nelements != zvec[0].Nelements) {
+    gprint (GP_ERR, "vectors must have same length\n");
+    return (FALSE);
+  }
+  if (xvec[0].Nelements != Fvec[0].Nelements) {
+    gprint (GP_ERR, "vectors must have same length\n");
+    return (FALSE);
+  }
+  CastVector (xvec, OPIHI_FLT);
+  CastVector (yvec, OPIHI_FLT);
+  CastVector (zvec, OPIHI_FLT);
+  CastVector (Fvec, OPIHI_FLT);
+
+  if (Weight) {
+    if (xvec[0].Nelements != dFvec[0].Nelements) {
+      gprint (GP_ERR, "vectors must have same length\n");
+      return (FALSE);
+    }
+    CastVector (dFvec, OPIHI_FLT);
+  }
+  
+  order = atof (argv[5]);
+  nterm = order + 1;
+  wterm = (order + 3)*(order + 2)*(order + 1)/6;
+  mterm = (order + 2)*(order + 1)/2;
+
+  ALLOCATE (Ffit, opihi_flt, xvec[0].Nelements);
+  ALLOCATE (mask, char, xvec[0].Nelements);
+  memset (mask, 0, xvec[0].Nelements);
+
+  /* allocate the summation matrices */
+  ALLOCATE (b, double *, wterm);
+  ALLOCATE (c, double *, wterm);
+  for (i = 0; i < wterm; i++) {
+    ALLOCATE (c[i], double, wterm);
+    ALLOCATE (b[i], double, 1);
+  }
+
+  /* we initially sum the values in a cube */
+  ALLOCATE (s, double **, mterm);
+  for (i = 0; i < mterm; i++) {
+    ALLOCATE (s[i], double *, mterm);
+    for (j = 0; j < mterm; j++) {
+      ALLOCATE (s[i][j], double, mterm);
+    }
+  }
+
+  for (N = 0; N < ClipNiter; N++) {
+
+    /* init registers for current pass */
+    for (i = 0; i < wterm; i++) {
+      memset (c[i], 0, wterm*sizeof(double));
+      memset (b[i], 0, sizeof(double));
+    }
+    for (i = 0; i < mterm; i++) {
+      for (j = 0; j < mterm; j++) {
+	memset (s[i][j], 0, mterm*sizeof(double));
+      }
+    }
+
+    x = xvec[0].elements.Flt;
+    y = yvec[0].elements.Flt;
+    z = zvec[0].elements.Flt;
+    F = Fvec[0].elements.Flt;
+    if (Weight) dFv = dFvec[0].elements.Flt;
+
+    /* add up the x,y,z values */
+    for (i = 0; i < xvec[0].Nelements; i++, x++, y++, z++, F++) {
+      if (mask[i]) continue;
+      if (!finite(*x)) continue;
+      if (!finite(*y)) continue;
+      if (!finite(*z)) continue;
+      if (!finite(*F)) continue;
+      dF1 = 1.0;
+      if (Weight) { 
+	dF1 = 1.0 / SQ(*dFv);
+	dFv ++;
+      }
+      X = Y = Z = dF1;
+      for (nz = 0; nz < mterm; nz++) {
+	Y = Z;
+	for (ny = 0; ny < mterm - nz; ny++) {
+	  X = Y;
+	  for (nx = 0; nx < mterm - nz - ny; nx++) {
+	    s[nx][ny][nz] += X;
+	    X = X * (*x);
+	  }
+	  Y = Y * (*y);
+	}
+	Z = Z * (*z);
+      }
+    }
+
+    /* add up the F values */
+    x = xvec[0].elements.Flt;
+    y = yvec[0].elements.Flt;
+    z = zvec[0].elements.Flt;
+    F = Fvec[0].elements.Flt;
+    for (i = 0; i < xvec[0].Nelements; i++, x++, y++, z++, F++) {
+      if (mask[i]) continue;
+      if (!finite(*x)) continue;
+      if (!finite(*y)) continue;
+      if (!finite(*z)) continue;
+      if (!finite(*F)) continue;
+      dF1 = 1.0;
+      if (Weight) { 
+	dF1 = 1.0 / SQ(*dFv);
+	dFv ++;
+      }
+      X = Y = Z = *F*dF1;
+      j = 0;
+      for (nz = 0; nz < nterm; nz++) {
+	Y = Z;
+	for (ny = 0; ny < nterm - nz; ny++) {
+	  X = Y;
+	  for (nx = 0; nx < nterm - ny - nz; nx++, j++) {
+	    b[j][0] += X;
+	    X = X * (*x);
+	  }
+	  Y = Y * (*y);
+	}
+	Z = Z * (*z);
+      }
+    }
+
+    /* re-sort mterm x mterm matrix to wterm matrix */
+    ix = 0;
+    for (k = 0; k < nterm; k++) {
+      for (j = 0; j < nterm - k; j++) {
+	for (i = 0; i < nterm - k - j; i++, ix++) {
+	  iy = 0;
+	  for (nz = 0; nz < nterm; nz++) {
+	    for (ny = 0; ny < nterm - nz; ny++) {
+	      for (nx = 0; nx < nterm - ny - nz; nx++, iy++) {
+		c[ix][iy] = s[nx+i][ny+j][nz+k];
+	      }
+	    }
+	  }
+	}
+      }
+    }
+
+    /** test print **/
+    if (VERBOSE) {
+      for (i = 0; i < wterm; i++) {
+	for (j = 0; j < wterm; j++) {
+	  gprint (GP_ERR, "%g  ", c[i][j]);
+	}
+	gprint (GP_ERR, "\n");
+      }
+      gprint (GP_ERR, "-----\n");
+    }
+
+    dgaussjordan (c, b, wterm, 1);
+
+    /** test print **/
+    if (VERBOSE) {
+      i = 0;
+      for (nz = 0; nz < nterm; nz++) {
+	for (ny = 0; ny < nterm - nz; ny++) {
+	  for (nx = 0; nx < nterm - nz - ny; nx++, i++) {
+	    gprint (GP_ERR, "x^%d y^%d z^%d: %g\n", nx, ny, nz, b[i][0]);
+	  }
+	}
+      }
+    }
+
+    /** test print **/
+    if (VERBOSE) {
+      for (i = 0; i < wterm; i++) {
+	for (j = 0; j < wterm; j++) {
+	  gprint (GP_ERR, "%g  ", c[i][j]);
+	}
+	gprint (GP_ERR, "\n");
+      }
+    }
+
+    /* the b[][0] terms are in the following order:
+       y^0 x^0, y^0 x^1, ... y^0 x^N
+       y^1 x^0, y^1 x^1, ... y^1 x^N
+       ...
+       y^N x^0, y^N x^1, ... y^N x^N
+    */
+    /* generate fitted values */
+    x = xvec[0].elements.Flt;
+    y = yvec[0].elements.Flt;
+    z = zvec[0].elements.Flt;
+    Ff = Ffit;
+    for (n = 0; n < xvec[0].Nelements; n++, x++, y++, z++, Ff++) {
+      if (!finite(*x)) continue;
+      if (!finite(*y)) continue;
+      if (!finite(*z)) continue;
+      if (!finite(*F)) continue;
+      *Ff = 0;
+      Z = Y = X = 1;
+      i = 0;
+      for (nz = 0; nz < nterm; nz++) {
+	Y = Z;
+	for (ny = 0; ny < nterm - nz; ny++) {
+	  X = Y;
+	  for (nx = 0; nx < nterm - nz - ny; nx++, i++) {
+	    *Ff += b[i][0]*X;
+	    X = X * (*x);
+	  }
+	  Y = Y * (*y);
+	}
+	Z = Z * (*z);
+      }
+    }
+
+    /* measure fit residual scatter */
+    x  = xvec[0].elements.Flt;
+    y  = yvec[0].elements.Flt;
+    z  = zvec[0].elements.Flt;
+    F  = Fvec[0].elements.Flt;
+    Ff = Ffit;
+    dF1 = dF2 = 0;
+    for (i = Npt = 0; i < xvec[0].Nelements; i++, x++, y++, z++, F++, Ff++) {
+      if (mask[i]) continue;
+      if (!finite(*x)) continue;
+      if (!finite(*y)) continue;
+      if (!finite(*z)) continue;
+      if (!finite(*F)) continue;
+      dF1 += (*F - *Ff);
+      dF2 += SQ(*F - *Ff);
+      Npt ++;
+    }
+    mean  = dF1 / Npt;
+    sigma = sqrt (fabs(dF2/Npt - SQ(mean)));
+    maxsigma = ClipNSigma * sigma;
+
+    if (VERBOSE) gprint (GP_ERR, "mean: %g, sigma: %g, maxsigma: %g\n", mean, sigma, maxsigma);
+
+    /* mask outlier points */
+    x  = xvec[0].elements.Flt;
+    y  = yvec[0].elements.Flt;
+    z  = zvec[0].elements.Flt;
+    F  = Fvec[0].elements.Flt;
+    Ff = Ffit;
+    Nmask = 0;
+    for (i = 0; ClipNSigma && (i < xvec[0].Nelements); i++, x++, y++, z++, Ff++) {
+      dF1 = (*F - *Ff);
+      if (fabs(dF1) > maxsigma) {
+	mask[i] = TRUE;
+	Nmask ++;
+      } else {
+	mask[i] = FALSE;
+      }	
+    }
+    if (VERBOSE) gprint (GP_ERR, "pass: %d, Nmask: %d\n", N, Nmask);
+  }
+
+  if (!Quiet) gprint (GP_ERR, "F = ");
+
+  N = 0;
+  for (nz = 0; nz < nterm; nz++) {
+    for (ny = 0; ny < nterm - nz; ny++) {
+      for (nx = 0; nx < nterm - nz - ny; nx++, N++) {
+	sprintf (name, "CX%dY%dZ%d", nx, ny, nz);
+	set_variable (name, b[N][0]);
+	if (!Quiet) gprint (GP_ERR, "%f x^%d y^%d z^%d ", b[N][0], nx, ny, nz);
+      }
+    }
+  }
+  sprintf (name, "Cnnn");
+  set_variable (name, (double) order);
+  
+  if (!Quiet) gprint (GP_ERR, "\n");
+
+  /* free internal data */
+  free (Ffit);
+  free (mask);
+
+  for (i = 0; i < wterm; i++) {
+    free (c[i]);
+    free (b[i]);
+  }
+  free (b);
+  free (c);
+
+  for (i = 0; i < mterm; i++) {
+    for (j = 0; j < mterm; j++) {
+      free (s[i][j]);
+    }
+    free (s[i]);
+  }
+  free (s);
+
+  return (TRUE);
+}
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/init.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/init.c	(revision 29060)
@@ -5,4 +5,5 @@
 int applyfit1d       PROTO((int, char **));
 int applyfit2d       PROTO((int, char **));
+int applyfit3d       PROTO((int, char **));
 int box              PROTO((int, char **));
 int book_command     PROTO((int, char **));
@@ -34,4 +35,5 @@
 int fit1d            PROTO((int, char **));
 int fit2d            PROTO((int, char **));
+int fit3d            PROTO((int, char **));
 int gaussjordan      PROTO((int, char **));
 int gaussdeviate     PROTO((int, char **));
@@ -138,4 +140,5 @@
   {1, "applyfit1d",   applyfit1d,       "apply 1-d fit to new vector"},
   {1, "applyfit2d",   applyfit2d,       "apply 2-d fit to new vector"},
+  {1, "applyfit3d",   applyfit3d,       "apply 3-d fit to new vector"},
   {1, "book",         book_command,     "commands to manipulate book/page/word data"},
   {1, "box",          box,              "draw a box on the plot"},
@@ -168,4 +171,5 @@
   {1, "fit1d",        fit1d,            "fit polynomial to vector pair"},
   {1, "fit2d",        fit2d,            "fit 2-d polynomial to vector triplet"},
+  {1, "fit3d",        fit3d,            "fit 3-d polynomial to vector quad"},
   {1, "gaussdev",     gaussdeviate,     "generate a gaussian deviate vector"},
   {1, "gaussint",     gaussintegral,    "return the integrated gaussian vector"},
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/vgauss.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/vgauss.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/cmd.data/vgauss.c	(revision 29060)
@@ -42,7 +42,7 @@
   if ((ovec = SelectVector (argv[4], ANYVECTOR, TRUE)) == NULL) return (FALSE);
 
-  REQUIRE_VECTOR_FLT (xvec, FALSE); 
-  REQUIRE_VECTOR_FLT (yvec, FALSE); 
-  REQUIRE_VECTOR_FLT (svec, FALSE); 
+  CastVector (xvec, OPIHI_FLT);
+  CastVector (yvec, OPIHI_FLT);
+  CastVector (svec, OPIHI_FLT);
 
   Npts = xvec[0].Nelements;
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/ImageSelection.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/ImageSelection.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/ImageSelection.c	(revision 29060)
@@ -38,5 +38,5 @@
 /* free loaded images */
 void FreeImageSelection () {
-  if (image != NULL) free (image);
+  if (image != NULL) FreeImages(image);
   if (subset != NULL) free (subset);
   image = NULL;
@@ -47,9 +47,16 @@
 Image *MatchImage (unsigned int time, short int source, unsigned int imageID) { 
 
-  int m;
+  int m = -1;
 
   if ((imageID != 0) && (imageID < Nimage)) {
-    m = (int) imageID - 1;
-  } else {
+    // imageID is in range for the array of images. If the table is still in order and
+    // no images have been deleted the index of the image we are looking for will be imageID - 1
+    // If this is the case, we have it. Otherwise we'll have to go search for it below
+    int guess = (int) imageID - 1;
+    if (image[guess].imageID == imageID) {
+        m = guess;
+    }
+  } 
+  if (m == -1) {
     m = match_image_subset (image, subset, Nsubset, time, source);
   }
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/LoadImages.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/LoadImages.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/LoadImages.c	(revision 29060)
@@ -1,3 +1,13 @@
 # include "dvoshell.h"
+
+// XXX: Maybe make this a command line option
+int dvoUseImageCache = 1;
+
+static char *lastFilename = NULL;
+static time_t lastModified = 0;
+static Image *imageCache = NULL;
+static off_t cacheNimage = 0;
+
+static time_t getLastModified(char *filename);
 
 Image *LoadImages (off_t *Nimage) {
@@ -12,4 +22,21 @@
   catdir = GetCATDIR ();
   sprintf (filename, "%s/Images.dat", catdir);
+
+  if (lastFilename) {
+    if (dvoUseImageCache && !strcmp(lastFilename, filename)) {
+      // Make sure the file hasn't changed since we loaded it
+      if (getLastModified(filename) == lastModified) {
+        *Nimage = cacheNimage;
+        return  imageCache;
+      }
+    }
+    free(lastFilename);
+    lastFilename = NULL;
+    free(imageCache);
+    imageCache = NULL;
+    cacheNimage = 0;
+    lastModified = 0;
+  }
+
 
   gfits_db_init (&db);
@@ -38,4 +65,32 @@
 
   image = gfits_table_get_Image (&db.ftable, Nimage, &db.swapped);
+  if (!image) {
+    fprintf (stderr, "ERROR: failed to read images\n");
+    return (NULL);
+  }
+  if (dvoUseImageCache && image) {
+    cacheNimage = *Nimage;
+    imageCache = image;
+    lastFilename = strdup(filename);
+    lastModified = getLastModified(filename);
+  }
   return (image);
 }
+
+static time_t getLastModified(char *filename) {
+  struct stat statbuf;
+  if (!stat(filename, &statbuf)) {
+    return statbuf.st_mtime;
+  } else {
+    return 0;
+  }
+}
+
+void FreeImages(Image *images) {
+  if (!dvoUseImageCache && (images != NULL)) {
+    free(images);
+  } else {
+    // defer free until next LoadImages with a different or modified Images.dat
+  }
+}
+
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/cmpReadFile.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/cmpReadFile.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/cmpReadFile.c	(revision 29060)
@@ -20,4 +20,8 @@
 
   smpdata = gfits_table_get_SMPData (&table, &Nstars, NULL);
+  if (!smpdata) {
+    fprintf (stderr, "ERROR: failed to read stars\n");
+    exit (2);
+  }
 
   ALLOCATE (stars, CMPstars, Nstars);
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/gimages.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/gimages.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/gimages.c	(revision 29060)
@@ -247,5 +247,5 @@
   set_int_variable ("IMAGEphotcode:n", Nfound);
 
-  free (image);
+  FreeImages (image);
   free (subset);
 
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/images.c	(revision 29060)
@@ -319,5 +319,5 @@
   free (Xvec.elements.Flt);
   free (Yvec.elements.Flt);
-  free (image);
+  FreeImages (image);
   return (TRUE);
 
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/imdense.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/imdense.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/imdense.c	(revision 29060)
@@ -70,5 +70,5 @@
   free (Xvec.elements.Flt);
   free (Yvec.elements.Flt);
-  free (image);
+  FreeImages (image);
   return (TRUE);
 
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/imextract.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/imextract.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/dvo/imextract.c	(revision 29060)
@@ -137,5 +137,5 @@
 
   // free (subset);
-  free (image);
+  FreeImages (image);
 
   if (vec) free (vec);
Index: /branches/sc_branches/trunkTest/Ohana/src/opihi/include/dvoshell.h
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/opihi/include/dvoshell.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/opihi/include/dvoshell.h	(revision 29060)
@@ -302,4 +302,5 @@
 int           InitPhotcodes         PROTO((void));
 Image        *LoadImages            PROTO((off_t *Nimage));
+void          FreeImages            PROTO((Image *images));
 Image        *MatchImage            PROTO((unsigned int time, short int source, unsigned int imageID));
 Coords       *MatchMosaic           PROTO((unsigned int time, short int source));
Index: /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/copy_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/copy_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/copy_images.c	(revision 29060)
@@ -46,4 +46,8 @@
     
   image = gfits_table_get_Image (&in.ftable, &Nimage, &in.swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
   dvo_image_addrows (&out, image, Nimage);
 
Index: /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/find_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/find_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/find_images.c	(revision 29060)
@@ -28,4 +28,8 @@
 
   timage = gfits_table_get_Image (&db[0].ftable, &Ntimage, &db[0].swapped);
+  if (!timage) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
 
   nimage = 0;
@@ -97,6 +101,6 @@
       if (found) {
 	image[nimage] = timage[i]; 
-	if (image[nimage].code == ID_IMAGE_NOCAL) {
-	  image[nimage].code &= ~ID_IMAGE_NOCAL;
+	if (image[nimage].code == ID_IMAGE_PHOTOM_NOCAL) {
+	  image[nimage].code &= ~ID_IMAGE_PHOTOM_NOCAL;
 	}	    
 	line_number[nimage] = i;
Index: /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/flag_measures.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/flag_measures.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/photdbc/src/flag_measures.c	(revision 29060)
@@ -16,4 +16,8 @@
 
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
 
   PhotNsec = GetPhotcodeNsecfilt ();
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/Makefile
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/Makefile	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/Makefile	(revision 29060)
@@ -58,4 +58,5 @@
 $(SRC)/CoordOps.$(ARCH).o            \
 $(SRC)/FixProblemImages.$(ARCH).o    \
+$(SRC)/StarMaps.$(ARCH).o    \
 $(SRC)/high_speed_catalogs.$(ARCH).o  \
 $(SRC)/high_speed_objects.$(ARCH).o  \
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/doc/notes.txt
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/doc/notes.txt	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/doc/notes.txt	(revision 29060)
@@ -1,2 +1,28 @@
+
+2010.07.15
+
+  Some issues:
+
+  * when I apply the fitted image parameters (UpdateObjectOffsets), I
+    currently check for good/bad fits and warn if the image is bad.
+    But the correction requires multiple re-loads of the catalog
+    tables.
+
+  * I would like to check for bad fits by defining a grid of test
+    points and seeing how much they move.  However, for some chips,
+    the region of valid data is much smaller than the regino with any
+    data.  
+
+  * I would like to define a grid (say, Nx * Ny with Nx >> polynomial
+    order) and only use those grid regions in testing the solution
+
+  * This means knowing which detections belong on a specific image.
+    I'm not sure if there is a good way to do this.  at the moment, it
+    is easy to do detection -> image, but not so easy to do
+    image->detection.
+
+  * That might argue for generating the grid for each image, then
+    running through all detections and, as detections are examined,
+    populate the grid elements for their own image.
 
 2010.03.24
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/include/relastro.h
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/include/relastro.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/include/relastro.h	(revision 29060)
@@ -3,4 +3,5 @@
 # include <kapa.h>
 # include <signal.h>
+# include <assert.h>
 
 typedef enum {
@@ -76,4 +77,10 @@
   int    Nmeas;
 } StatType;
+
+# define MARKTIME(MSG,...) { \
+  float dtime; \
+  gettimeofday (&stop, (void *) NULL); \
+  dtime = DTIME (stop, start); \
+  fprintf (stderr, MSG, __VA_ARGS__); }
 
 /* global variables set in parameter file */
@@ -145,4 +152,10 @@
 int DoUpdateChips;
 int DoUpdateMosaics;
+
+// StarMap parameters:
+int NX_MAP;
+int NY_MAP;
+double DPOS_MAX;
+double ADDSTAR_RADIUS;
 
 /*** relphot prototypes ***/
@@ -207,4 +220,6 @@
 void create_image_db (FITS_DB *db);
 void save_catalogs (Catalog *catalog, int Ncatalog);
+
+int reload_images (FITS_DB *db);
 
 int           main                PROTO((int argc, char **argv));
@@ -267,8 +282,8 @@
 double **poly2d_copy (double **poly, int Nx, int Ny);
 double poly2d_eval (double **poly, int Nx, int Ny, double x, double y);
-int fit_apply_coords (CoordFit *fit, Coords *coords);
+int fit_apply_coords (CoordFit *fit, Coords *coords, int keepRef);
 int CoordsGetCenter (CoordFit *fit, double tol, double *xo, double *yo);
 CoordFit *CoordsSetCenter (CoordFit *input, double Xo, double Yo);
-int FitChip (StarData *raw, StarData *ref, int Nmatch, Coords *coords);
+int FitChip (StarData *raw, StarData *ref, int Nmatch, Image *image);
 void FitMosaic (StarData *raw, StarData *ref, int Nmatch, Coords *coords);
 void FitSimple (StarData *raw, StarData *ref, int Nmatch, Coords *coords);
@@ -293,4 +308,5 @@
 StarData *getImageRef (Catalog *catalog, int Ncatalog, off_t im, off_t *Nstars, CoordMode mode);
 StarData *getImageRaw (Catalog *catalog, int Ncatalog, off_t im, off_t *Nstars, CoordMode mode);
+off_t getImageByID (off_t ID);
 
 Mosaic *getmosaics (off_t *N);
@@ -331,2 +347,7 @@
 int high_speed_objects (SkyRegion *region, Catalog *catalog);
 int MeasMatchesPhotcode(Measure *measure, PhotCode **photcodeSet, int Nset);
+
+int initStarMaps ();
+int updateStarMaps(Catalog *catalog);
+int createStarMapPoints();
+int checkStarMap(int N);
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/ConfigInit.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/ConfigInit.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/ConfigInit.c	(revision 29060)
@@ -32,4 +32,9 @@
   GetConfig (config, "PM_TOOFEW",              "%d",  0, &PM_TOOFEW);
   GetConfig (config, "POS_TOOFEW",             "%d",  0, &POS_TOOFEW);
+
+  GetConfig (config, "RELASTRO_MAP_NX",        "%d",  0, &NX_MAP);
+  GetConfig (config, "RELASTRO_MAP_NY",        "%d",  0, &NY_MAP);
+  GetConfig (config, "RELASTRO_DPOS_MAX",      "%lf", 0, &DPOS_MAX);
+  GetConfig (config, "ADDSTAR_RADIUS",         "%lf", 0, &ADDSTAR_RADIUS);
 
   GetConfig (config, "GSCFILE",                "%s",  0, GSCFILE);
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitChip.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitChip.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitChip.c	(revision 29060)
@@ -3,13 +3,6 @@
 
 // XXX make these user parameters
-# define FIT_CHIP_MAX_ERROR 0.05
 # define FIT_CHIP_NITER     3
 # define FIT_CHIP_NSIGMA    3.0
-
-
-// XXX we should test if the fit is sufficiently constrained across the chip, or if the
-// new positions deviate too much from the old positions
-
-// XXX add visualization tools: per chip residual plots
 
 // XXX save the fit[0].Npts value in the image table?
@@ -17,5 +10,5 @@
 // XXX save measurements of the fit quality (scatter, chisq) in the image table
 
-int FitChip (StarData *raw, StarData *ref, int Nmatch, Coords *coords) {
+int FitChip (StarData *raw, StarData *ref, int Nmatch, Image *image) {
 
   int i, Nscatter, Niter, skip;
@@ -29,5 +22,5 @@
     for (i = Nscatter = 0; i < Nmatch; i++) {
       if (raw[i].mask) continue;
-      if (isnan(raw[i].dMag) || raw[i].dMag > FIT_CHIP_MAX_ERROR) continue;
+      if (isnan(raw[i].dMag) || raw[i].dMag > SIGMA_LIM) continue;
 
       dL = raw[i].L - ref[i].L;
@@ -39,15 +32,20 @@
     }
 
-    // for a 2D Gaussian, 40% of the points are within 1 sigma; dRmax is ~ 3 sigma
-    dsort (values, Nscatter);
-    dRmax = FIT_CHIP_NSIGMA*values[(int)(0.40*Nscatter)];
-    relastroVisualPlotScatter(values, dRmax, Nscatter);
-    relastroVisualPlotRawRef(raw, ref, dRmax, Nmatch);
+    if (Nscatter > 5) {
+      // for a 2D Gaussian, 40% of the points are within 1 sigma; dRmax is ~ 3 sigma
+      // XXX this test is not sensible for Nscatter < XXX (5?)
+      dsort (values, Nscatter);
+      dRmax = FIT_CHIP_NSIGMA*values[(int)(0.40*Nscatter)];
+      relastroVisualPlotScatter(values, dRmax, Nscatter);
+      relastroVisualPlotRawRef(raw, ref, dRmax, Nmatch);
+    } else {
+      dRmax = 0;
+    }
 
     // fit the requested order polynomial
     if (CHIPORDER > 0) {
-      coords[0].Npolyterms = CHIPORDER;
+      image[0].coords.Npolyterms = CHIPORDER;
     }
-    fit = fit_init (coords[0].Npolyterms);
+    fit = fit_init (image[0].coords.Npolyterms);
 
     // generate the fit matches
@@ -56,5 +54,5 @@
 	continue;
       }
-      if (isnan(raw[i].dMag) || raw[i].dMag > FIT_CHIP_MAX_ERROR) {
+      if (isnan(raw[i].dMag) || raw[i].dMag > SIGMA_LIM) {
 	continue;
       }
@@ -64,5 +62,8 @@
       dM = raw[i].M - ref[i].M;
       dR = hypot (dL, dM);
-      if (dR > dRmax) continue;
+
+      // fprintf (stderr, "fit %f %f -> %f %f : %f %f (%f vs %f) wt: %f\n", raw[i].X, raw[i].Y, ref[i].L, ref[i].M, raw[i].L, raw[i].M, dR, dRmax, raw[i].dPos);
+
+      if ((dRmax > 0.0) && (dR > dRmax)) continue;
 
       fit_add (fit, raw[i].X, raw[i].Y, ref[i].L, ref[i].M, raw[i].dPos);
@@ -71,5 +72,5 @@
     // check if the fit has enough data points for the polynomial order
     skip = FALSE;
-    switch (coords[0].Npolyterms) {
+    switch (image[0].coords.Npolyterms) {
       case 0:
       case 1:
@@ -83,11 +84,12 @@
         break;
       default:
-        fprintf (stderr, "invalid chip order %d\n", coords[0].Npolyterms);
+        fprintf (stderr, "invalid chip order %d\n", image[0].coords.Npolyterms);
 	skip = TRUE;
     }
     if (skip) {
-      fprintf (stderr, "insufficient measurements (%d) for requested order (%d)\n", fit[0].Npts, coords[0].Npolyterms);
+      if (VERBOSE) fprintf (stderr, "insufficient measurements (%d) for requested order (%d)\n", fit[0].Npts, image[0].coords.Npolyterms);
       fit_free (fit);
       free (values);
+      image[0].flags |= ID_IMAGE_ASTROM_FEW;
       return FALSE;
     }
@@ -98,9 +100,11 @@
     if (!fit_eval (fit)) {
       fprintf (stderr, "failed to fit new model\n");
+      image[0].flags |= ID_IMAGE_ASTROM_FAIL;
       return FALSE;
     }
 
-    if (!fit_apply_coords (fit, coords)) {
+    if (!fit_apply_coords (fit, &image[0].coords, FALSE)) {
       fprintf (stderr, "failed to fit new model\n");
+      image[0].flags |= ID_IMAGE_ASTROM_FAIL;
       return FALSE;
     }
@@ -109,5 +113,5 @@
 
     for (i = 0; i < Nmatch; i++) {
-      XY_to_LM (&raw[i].L, &raw[i].M, raw[i].X, raw[i].Y, coords);
+      XY_to_LM (&raw[i].L, &raw[i].M, raw[i].X, raw[i].Y, &image[0].coords);
     }
 
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitMosaic.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitMosaic.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitMosaic.c	(revision 29060)
@@ -26,5 +26,5 @@
   }
   fit_eval (fit);
-  fit_apply_coords (fit, coords);
+  fit_apply_coords (fit, coords, TRUE);
   fit_free (fit);
 
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitSimple.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitSimple.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/FitSimple.c	(revision 29060)
@@ -26,5 +26,5 @@
   }
   fit_eval (fit);
-  fit_apply_coords (fit, coords);
+  fit_apply_coords (fit, coords, TRUE);
   fit_free (fit);
 
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/ImageOps.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/ImageOps.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/ImageOps.c	(revision 29060)
@@ -319,4 +319,15 @@
 }
 
+void dump_measures(Average *average, Measure *measure) {
+
+  off_t j, off;
+
+  for (j = 0; j < average[0].Nmeasure; j++) {
+    off = average[0].measureOffset + j;
+    fprintf (stderr, "%f, %f\n", measure[off].dR, measure[off].dD);
+  }
+  return;
+}
+
 // return StarData values for detections in the specified image, converting coordinates from the
 // chip positions: X,Y -> L,M -> P,Q -> R,D
@@ -325,5 +336,5 @@
   off_t i, m, c, n, nPos;
   double X, Y, L, M, P, Q, R, D, dR, dD;
-  double dPos;
+  double dPos, DPOS_MAX_ASEC;
 
   Mosaic *mosaic;
@@ -341,4 +352,10 @@
   }
   imcoords = &image[im].coords;
+
+  if (moscoords) {
+    DPOS_MAX_ASEC = 3600.0*DPOS_MAX*hypot(moscoords[0].cdelt1, moscoords[0].cdelt2);
+  } else {
+    DPOS_MAX_ASEC = 3600.0*DPOS_MAX*hypot(imcoords[0].cdelt1, imcoords[0].cdelt2);
+  }
 
   // accumulate the rms position offsets.  if this value, or any specific entry, is too
@@ -372,25 +389,26 @@
 
     // complain if the new location is far from the average location
-    if (fabs(dR) > 2.0) {
-      fprintf (stderr, "!");
-      setBadCoords (im); // report a failure for this image
-      return;
-    }
-    if (fabs(dD) > 2.0) {
-      fprintf (stderr, "*");
-      setBadCoords (im); // report a failure for this image
-      return;
+    // NOTE: This should never happen, or our StarMap tests are not working
+    if (fabs(dR) > 1.5*ADDSTAR_RADIUS) {
+      fprintf (stderr, "measurement is far from average location (R): %f %f (%f %f)\n", catalog[c].average[n].R, catalog[c].average[n].D, dR, dD);
+      dump_measures (&catalog[c].average[n], catalog[c].measure);
+      // abort ();
+    }
+    if (fabs(dD) > 1.5*ADDSTAR_RADIUS) {
+      fprintf (stderr, "measurement is far from average location (D): %f %f (%f %f)\n", catalog[c].average[n].R, catalog[c].average[n].D, dR, dD);
+      dump_measures (&catalog[c].average[n], catalog[c].measure);
+      // abort ();
     }
 
     // complain if the new location is far from the old location
-    if (fabs(catalog[c].measure[m].dR - dR) > 2.0) {
-      fprintf (stderr, "@");
-      setBadCoords (im); // report a failure for this image
-      return;
-    }
-    if (fabs(catalog[c].measure[m].dD - dD) > 2.0) {
-      fprintf (stderr, "#");
-      setBadCoords (im); // report a failure for this image
-      return;
+    if (fabs(catalog[c].measure[m].dR - dR) > DPOS_MAX_ASEC) {
+      fprintf (stderr, "measurement is far from original location (R): %f %f (%f %f)\n", catalog[c].average[n].R, catalog[c].average[n].D, dR, dD);
+      dump_measures (&catalog[c].average[n], catalog[c].measure);
+      // abort();
+    }
+    if (fabs(catalog[c].measure[m].dD - dD) > DPOS_MAX_ASEC) {
+      fprintf (stderr, "measurement is far from original location (D): %f %f (%f %f)\n", catalog[c].average[n].R, catalog[c].average[n].D, dR, dD);
+      dump_measures (&catalog[c].average[n], catalog[c].measure);
+      // abort();
     }
 
@@ -414,4 +432,6 @@
 
   saveOffsets (dPos, nPos, im);
+
+  // XXX this function should probably update the average positions as well.
 
   return;
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/StarMaps.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/StarMaps.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/StarMaps.c	(revision 29060)
@@ -0,0 +1,153 @@
+# include "relastro.h"
+
+// XXX mark the image grid based on the loaded detections
+// XXX modify tcatalog to exclude any photcode or other choices that
+// only affect image selection?
+
+// XXX this stuff is only going to work for SIMPLE and CHIP; need to
+// use parentID to get from imageID to the mosaic pseudo-image
+
+typedef struct {
+  double L;
+  double M;
+  double X;
+  double Y;
+  double dL;
+  double dM;
+} StarMapPoint;
+
+typedef struct {
+  int  Nx;
+  int  Ny;
+  int *stars; // arrays to count the number of stars in each map bin
+  StarMapPoint *points; // test points generated based on map
+  int Npoints;
+} StarMap;
+
+static StarMap     *starmap;         
+// static int         Nstarmap;  -- is it always == Nimages?
+
+/** we have two possible options for how the user defines the map bins:
+    a) the user specifies the number of cells in the map, leading to varying binning
+    b) the user specifies the binning factor, leading to variable grid sizes.
+    
+    We want to use (b) since we know the order of the model
+**/
+
+int initStarMaps () {
+
+  Image *images;
+  off_t i, Nimages;
+
+  images = getimages(&Nimages);
+
+  ALLOCATE (starmap, StarMap, Nimages);
+
+  for (i = 0; i < Nimages; i++) {
+    starmap[i].Npoints = 0;
+    starmap[i].points = NULL;
+    starmap[i].Nx = images[i].NX / NX_MAP;
+    starmap[i].Ny = images[i].NY / NY_MAP;
+    ALLOCATE (starmap[i].stars, int, NX_MAP*NY_MAP);
+    memset (starmap[i].stars, 0, sizeof(int)*NX_MAP*NY_MAP);
+  }
+  return (TRUE);
+}
+
+int updateStarMaps(Catalog *catalog) {
+
+  Image *images;
+  off_t i, N, Nimages;
+  int xbin, ybin;
+  struct timeval start, stop;
+
+  gettimeofday (&start, (void *) NULL);
+
+  images = getimages(&Nimages);
+
+  for (i = 0; i < catalog[0].Nmeasure; i++) {
+    
+    N = getImageByID(catalog[0].measure[i].imageID);
+    if (N < 0) continue;
+
+    xbin = catalog[0].measure[i].Xccd / starmap[N].Nx;
+    ybin = catalog[0].measure[i].Yccd / starmap[N].Ny;
+
+    xbin = MAX(0, MIN(NX_MAP-1, xbin));
+    ybin = MAX(0, MIN(NY_MAP-1, ybin));
+
+    starmap[N].stars[ybin*NX_MAP + xbin] ++;
+  }
+  MARKTIME("assign stars to starmap bins: %f sec\n", dtime);
+
+  return (TRUE);
+}
+
+int createStarMapPoints() {
+
+  Image *images;
+  off_t i, Nimages;
+  int ix, iy;
+
+  images = getimages(&Nimages);
+
+  for (i = 0; i < Nimages; i++) {
+    
+    assert (!starmap[i].points);
+
+    ALLOCATE (starmap[i].points, StarMapPoint, NX_MAP*NY_MAP);
+    starmap[i].Npoints = 0;
+
+    for (ix = 0; ix < NX_MAP; ix++) {
+      for (iy = 0; iy < NY_MAP; iy++) {
+	if (starmap[i].stars[iy*NX_MAP + ix] < 1) continue;
+	StarMapPoint *point = &starmap[i].points[starmap[i].Npoints];
+	starmap[i].Npoints++;
+
+	// set the pixel coordinates
+	point[0].X = ix * starmap[i].Nx; // XXX fix 0.5 pixel offset
+	point[0].Y = iy * starmap[i].Nx; // XXX fix 0.5 pixel offset
+
+	// set the transformed coordinates
+	XY_to_LM (&point[0].L, &point[0].M, point[0].X, point[0].Y, &images[i].coords);
+
+	point[0].dL = 0.0;
+	point[0].dM = 0.0;
+      }
+    }
+
+    if (VERBOSE) fprintf (stderr, "starmap: %d points for image %s\n", starmap[i].Npoints, images[i].name);
+  }
+
+  return (TRUE);
+}
+
+int checkStarMap(int N) {
+
+  Image *images;
+  off_t i, Nimages;
+  double L, M, dLmax, dMmax;
+
+  images = getimages(&Nimages);
+
+  dLmax = dMmax = 0.0;
+
+  for (i = 0; i < starmap[N].Npoints; i++) {
+
+    // set the transformed coordinates
+    XY_to_LM (&L, &M, starmap[N].points[i].X, starmap[N].points[i].Y, &images[N].coords);
+
+    starmap[N].points[i].dL = starmap[N].points[i].L - L;
+    starmap[N].points[i].dM = starmap[N].points[i].M - M;
+
+    dLmax = MAX(fabs(starmap[N].points[i].dL), dLmax);
+    dMmax = MAX(fabs(starmap[N].points[i].dM), dMmax);
+  }
+
+  if (VERBOSE) fprintf (stderr, "max deviations for %s using %d pts : %f, %f\n", images[N].name, starmap[N].Npoints, dLmax, dMmax);
+
+  if (dLmax > DPOS_MAX) return (FALSE);
+  if (dMmax > DPOS_MAX) return (FALSE);
+  return (TRUE);
+}
+
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/UpdateChips.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/UpdateChips.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/UpdateChips.c	(revision 29060)
@@ -31,8 +31,18 @@
     // FitChip does iterative, clipped fitting
     // fprintf (stderr, "image "OFF_T_FMT" : Nstars: "OFF_T_FMT"\n",  i,  Nraw);
-    if (!FitChip (raw, ref, Nraw, &image[i].coords)) {
-      fprintf (stderr, "reject fit for image %s ("OFF_T_FMT") : Nstars: "OFF_T_FMT"\n", image[i].name,  i,  Nraw);
+    if (!FitChip (raw, ref, Nraw, &image[i])) {
+      if (VERBOSE) fprintf (stderr, "reject fit for image %s ("OFF_T_FMT") : Nstars: "OFF_T_FMT"\n", image[i].name,  i,  Nraw);
       oldCoords = getCoords (i);
       memcpy (&image[i].coords, oldCoords, sizeof(Coords));
+      free (raw);
+      free (ref);
+      continue;
+    }
+
+    if (!checkStarMap (i)) {
+      if (VERBOSE) fprintf (stderr, "fit diverges too much for image %s ("OFF_T_FMT") : Nstars: "OFF_T_FMT"\n", image[i].name,  i,  Nraw);
+      oldCoords = getCoords (i);
+      memcpy (&image[i].coords, oldCoords, sizeof(Coords));
+      image[i].flags |= ID_IMAGE_ASTROM_POOR;
     }
 
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/UpdateMeasures.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/UpdateMeasures.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/UpdateMeasures.c	(revision 29060)
@@ -5,4 +5,11 @@
   off_t i, Nimage;
   Image *image;
+
+  int badImage = 
+    ID_IMAGE_ASTROM_NOCAL | 
+    ID_IMAGE_ASTROM_POOR | 
+    ID_IMAGE_ASTROM_FAIL | 
+    ID_IMAGE_ASTROM_SKIP | 
+    ID_IMAGE_ASTROM_FEW;
 
   image = getimages (&Nimage);
@@ -13,4 +20,7 @@
     if (!strcmp(&image[i].coords.ctype[4], "-DIS")) continue;
 
+    // skip images that have failed solutions (divergent or otherwise)
+    if (image[i].flags & badImage) continue;
+
     /* convert measure coordinates to raw entries */
     fixImageRaw (catalog, Ncatalog, i);
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/bcatalog.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/bcatalog.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/bcatalog.c	(revision 29060)
@@ -45,5 +45,5 @@
       offset = catalog[0].average[i].measureOffset + j;
       
-      //filter objects based on user supplied criteria
+      // filter objects based on user supplied criteria
       if (!MeasFilterTest(&catalog[0].measure[offset])) {
 	catalog[0].measure[offset].dbFlags &= ~ID_MEAS_USED_CHIP;
@@ -51,5 +51,5 @@
       }
 
-      //filter out outliers
+      // filter out outliers
       if (FlagOutlier && (catalog[0].measure[offset].dbFlags & ID_MEAS_POOR_ASTROM)) {
 	catalog[0].measure[offset].dbFlags &= ~ID_MEAS_USED_CHIP;
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/fitpoly.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/fitpoly.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/fitpoly.c	(revision 29060)
@@ -110,4 +110,5 @@
   if (fit[0].Npts == 0) {
     fprintf (stderr, "warning: no valid pts\n");
+    return (FALSE);
   }
 
@@ -140,9 +141,9 @@
   }
 
-  for (i = 0; i < fit[0].Nelems; i++) {
+  for (i = 0; FALSE && (i < fit[0].Nelems); i++) {
     ix = i % fit[0].Nterms;
     iy = i / fit[0].Nterms;
-    // fprintf (stderr, "x2 : x^%dy^%d: %10.4g    y2 : x^%dy^%d: %10.4g \n", 
-    // ix, iy, vector[i][0], ix, iy, vector[i][1]);
+    fprintf (stderr, "x2 : x^%dy^%d: %10.4g    y2 : x^%dy^%d: %10.4g \n", 
+    ix, iy, vector[i][0], ix, iy, vector[i][1]);
   }	
   
@@ -151,9 +152,9 @@
   }
 
-  for (i = 0; i < fit[0].Nelems; i++) {
+  for (i = 0; FALSE && i < fit[0].Nelems; i++) {
     ix = i % fit[0].Nterms;
     iy = i / fit[0].Nterms;
-    // fprintf (stderr, "x2 : x^%dy^%d: %10.4g    y2 : x^%dy^%d: %10.4g \n", 
-    // ix, iy, vector[i][0], ix, iy, vector[i][1]);
+    fprintf (stderr, "x2 : x^%dy^%d: %10.4g    y2 : x^%dy^%d: %10.4g \n", 
+    ix, iy, vector[i][0], ix, iy, vector[i][1]);
   }	
 
@@ -274,25 +275,35 @@
 /* this should only apply to the polynomial, not the projection terms */
 /* compare with psastro supporting code */
-int fit_apply_coords (CoordFit *fit, Coords *coords) {
+int fit_apply_coords (CoordFit *fit, Coords *coords, int keepRef) {
 
   double Xo, Yo, R1, R2;
   CoordFit *modfit;
 
-  /* I have L,M = fit(X,Y). set corresponding terms for coords */
-
-  // L = a[0][0] + a[1][0]x^1 y^0 + a[0][1] x^0 y^1 + ...
-  // L = pc1_1*cd1*(x - cp1) + pc1_2*cd2*(y - cp2) + ...
-
-  if (!CoordsGetCenter (fit, 0.001, &Xo, &Yo)) {
-    fprintf (stderr, "failed to modify model\n");
-    return (FALSE);
-  }
-  coords[0].crpix1 = Xo;
-  coords[0].crpix2 = Yo;
-  
-  // resulting fit should have zero constant terms
-  modfit = CoordsSetCenter (fit, Xo, Yo);
-
-  /* we do not modify crval1,2: these are kept at the default values */
+  if (keepRef) {
+    // adjust crpix1,2 as needed:
+    // L = a[0][0] + a[1][0]x^1 y^0 + a[0][1] x^0 y^1 + ...
+    // L = pc1_1*cd1*(x - cp1) + pc1_2*cd2*(y - cp2) + ...
+
+    if (!CoordsGetCenter (fit, 0.001, &Xo, &Yo)) {
+      fprintf (stderr, "failed to modify model\n");
+      return (FALSE);
+    }
+    coords[0].crpix1 = Xo;
+    coords[0].crpix2 = Yo;
+    /* we do not modify crval1,2: these are kept at the default values */
+  
+    // resulting fit should have zero constant terms
+    modfit = CoordsSetCenter (fit, Xo, Yo);
+  } else {
+    // L = a[0][0] + a[1][0]x^1 y^0 + a[0][1] x^0 y^1 + ...
+    // P = cd1*x, Q = cd2*y
+    // L = pc1_1*P + pc1_2*Q + ...
+
+    /* modify crval1,2: these are kept at the default values */
+
+    coords[0].crpix1 = 0.0;
+    coords[0].crpix2 = 0.0;
+    modfit = fit;
+  }
 
   // set cdelt1, cdelt2
@@ -331,6 +342,10 @@
     coords[0].polyterms[6][1] = modfit[0].yfit[0][3]*R2*R2*R2;
   }
-
-  fit_free (modfit);
+  
+  if (keepRef) {
+    fit_free (modfit);
+  } else {
+    fit_apply (fit, &coords[0].crval1, &coords[0].crval2, coords[0].crpix1, coords[0].crpix2); 
+  }
   /* keep the order and type from initial values */
   
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/initialize.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/initialize.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/initialize.c	(revision 29060)
@@ -100,5 +100,5 @@
   initstats (STATMODE);
 
-  // IMAGE_BAD = ID_IMAGE_POOR | ID_IMAGE_FEW | ID_IMAGE_SKIP;
+  // IMAGE_BAD = ID_IMAGE_ASTROM_POOR | ID_IMAGE_ASTROM_FEW | ID_IMAGE_ASTROM_SKIP;
   // STAR_BAD  = ID_STAR_POOR | ID_STAR_FEW;
   // MEAS_BAD  = ID_MEAS_NOCAL | ID_MEAS_POOR_ASTROM | ID_MEAS_SKIP_ASTROM | ID_MEAS_AREA;
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/load_catalogs.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/load_catalogs.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/load_catalogs.c	(revision 29060)
@@ -9,4 +9,6 @@
 
   ALLOCATE (catalog, Catalog, skylist[0].Nregions);
+
+  initStarMaps();
 
   // load data from each region file, only use bright stars
@@ -34,4 +36,6 @@
       FlagOutliers(&tcatalog);
     }
+
+    updateStarMaps (&tcatalog);
 
     // select only the brighter stars
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/load_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/load_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/load_images.c	(revision 29060)
@@ -33,4 +33,9 @@
   // convert database table to internal structure
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
+
   MARKTIME("  convert image table: %f sec\n", dtime);
 
@@ -52,2 +57,19 @@
   return (skylist);
 }
+
+int reload_images (FITS_DB *db) {
+
+  Image     *image;
+  off_t     Nimage, Nx, i;
+  VTable    *vtable;
+
+  image = getimages (&Nimage);
+
+  vtable = &db[0].vtable;
+
+  gfits_scan (vtable[0].header, "NAXIS1", OFF_T_FMT, 1,  &Nx);
+  for (i = 0; i < Nimage; i++) {
+    memcpy (vtable[0].buffer[i], &image[i], Nx);
+  }
+  return (TRUE);
+}
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/mkpolyterm.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/mkpolyterm.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/mkpolyterm.c	(revision 29060)
@@ -66,4 +66,5 @@
       Xo -= beta[0][0];
       Yo -= beta[1][0];
+
       dPos = hypot(beta[0][0], beta[1][0]);
       if (i == 0) {
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/relastro.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/relastro.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/relastro.c	(revision 29060)
@@ -1,9 +1,3 @@
 # include "relastro.h"
-
-# define MARKTIME(MSG,...) { \
-  float dtime; \
-  gettimeofday (&stop, (void *) NULL); \
-  dtime = DTIME (stop, start); \
-  fprintf (stderr, MSG, __VA_ARGS__); }
 
 int main (int argc, char **argv) {
@@ -49,4 +43,6 @@
 
   /* load catalog data from region files : subselect high-quality measurements */
+  // XXX pass in the image table
+  // XXX who carries the image grid?
   catalog = load_catalogs (skylist, &Ncatalog, TRUE);
   MARKTIME("load catalog data: %f sec\n", dtime);
@@ -63,4 +59,7 @@
     // plot_mosaic_fields (catalog);
   }
+
+  // set test points based on the starmap
+  createStarMapPoints();
 
   /* major modes */
@@ -98,9 +97,11 @@
   freeImageBins (1);
 
+  reload_images (&db);
+    
   // iterate over catalogs to make detection coordinates consistant
   UpdateObjectOffsets (skylist);
 
   // iterate over catalogs to make detection coordinates consistant
-  FixProblemImages (skylist);
+  // FixProblemImages (skylist);
 
   // save the updated image parameters
Index: /branches/sc_branches/trunkTest/Ohana/src/relastro/src/select_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relastro/src/select_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relastro/src/select_images.c	(revision 29060)
@@ -28,4 +28,9 @@
   double *RmaxSky;
   off_t *index;
+
+  int badImage = 
+    ID_IMAGE_ASTROM_POOR | 
+    ID_IMAGE_ASTROM_FAIL | 
+    ID_IMAGE_ASTROM_FEW;
 
   if (skylist[0].Nregions < 1) {
@@ -171,6 +176,6 @@
       image[nimage] = timage[i]; 
       /* always allow 'few' images to succeed, if possible */
-      if (image[nimage].flags & ID_IMAGE_FEW) { 
-	image[nimage].flags &= ~(ID_IMAGE_FEW | ID_IMAGE_POOR);
+      if (image[nimage].flags & ID_IMAGE_ASTROM_FEW) { 
+	image[nimage].flags &= ~ID_IMAGE_ASTROM_FEW;
       }
       if (RESET) {
@@ -178,5 +183,5 @@
 	assignMcal (&image[nimage], (double *) NULL, -1);
 	image[nimage].dMcal = NAN;
-	image[nimage].flags &= ~ID_IMAGE_POOR;
+	image[nimage].flags &= ~badImage;
       }
       line_number[nimage] = i;
Index: /branches/sc_branches/trunkTest/Ohana/src/relphot/src/ImageOps.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relphot/src/ImageOps.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relphot/src/ImageOps.c	(revision 29060)
@@ -323,5 +323,5 @@
     /* on PoorImages run, skip good images */
     if (PoorImages) {
-      bad = image[i].flags & (ID_IMAGE_FEW | ID_IMAGE_POOR | ID_IMAGE_SKIP);
+      bad = image[i].flags & (ID_IMAGE_PHOTOM_FEW | ID_IMAGE_PHOTOM_POOR | ID_IMAGE_PHOTOM_SKIP);
       if (!bad) continue;
     }      
@@ -369,8 +369,8 @@
       mark = (N < IMAGE_TOOFEW) || (N < IMAGE_GOOD_FRACTION*Nlist[i]);
       if (mark) {
-	image[i].flags |= ID_IMAGE_FEW;
+	image[i].flags |= ID_IMAGE_PHOTOM_FEW;
 	Nfew ++;
       } else {
-	image[i].flags &= ~ID_IMAGE_FEW;
+	image[i].flags &= ~ID_IMAGE_PHOTOM_FEW;
       }      
     }
@@ -387,5 +387,5 @@
 
   if (PoorImages) {
-    IMAGE_BAD = ID_IMAGE_POOR | ID_IMAGE_FEW | ID_IMAGE_SKIP;
+    IMAGE_BAD = ID_IMAGE_PHOTOM_POOR | ID_IMAGE_PHOTOM_FEW | ID_IMAGE_PHOTOM_SKIP;
     STAR_BAD  = ID_STAR_POOR | ID_STAR_FEW;
     MEAS_BAD  = ID_MEAS_NOCAL | ID_MEAS_POOR_PHOTOM | ID_MEAS_SKIP_PHOTOM | ID_MEAS_AREA;
@@ -429,11 +429,11 @@
   for (i = 0; i < Nimage; i++) {
     mark = FALSE;
-    image[i].flags &= ~ID_IMAGE_POOR;
+    image[i].flags &= ~ID_IMAGE_PHOTOM_POOR;
     mark = (image[i].dMcal > MaxScatter) || (fabs(image[i].Mcal - MedOffset) > MaxOffset);
     if (mark) { 
       Nmark ++;
-      image[i].flags |= ID_IMAGE_POOR;
+      image[i].flags |= ID_IMAGE_PHOTOM_POOR;
     } else {
-      image[i].flags &= ~ID_IMAGE_POOR;
+      image[i].flags &= ~ID_IMAGE_PHOTOM_POOR;
     }
   }
Index: /branches/sc_branches/trunkTest/Ohana/src/relphot/src/MosaicOps.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relphot/src/MosaicOps.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relphot/src/MosaicOps.c	(revision 29060)
@@ -189,6 +189,6 @@
       image[im].dMcal = mosaic[i].dMcal;
       image[im].Xm = mosaic[i].Xm;
-      image[im].flags |= (mosaic[i].flags & ID_IMAGE_FEW);
-      image[im].flags |= (mosaic[i].flags & ID_IMAGE_POOR);
+      image[im].flags |= (mosaic[i].flags & ID_IMAGE_PHOTOM_FEW);
+      image[im].flags |= (mosaic[i].flags & ID_IMAGE_PHOTOM_POOR);
     }
   }      
@@ -351,5 +351,5 @@
     /* on PoorImages run, skip good images */
     if (PoorImages) {
-      bad = mosaic[i].flags & (ID_IMAGE_FEW | ID_IMAGE_POOR | ID_IMAGE_SKIP);
+      bad = mosaic[i].flags & (ID_IMAGE_PHOTOM_FEW | ID_IMAGE_PHOTOM_POOR | ID_IMAGE_PHOTOM_SKIP);
       if (!bad) continue;
     }      
@@ -401,8 +401,8 @@
       if (mark) {
 	fprintf (stderr, "marked mosaic %s ("OFF_T_FMT"), ("OFF_T_FMT" < %d) || ("OFF_T_FMT" < %f*"OFF_T_FMT")\n", image[imlist[i][0]].name,  i,  N, IMAGE_TOOFEW,  N, IMAGE_GOOD_FRACTION,  Nlist[i]);
-	mosaic[i].flags |= ID_IMAGE_FEW;
+	mosaic[i].flags |= ID_IMAGE_PHOTOM_FEW;
 	Nfew ++;
       } else {
-	mosaic[i].flags &= ~ID_IMAGE_FEW;
+	mosaic[i].flags &= ~ID_IMAGE_PHOTOM_FEW;
       }
     }
@@ -421,5 +421,5 @@
 
   if (PoorImages) {
-    IMAGE_BAD = ID_IMAGE_POOR | ID_IMAGE_FEW | ID_IMAGE_SKIP;
+    IMAGE_BAD = ID_IMAGE_PHOTOM_POOR | ID_IMAGE_PHOTOM_FEW | ID_IMAGE_PHOTOM_SKIP;
     STAR_BAD  = ID_STAR_POOR | ID_STAR_FEW;
     MEAS_BAD  = ID_MEAS_NOCAL | ID_MEAS_POOR_PHOTOM | ID_MEAS_SKIP_PHOTOM | ID_MEAS_AREA;
@@ -593,7 +593,7 @@
     if (mark) { 
       Nmark ++;
-      mosaic[i].flags |= ID_IMAGE_POOR;
+      mosaic[i].flags |= ID_IMAGE_PHOTOM_POOR;
     } else {
-      mosaic[i].flags &= ~ID_IMAGE_POOR;
+      mosaic[i].flags &= ~ID_IMAGE_PHOTOM_POOR;
     }
   }
Index: /branches/sc_branches/trunkTest/Ohana/src/relphot/src/StarOps.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relphot/src/StarOps.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relphot/src/StarOps.c	(revision 29060)
@@ -188,4 +188,7 @@
   StatType stats;
   PhotCode *code;
+  DVOAverageFlags flagBits;
+
+  flagBits = ID_OBJ_EXT | ID_OBJ_EXT_ALT | ID_OBJ_GOOD | ID_OBJ_GOOD_ALT;
 
   // pre-allocate a list for stats purposes
@@ -281,15 +284,18 @@
 	}
 
+	// we attempt to set a few flags here; reset those bits before trying:
+	catalog[i].average[j].flags &= ~flagBits;
+
 	if (nEXT && (nEXT > nPSF)) {
-	  catalog[i].average[j].flags |= 0x00010000;
+	  catalog[i].average[j].flags |= ID_OBJ_EXT;
 	}
 	if (goodPS1) {
-	  catalog[i].average[j].flags |= 0x00020000;
+	  catalog[i].average[j].flags |= ID_OBJ_GOOD;
 	}
 	if (Galaxy2MASS) {
-	  catalog[i].average[j].flags |= 0x00040000;
+	  catalog[i].average[j].flags |= ID_OBJ_EXT_ALT;
 	}
 	if (good2MASS) {
-	  catalog[i].average[j].flags |= 0x00080000;
+	  catalog[i].average[j].flags |= ID_OBJ_GOOD_ALT;
 	}
       }
@@ -302,5 +308,5 @@
 }
 
-/* set measure.Mcal for all measures except ID_MEAS_NOCAL and ID_IMAGE_NOCAL */
+/* set measure.Mcal for all measures except ID_MEAS_NOCAL and ID_IMAGE_PHOTOM_NOCAL */
 int setMcalOutput (Catalog *catalog, int Ncatalog) {
 
@@ -310,5 +316,5 @@
 
   MEAS_BAD = ID_MEAS_NOCAL;
-  IMAGE_BAD = ID_IMAGE_NOCAL;
+  IMAGE_BAD = ID_IMAGE_PHOTOM_NOCAL;
 
   for (i = 0; i < Ncatalog; i++) {
@@ -470,5 +476,5 @@
       /* apply to list of all relevant measurements, including IMAGE_POOR & IMAGE_FEW */
       image_bad = IMAGE_BAD;
-      IMAGE_BAD = ID_IMAGE_NOCAL;
+      IMAGE_BAD = ID_IMAGE_PHOTOM_NOCAL;
       m = catalog[i].average[j].measureOffset;
       N = 0;
Index: /branches/sc_branches/trunkTest/Ohana/src/relphot/src/initialize.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relphot/src/initialize.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relphot/src/initialize.c	(revision 29060)
@@ -27,5 +27,5 @@
   initstats (STATMODE);
 
-  IMAGE_BAD = ID_IMAGE_POOR | ID_IMAGE_FEW | ID_IMAGE_SKIP;
+  IMAGE_BAD = ID_IMAGE_PHOTOM_POOR | ID_IMAGE_PHOTOM_FEW | ID_IMAGE_PHOTOM_SKIP;
   STAR_BAD  = ID_STAR_POOR | ID_STAR_FEW;
   MEAS_BAD  = ID_MEAS_NOCAL | ID_MEAS_POOR_PHOTOM | ID_MEAS_SKIP_PHOTOM | ID_MEAS_AREA;
Index: /branches/sc_branches/trunkTest/Ohana/src/relphot/src/load_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relphot/src/load_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relphot/src/load_images.c	(revision 29060)
@@ -25,4 +25,8 @@
   // convert database table to internal structure
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
 
   // select the images which overlap the selected sky regions
Index: /branches/sc_branches/trunkTest/Ohana/src/relphot/src/select_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relphot/src/select_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relphot/src/select_images.c	(revision 29060)
@@ -157,11 +157,11 @@
       image[nimage] = timage[i]; 
       /* always allow 'few' images to succeed, if possible */
-      if (image[nimage].flags & ID_IMAGE_FEW) { 
-	image[nimage].flags &= ~(ID_IMAGE_FEW | ID_IMAGE_POOR);
+      if (image[nimage].flags & ID_IMAGE_PHOTOM_FEW) { 
+	image[nimage].flags &= ~(ID_IMAGE_PHOTOM_FEW | ID_IMAGE_PHOTOM_POOR);
       }
       if (RESET) {
 	assignMcal (&image[nimage], (double *) NULL, -1);
 	image[nimage].dMcal = NAN;
-	image[nimage].flags &= ~ID_IMAGE_POOR;
+	image[nimage].flags &= ~ID_IMAGE_PHOTOM_POOR;
       }
       line_number[nimage] = i;
Index: /branches/sc_branches/trunkTest/Ohana/src/relphot/src/setMrelFinal.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/relphot/src/setMrelFinal.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/relphot/src/setMrelFinal.c	(revision 29060)
@@ -75,5 +75,5 @@
 
   /* allow measures from images marked POOR and FEW */
-  if (pass >= 3) IMAGE_BAD = ID_IMAGE_NOCAL;
+  if (pass >= 3) IMAGE_BAD = ID_IMAGE_PHOTOM_NOCAL;
   
   /* allow measures marked as outliers (POOR) and off image region (AREA) */
Index: /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/find_image_sgroups.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/find_image_sgroups.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/find_image_sgroups.c	(revision 29060)
@@ -13,4 +13,8 @@
   imlink = *Imlink;
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
 
   coords.crpix1 = coords.crpix2 = 0.0;
@@ -28,5 +32,5 @@
   for (i = 0; i < Nimage; i++) {
     if (imlink[i].sgroup != NULL) continue;
-    if (image[i].flags & ID_IMAGE_NOCAL) continue;
+    if (image[i].flags & ID_IMAGE_PHOTOM_NOCAL) continue;
 
     /* new sgroup, set ref coords */
@@ -53,5 +57,5 @@
 
     for (j = 0; j < Nimage; j++) {
-      if (image[j].flags & ID_IMAGE_NOCAL) continue;
+      if (image[j].flags & ID_IMAGE_PHOTOM_NOCAL) continue;
       if (imlink[j].sgroup != NULL) continue;
 
Index: /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/find_image_tgroups.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/find_image_tgroups.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/find_image_tgroups.c	(revision 29060)
@@ -12,4 +12,9 @@
 
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
+
   ALLOCATE (imlink, ImageLink, Nimage);
 
@@ -64,5 +69,5 @@
       if (image[j].tzero < tmin[i]) continue;
       if (image[j].tzero > tmax[i]) continue;
-      if (image[j].flags & ID_IMAGE_NOCAL) continue;
+      if (image[j].flags & ID_IMAGE_PHOTOM_NOCAL) continue;
       
       group[i].image[Nentry] = &image[j];
Index: /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/initialize.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/initialize.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/initialize.c	(revision 29060)
@@ -16,5 +16,5 @@
   }
 
-  IMAGE_BAD = ID_IMAGE_NOCAL | ID_IMAGE_POOR | ID_IMAGE_SKIP | ID_IMAGE_FEW;
+  IMAGE_BAD = ID_IMAGE_PHOTOM_NOCAL | ID_IMAGE_PHOTOM_POOR | ID_IMAGE_PHOTOM_SKIP | ID_IMAGE_PHOTOM_FEW;
 
   initstats (STATMODE);
Index: /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/load_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/load_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/load_images.c	(revision 29060)
@@ -22,4 +22,8 @@
   /* use a vtable to keep the images to be calibrated */
   image = gfits_table_get_Image (&db[0].ftable, Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
 
   fprintf (stderr, "loaded "OFF_T_FMT" images\n", *Nimage);
Index: /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/match_zpts_to_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/match_zpts_to_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/match_zpts_to_images.c	(revision 29060)
@@ -71,5 +71,5 @@
     image[Ni].Mcal = SCALE*code[0].C - zpts[Nz].zpt;
     image[Ni].dMcal = zpts[Nz].zpt_err;
-    image[Ni].flags &= ~ID_IMAGE_NOCAL; // clear the NOCAL flag
+    image[Ni].flags &= ~ID_IMAGE_PHOTOM_NOCAL; // clear the NOCAL flag
     zpts[Nz].found = TRUE;
     NImatch ++;
Index: /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/subset_images.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/subset_images.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/subset_images.c	(revision 29060)
@@ -9,4 +9,8 @@
   /* use a vtable to keep the images to be calibrated */
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
 
   Nkeep = 0;
@@ -16,5 +20,5 @@
   for (i = 0; i < Nimage; i++) {
       
-    image[i].flags |= ID_IMAGE_NOCAL;
+    image[i].flags |= ID_IMAGE_PHOTOM_NOCAL;
 
     /* select images by photcode */
@@ -27,5 +31,5 @@
       if (image[i].tzero > TSTOP) continue;
     }
-    image[i].flags &= ~ID_IMAGE_NOCAL;
+    image[i].flags &= ~ID_IMAGE_PHOTOM_NOCAL;
     keep[Nkeep] = i;
     Nkeep ++;
Index: /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/update.c
===================================================================
--- /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/update.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/Ohana/src/uniphot/src/update.c	(revision 29060)
@@ -14,8 +14,12 @@
 
   image = gfits_table_get_Image (&db[0].ftable, &Nimage, &db[0].swapped);
+  if (!image) {
+      fprintf (stderr, "ERROR: failed to read images\n");
+      exit (2);
+  }
 
   /* clear the NOCAL flags */
   for (i = 0; i < Nimage; i++) {
-    image[i].flags &= ~ID_IMAGE_NOCAL;
+    image[i].flags &= ~ID_IMAGE_PHOTOM_NOCAL;
   }
 
Index: /branches/sc_branches/trunkTest/PS-IPP-PStamp/lib/PS/IPP/PStamp/Job.pm
===================================================================
--- /branches/sc_branches/trunkTest/PS-IPP-PStamp/lib/PS/IPP/PStamp/Job.pm	(revision 29059)
+++ /branches/sc_branches/trunkTest/PS-IPP-PStamp/lib/PS/IPP/PStamp/Job.pm	(revision 29060)
@@ -1130,5 +1130,5 @@
                     }
                     $cam_path_base = $run->{cam_path_base};
-                    $astrom_file = $run->{astrom_file};
+                    $astrom_file = $run->{astrom};
                 }
                 my $astrom_file_resolved = $ipprc->file_resolve($astrom_file);
Index: /branches/sc_branches/trunkTest/ippMonitor/Makefile.in
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/Makefile.in	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippMonitor/Makefile.in	(revision 29060)
@@ -61,5 +61,6 @@
 $(DESTWWW)/cleanTmpDirectory.php \
 $(DESTWWW)/warpProcessedExp_Images.php \
-$(DESTWWW)/warpProcessedExp.php
+$(DESTWWW)/warpProcessedExp.php \
+$(DESTWWW)/diskUsage.php
 
 DEFSRC = \
@@ -103,4 +104,5 @@
 $(DESTWWW)/chipProcessedImfile.php \
 $(DESTWWW)/chipProcessedImfile_failure.php \
+$(DESTWWW)/failedChipProcessedImfile.php \
 $(DESTWWW)/camSummary.php \
 $(DESTWWW)/camStageExp.php \
@@ -109,4 +111,5 @@
 $(DESTWWW)/camProcessedExp_Images.php \
 $(DESTWWW)/camProcessedExp_failure.php \
+$(DESTWWW)/failedCamProcessedExp.php \
 $(DESTWWW)/camIQstats.php \
 $(DESTWWW)/camProcessedImfile.php \
@@ -118,4 +121,5 @@
 $(DESTWWW)/fakeProcessedImfile.php \
 $(DESTWWW)/fakeProcessedImfile_failure.php \
+$(DESTWWW)/failedFakeProcessedImfile.php \
 $(DESTWWW)/pzPendingExp.php \
 $(DESTWWW)/pzPendingImfile.php \
@@ -142,4 +146,5 @@
 $(DESTWWW)/warpProcessedSkyfiles.php \
 $(DESTWWW)/warpFailedSkyfiles.php \
+$(DESTWWW)/failedWarpSkyfiles.php \
 $(DESTWWW)/diffSummary.php \
 $(DESTWWW)/diffSummary_Images.php \
@@ -148,5 +153,5 @@
 $(DESTWWW)/diffProcessedSkyfile.php \
 $(DESTWWW)/diffProcessedSkyfile_Images.php \
-$(DESTWWW)/diffFailedSkyfile.php \
+$(DESTWWW)/failedDiffSkyfile.php \
 $(DESTWWW)/stackRun.php \
 $(DESTWWW)/stackSummary.php \
@@ -156,4 +161,5 @@
 $(DESTWWW)/stackProcessedSkyfile_Images.php \
 $(DESTWWW)/stackFailedSkyfile.php \
+$(DESTWWW)/failedStackSkyfile.php \
 $(DESTWWW)/staticskyRun.php \
 $(DESTWWW)/staticskySummary.php \
@@ -168,6 +174,9 @@
 $(DESTWWW)/magicProcessedMasks_Images.php \
 $(DESTWWW)/magicFailedTrees.php \
+$(DESTWWW)/failedMagicTrees.php \
 $(DESTWWW)/magicFailedNodes.php \
+$(DESTWWW)/failedMagicNodes.php \
 $(DESTWWW)/magicFailedMasks.php \
+$(DESTWWW)/failedMagicMasks.php \
 $(DESTWWW)/distSummary.php \
 $(DESTWWW)/distTarget.php \
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedCamProcessedExp.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedCamProcessedExp.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedCamProcessedExp.d	(revision 29060)
@@ -0,0 +1,39 @@
+TABLE camRun, camProcessedExp, chipRun, rawExp
+TITLE Camera Failed Exposures
+FILE  failedCamProcessedExp.php
+MENU  ipp.science.dat
+
+# the following WHERE clauses are added to all queries joined by AND
+WHERE camRun.chip_id = chipRun.chip_id
+WHERE chipRun.exp_id = rawExp.exp_id
+WHERE camProcessedExp.cam_id  = camRun.cam_id
+WHERE camProcessedExp.fault != 0
+
+# define the arguments supplied to the links below (if any)
+ARGS  ARG1  rawImfile.exp_id=$rawExp.exp_id
+ARGS  ARG2  chipRun.chip_id=$chipRun.chip_id
+ARGS  ARG3  camRun.cam_id=$camRun.cam_id
+
+ARGS  ARG4 camRun.cam_id=$camRun.cam_id
+ARGS  ARG4 camera=$rawExp.camera
+ARGS  ARG4 basename=$camProcessedExp.path_base
+
+OP   OP1  ( $camProcessedExp.fault == 2 ? "cam.revert.on and cam.revert.off" : "camtool -revertprocessedexp -fault $camProcessedExp.fault -label $camRun.label -dbname ". $ID['proj'] )
+
+#     field                     	size  format  name          show   	 link to                      extras
+FIELD rawExp.exp_name,     	 	 5,   %s,     Exp Name
+FIELD rawExp.exp_id,	         	 5,   %d,     Exp ID,       value,  	 rawImfile.php,               ARG1
+FIELD chipRun.chip_id,           	 5,   %d,     Chip ID,      value,  	 chipProcessedImfile.php,     ARG2
+FIELD camRun.cam_id,            	 5,   %d,     Cam ID,       value,       camProcessedExp_failure.php, ARG3
+FIELD camRun.state,                      5,   %s,     state,        value,       camProcessedImfile.php,      ARG4
+FIELD camRun.label,                      5,   %s,     label
+FIELD camRun.data_group,                 5,   %s,     data grp
+FIELD camRun.dist_group,                 5,   %s,     dist grp
+FIELD camProcessedExp.fault,		 2,   %d,     Fault
+FIELD *,				 50,  %s,     Command <blink>(Experimental)</blink>, op=OP1
+
+FIELD camProcessedExp.path_base,     	 5,   %s,     path_base,    none
+FIELD rawExp.exp_id,     		 5,   %s,     Exp ID,       none
+
+
+TAIL PHP insert_log ('LOG.IMFILE');
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedChipProcessedImfile.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedChipProcessedImfile.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedChipProcessedImfile.d	(revision 29060)
@@ -0,0 +1,52 @@
+TABLE chipRun, rawExp, chipProcessedImfile
+TITLE Chip Failed Imfiles
+FILE  failedChipProcessedImfile.php
+MENU  ipp.science.dat
+
+# limit this table to non-OBJECT types of images
+WHERE chipRun.exp_id = rawExp.exp_id
+WHERE chipProcessedImfile.exp_id = chipRun.exp_id
+WHERE chipProcessedImfile.chip_id = chipRun.chip_id
+WHERE chipProcessedImfile.fault != 0
+
+ARGS  ARG1 rawImfile.exp_id=$rawExp.exp_id
+
+ARGS  ARG2 chipRun.chip_id=$chipRun.chip_id
+
+ARGS  ARG3 chipRun.chip_id=$chipRun.chip_id
+ARGS  ARG3 chipProcessedImfile.class_id=$chipProcessedImfile.class_id
+ARGS  ARG3 camera=$rawExp.camera
+ARGS  ARG3 basename=$chipProcessedImfile.path_base
+ARGS  ARG3 class=$chipProcessedImfile.class_id
+
+OP    OP1  ( $chipProcessedImfile.fault == 2 ? "chip.revert.on and chip.revert.off" : "chiptool -revertprocessedimfile -fault $chipProcessedImfile.fault -label $chipRun.label -dbname ". $ID['proj'] )
+
+#     field                            size  format  name         show    link to                          extras
+FIELD rawExp.exp_name,     	   	  5, %s,     Exp Name
+FIELD chipProcessedImfile.class_id,	  8, %s,     Class ID
+FIELD rawExp.exp_id,         	   	  5, %d,     Exp ID,      value,  rawImfile.php,                   ARG1
+FIELD chipRun.chip_id,        	   	  7, %d,     Chip ID,     value,  chipProcessedImfile_failure.php, ARG2
+FIELD chipRun.state,        	   	  7, %s,     State,       value,  chipProcessedImfile_failure.php, ARG3
+FIELD chipRun.label,        	   	  7, %s,     Label
+FIELD chipRun.data_group,        	   	  7, %s,     data grp
+FIELD chipRun.dist_group,        	   	  7, %s,     dist grp
+FIELD chipProcessedImfile.fault,      	  2, %d,     Fault
+FIELD *,				  50, %s,    Command <blink>Experimental</blink>, op=OP1
+
+# FIELD rawExp.telescope,      	   	 10, %s,     Telescope
+# FIELD rawExp.camera,         	   	 10, %s,     Camera
+# FIELD rawExp.dateobs,        	   	 19, %T,     Date/Time
+# FIELD rawExp.ra,           	 	  8, %C, RA,           op=OP1      
+# FIELD rawExp.decl,         	 	  8, %C, DEC,          op=OP2
+# FIELD rawExp.object,       	   	  8, %s,     Object
+# FIELD rawExp.filter,         	   	 10, %s,     FILTER
+# FIELD rawExp.exp_time,       	   	  5, %.2f,   exp_time    
+# FIELD rawExp.airmass,        	   	  5, %.4f,   airmass     
+# FIELD chipProcessedImfile.bg,             5, %.2f,   backgnd
+# FIELD chipProcessedImfile.bg_stdev,       5, %.2f,   stdev    
+# FIELD chipProcessedImfile.n_stars,  	  5, %d,     Nstars
+# FIELD chipProcessedImfile.fwhm_major, 	  5, %.2f,   FHWM
+# FIELD chipProcessedImfile.path_base,      5, %s,     path_base, none
+# FIELD rawExp.comment,  	                 65, %s,     Comment
+
+TAIL PHP insert_log ('LOG.IMFILE');
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedDiffSkyfile.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedDiffSkyfile.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedDiffSkyfile.d	(revision 29060)
@@ -0,0 +1,30 @@
+TABLE diffRun, diffSkyfile
+TITLE Diff Failed Skyfiles
+FILE  failedDiffSkyfile.php
+MENU  ipp.stack.dat
+
+WHERE diffRun.diff_id             = diffSkyfile.diff_id
+WHERE diffSkyfile.fault != 0
+
+ARGS  ARG7 diffSkyfile.diff_id=$diffSkyfile.diff_id
+ARGS  ARG7 diffSkyfile.skycell_id=$diffSkyfile.skycell_id
+ARGS  ARG7 camera=GPC1
+ARGS  ARG7 basename=$diffSkyfile.path_base
+
+OP    OP1  ( $fault == 2 ? "diff.revert.on and diff.revert.off" : "difftool -revertdiffskyfile -fault $diffSkyfile.fault -label $diffRun.label -dbname ". $ID['proj'] )
+
+#     field                         size  format  name           show     link to         extras
+FIELD diffSkyfile.diff_id,             5, %d,     Diff ID
+FIELD diffSkyfile.skycell_id,          5, %s,     Skycell ID
+FIELD diffRun.label,    	       5, %s,     Label
+FIELD diffRun.data_group,    	       5, %s,     data grp
+FIELD diffRun.dist_group,    	       5, %s,     dist grp
+# FIELD diffRun.filter,    	       5, %s,     Filter
+FIELD diffRun.tess_id,    	       5, %s,     Tess ID
+FIELD diffRun.state,    	       7, %s,     State,         value,   diffProcessedSkyfile.php, ARG7
+FIELD diffSkyfile.fault,               5, %d,     Fault
+FIELD *,		 	       50,  %s,   Command <blink>(Experimental)</blink>, op=OP1
+
+FIELD diffSkyfile.path_base,           5, %s,     path_base,     none
+
+TAIL PHP insert_log ('LOG.EXP');
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedFakeProcessedImfile.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedFakeProcessedImfile.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedFakeProcessedImfile.d	(revision 29060)
@@ -0,0 +1,40 @@
+TABLE fakeRun, fakeProcessedImfile, camRun, chipRun, rawExp
+TITLE fake Processed Imfile
+FILE  failedFakeProcessedImfile.php
+MENU  ipp.science.dat
+
+# limit this table to non-OBJECT types of images
+WHERE fakeRun.cam_id = camRun.cam_id
+WHERE camRun.chip_id = chipRun.chip_id
+WHERE chipRun.exp_id = rawExp.exp_id
+WHERE fakeProcessedImfile.fake_id = fakeRun.fake_id
+WHERE fakeProcessedImfile.fault != 0
+
+ARGS  ARG1  rawImfile.exp_id=$rawExp.exp_id
+ARGS  ARG2  chipRun.chip_id=$chipRun.chip_id
+ARGS  ARG3  camRun.cam_id=$camRun.cam_id
+ARGS  ARG4  fakeRun.fake_id=$fakeRun.fake_id
+
+ARGS  ARG5 fakeRun.fake_id=fakeRun.fake_id
+ARGS  ARG5 fakeProcessedImfile.class_id=$fakeProcessedImfile.class_id
+ARGS  ARG5 camera=$rawExp.camera
+ARGS  ARG5 basename=$fakeProcessedImfile.path_base
+ARGS  ARG5 class=$fakeProcessedImfile.class_id
+
+OP   OP1    ( $fakeProcessedImfile.fault == 2 ? "fake.revert.on and fake.revert.off" : "faketool -revertprocessedimfile -fault $fakeProcessedImfile.fault -label $fakeRun.label -dbname ". $ID['proj'] )
+
+#     field                         size  format  name         show    link to                  extras
+FIELD rawExp.exp_name,                10, %s,     Exp Name
+FIELD fakeProcessedImfile.class_id,    8, %s,     Class ID
+FIELD rawExp.exp_id,                   5, %d,     Exp ID,       value,  rawImfile.php,           ARG1
+FIELD chipRun.chip_id,                 7, %d,     Chip ID,      value,  chipProcessedImfile.php, ARG2
+FIELD camRun.cam_id,                   7, %d,     Cam ID,       value,  camProcessedExp.php,     ARG3
+FIELD fakeRun.fake_id,                 7, %d,     Fake ID,      value,  fakeProcessedImfile_failure.php, ARG4
+FIELD fakeRun.state,                   7, %s,     State,       value,  fakeProcessedImfile_failure.php, ARG5
+FIELD fakeRun.label,                   7, %s,     Label
+FIELD fakeProcessedImfile.fault,       2, %d,     Fault
+FIELD *,			       50, %s,	  Command <blink>(Experimental/Not tested)</blink>, op=OP1
+
+FIELD fakeProcessedImfile.path_base,      5, %s,     path_base, none
+
+TAIL PHP insert_log ('LOG.IMFILE');
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicMasks.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicMasks.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicMasks.d	(revision 29060)
@@ -0,0 +1,21 @@
+TABLE magicRun, magicMask
+TITLE Magic Failed Masks
+FILE  failedMagicMasks.php
+MENU  ipp.stack.dat
+
+WHERE magicRun.magic_id  = magicMask.magic_id
+WHERE magicMask.fault   != 0
+
+OP    OP1  ( $fault == 2 ? "magic.revert.on and magic.revert.off" : "magictool -revertmask -fault $magicMask.fault -label $label -dbname ". $ID['proj'] )
+
+#        field                   size  format  name           show     link to         extras
+FIELD    magicRun.magic_id,	 5,   %d,     Magic ID
+FIELD    magicRun.exp_id,	 5,   %d,     Exp ID
+FIELD    magicRun.diff_id,	 5,   %d,     Diff ID
+FIELD    magicRun.label, 	 5,   %s,     Label
+FIELD    magicRun.data_group, 	 5,   %s,     data grp
+FIELD    magicRun.inverse,	 5,   %d,     Inverse
+FIELD    magicRun.state,	 5,   %s,     State
+FIELD    magicMask.streaks,	 5,   %d,     Streaks
+FIELD    magicMask.fault,	 5,   %d,     Fault
+FIELD	 *,		 	 50,  %s,     Command <blink>(Experimental)</blink>, op=OP1
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicNodes.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicNodes.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicNodes.d	(revision 29060)
@@ -0,0 +1,24 @@
+TABLE magicRun, magicTree, magicNodeResult
+TITLE Magic Failed Nodes
+FILE  failedMagicNodes.php
+MENU  ipp.stack.dat
+
+WHERE magicRun.magic_id        = magicTree.magic_id
+WHERE magicTree.magic_id       = magicNodeResult.magic_id
+WHERE magicTree.node           = magicNodeResult.node
+WHERE magicNodeResult.fault    != 0
+
+OP    OP1  ( $magicNodeResult.fault == 2 ? "magic.revert.on and magic.revert.off" : "magictool -revertnode -fault $magicNodeResult.fault -label $magicRun.label -dbname ". $ID['proj'] )
+
+#        field                   size  format  name           show     link to         extras
+FIELD    magicRun.magic_id,	 5,   %d,     Magic ID
+FIELD    magicRun.exp_id,	 5,   %d,     Exp ID
+FIELD    magicRun.diff_id,	 5,   %d,     Diff ID
+FIELD    magicRun.label, 	 5,   %s,     Label
+FIELD    magicRun.data_group, 	 5,   %s,     data grp
+FIELD    magicRun.inverse,	 5,   %d,     Inverse
+FIELD    magicRun.state,	 5,   %s,     State
+FIELD    magicTree.node,	 5,   %s,     Node
+FIELD    magicTree.dep,	 	 5,   %s,     Parent
+FIELD    magicNodeResult.fault,	 5,   %d,     Fault
+FIELD	 *,		 	 50,  %s,     Command <blink>(Experimental)</blink>, op=OP1
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicTrees.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicTrees.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedMagicTrees.d	(revision 29060)
@@ -0,0 +1,19 @@
+TABLE magicRun
+TITLE magic Failed Trees
+FILE  failedMagicTrees.php
+MENU  ipp.stack.dat
+
+WHERE fault != 0
+
+OP    OP1  ( $fault == 2 ? "magic.revert.on and magic.revert.off" : "magictool -reverttree -fault $fault -label $label -dbname ". $ID['proj'] )
+
+#        field          size  format  name           show     link to         extras
+FIELD    magic_id,	 5,   %d,     Magic ID
+FIELD    exp_id,	 5,   %d,     Exp ID
+FIELD    diff_id,	 5,   %d,     Diff ID
+FIELD    label,	 	 5,   %s,     Label
+FIELD    data_group, 	 5,   %s,     Data Grp
+FIELD    inverse,	 5,   %d,     Inverse
+FIELD    state,		 5,   %s,     State
+FIELD    fault,		 5,   %d,     Fault
+FIELD	 *,		 50,  %s,     Command <blink>(Experimental)</blink>, op=OP1
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedStackSkyfile.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedStackSkyfile.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedStackSkyfile.d	(revision 29060)
@@ -0,0 +1,31 @@
+TABLE stackRun, stackSumSkyfile
+TITLE Stack Failed Skyfiles
+FILE  failedStackSkyfile.php
+MENU  ipp.stack.dat
+
+WHERE stackRun.stack_id = stackSumSkyfile.stack_id
+WHERE stackSumSkyfile.fault != 0
+
+ARGS  ARG7 stackRun.stack_id=$stackRun.stack_id
+ARGS  ARG7 stackRun.skycell_id=$stackRun.skycell_id
+ARGS  ARG7 camera=GPC1
+ARGS  ARG7 basename=$stackSumSkyfile.path_base
+
+OP    OP1  ( $stackSumSkyfile.fault == 2 ? "stack.revert.on and stack.revert.off" : "stacktool -revertsumskyfile -fault $stackSumSkyfile.fault -label $stackRun.label -dbname ". $ID['proj'] )
+
+#        field                          size  format  name    show     link to         extras
+FIELD stackRun.stack_id,            5, %s,     Stack ID
+FIELD stackRun.skycell_id,          5, %s,     Skycell ID
+FIELD stackRun.label,    	    5, %s,     Label
+FIELD stackRun.data_group,    	    5, %s,     data grp
+FIELD stackRun.dist_group,    	    5, %s,     dist grp
+FIELD stackRun.filter,    	    5, %s,     Filter
+FIELD stackRun.tess_id,    	    5, %s,     Tess ID
+FIELD stackRun.state,    	    7, %s,     State,         value,   stackFailedSkyfile.php, ARG7
+FIELD stackSumSkyfile.fault,	    2, %d,     Fault
+
+FIELD *,        50, %s, Command you should try to run as the ipp user? <blink>(Experimental feature)</blink>, op=OP1
+
+FIELD stackSumSkyfile.path_base,    5, %s,     path_base,     none
+
+TAIL PHP insert_log ('LOG.EXP');
Index: /branches/sc_branches/trunkTest/ippMonitor/def/failedWarpSkyfiles.d
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/def/failedWarpSkyfiles.d	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/def/failedWarpSkyfiles.d	(revision 29060)
@@ -0,0 +1,42 @@
+TABLE warpSkyfile, warpRun, fakeRun, camRun, chipRun, rawExp
+TITLE Warp Failed Skyfiles
+FILE  failedWarpSkyfiles.php
+MENU  ipp.science.dat
+
+WHERE warpSkyfile.warp_id = warpRun.warp_id
+WHERE warpRun.fake_id = fakeRun.fake_id
+WHERE fakeRun.cam_id = camRun.cam_id
+WHERE camRun.chip_id = chipRun.chip_id
+WHERE chipRun.exp_id = rawExp.exp_id
+WHERE warpSkyfile.fault != 0
+
+ARGS  ARG1  rawImfile.exp_id=$rawExp.exp_id
+ARGS  ARG2  chipRun.chip_id=$chipRun.chip_id
+ARGS  ARG3  camRun.cam_id=$camRun.cam_id
+ARGS  ARG4  fakeRun.fake_id=$fakeRun.fake_id
+ARGS  ARG5  warpRun.warp_id=$warpRun.warp_id
+ARGS  ARG6  warpSkyfile.skycell_id=$warpSkyfile.skycell_id
+
+ARGS  ARG7 warpRun.warp_id=$warpRun.warp_id
+ARGS  ARG7 warpSkyfile.skycell_id=$warpSkyfile.skycell_id
+ARGS  ARG7 camera=$rawExp.camera
+ARGS  ARG7 basename=$warpSkyfile.path_base
+
+OP   OP1    ( $warpSkyfile.fault == 2 ? "warp.revert.on and warp.revert.off" : "warptool -revertwarped -fault $warpSkyfile.fault -label $warpRun.label -dbname ". $ID['proj'] )
+
+#     field                    size  format  name         show    link to         extras
+FIELD rawExp.exp_name,     	  5, %s,     Exp Name
+FIELD rawExp.exp_id,     	  5, %d,     Exp ID,       value,  rawImfile.php,           ARG1
+FIELD chipRun.chip_id,    	  7, %d,     Chip ID,      value,  chipProcessedImfile.php, ARG2
+FIELD camRun.cam_id,    	  7, %d,     Cam ID,       value,  camProcessedExp.php,     ARG3
+FIELD fakeRun.fake_id,    	  7, %d,     Fake ID,      value,  fakeProcessedImfile.php, ARG4
+FIELD warpRun.warp_id,    	  7, %d,     Warp ID,      value,  warpStageExp.php,        ARG5
+FIELD warpSkyfile.skycell_id, 	 10, %s,     Skycell ID,      value,  warpFailedSkyfiles.php,  ARG6
+FIELD warpRun.state,    	  7, %s,     State,        value,  warpFailedSkyfiles.php,  ARG7
+FIELD warpRun.label,    	  7, %s,     Label
+FIELD warpSkyfile.fault,      	  2, %d,     Fault
+FIELD *,			  50, %s,    Command <blink>(Experimental)</blink>, op=OP1
+
+FIELD warpSkyfile.path_base,      5, %s,     path_base,   none
+
+TAIL PHP insert_log ('LOG.EXP');
Index: /branches/sc_branches/trunkTest/ippMonitor/raw/czartool_labels.php
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/raw/czartool_labels.php	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippMonitor/raw/czartool_labels.php	(revision 29060)
@@ -10,4 +10,6 @@
 //$db = dbconnect($ID['proj']);
 $czardb = dbconnect("czardb"); // HACK to connect to czarDb 
+$lastUpdateTime = getLastUpdateTime($czardb);
+
 $gpc1db = dbconnect($ID['proj']);
 
@@ -22,5 +24,5 @@
 else {$myMenu = "ipp.imfiles.dat";}
 
-menu($myMenu, 'Czartool', 'ipp.css', $ID['link'], $ID['proj']);
+menu($myMenu, 'Czartool on '.$lastUpdateTime, 'ipp.css', $ID['link'], $ID['proj']);
 
 $pass = $ID['pass'];
@@ -34,6 +36,8 @@
 $selectedRevertMode = $_GET[revertmode];
 
-if ($selectedLabel == "") $selectedLabel = "all_labels";
-if ($selectedStage == "") $selectedStage = "all_stages";
+if ($selectedLabel == "") { $selectedLabel = "all_stdscience_labels"; }
+if ($selectedStage == "") { $selectedStage = "all_stages"; }
+
+echo "<p  align=\"center\"> Current status of the IPP as of $lastUpdateTime (faults are shown in parentheses). <br>Documentation can be found <a href=\"http://svn.pan-starrs.ifa.hawaii.edu/trac/ipp/wiki/Processing\">here</a> and cluster load monitored <a href=\"http://ganglia.pan-starrs.ifa.hawaii.edu/?r=hour&s=descending&c=IPP%2520Production\">here</a></p>";
 
 // deal with reverts: turn on or off if requested and pass current revert state for this stage onto labels table later
@@ -52,4 +56,5 @@
 $distLabels = getLabels($czardb, "distribution");
 $pubLabels = getLabels($czardb, "publishing");
+$updateLabels = getLabels($czardb, "update");
 
 if ($debug) {
@@ -61,5 +66,5 @@
 
 $states=array("full","new","drop","wait");
-$stages=array("chip","cam","fake","warp","stack","diff","magic","magicDS","dist");
+$stages=array("burntool", "chip","cam","fake","warp","stack","diff","magic","magicDS","dist");
 $servers=array(
         "addstar",
@@ -82,6 +87,4 @@
 echo "<input type=\"hidden\" name=\"menu\" value=\"$menu\">\n";
 echo "</form>\n";
-$lastUpdateTime = getLastUpdateTime($czardb);
-echo "<p  align=\"center\"> Current status of IPP (any faults are shown in parentheses). NOTE: This data is good as of: $lastUpdateTime </p>";
 
 echo "<table>\n";
@@ -92,5 +95,15 @@
 
     echo "<td> \n";
-      createLabelsTable($pass, $proj, $czardb, $stdsLabels, $distLabels, $pubLabels, $stages, $states, "new", $selectedLabel, $selectedStage);
+      createLabelsTable($pass, $proj, $czardb, "stdscience", $stdsLabels, $distLabels, $pubLabels, $stages, $states, "new", $selectedLabel, $selectedStage);
+    echo "</td>\n";
+  echo "</tr>\n";
+
+  echo "<tr>\n";
+    echo "<td>\n";
+      echo "<img src=\"czartool_getplot.php?type=h&label=$selectedLabel&stage=$selectedStage\"><br>";
+    echo "</td>\n";
+
+    echo "<td> \n";
+      createLabelsTable($pass, $proj, $czardb, "update", $updateLabels, $distLabels, $pubLabels, $stages, $states, "new", $selectedLabel, $selectedStage);
     echo "</td>\n";
   echo "</tr>\n";
@@ -100,5 +113,5 @@
       echo "<tr valign=top>\n";
         echo "<td> \n";
-          echo "<img src=\"czartool_getplot.php?type=h&label=$selectedLabel&stage=$selectedStage\"><br>";
+          echo "<img src=\"czartool_getplot.php?type=s\"><br>";
         echo "</td>\n";
         echo "<td>\n";
@@ -116,5 +129,4 @@
       echo "<tr valign=top>\n";
         echo "<td> \n";
-          echo "<img src=\"czartool_getplot.php?type=s\"><br>";
         echo "</td>\n";
         echo "<td>\n";
@@ -211,5 +223,5 @@
 #
 ###########################################################################
-function createLabelsTable($pass, $proj, $db, $stdsLabels, $distLabels, $pubLabels, $stages, $states, $selectedState, $selectedLabel, $selectedStage) {
+function createLabelsTable($pass, $proj, $db, $server, $labels, $distLabels, $pubLabels, $stages, $states, $selectedState, $selectedLabel, $selectedStage) {
 
     // set up table columns
@@ -218,4 +230,6 @@
     echo "<tr><td></td>\n";
 
+    echo "<p  align=\"center\"> Current labels for $server server (D=distributing, P=publishing)</p>";
+
     write_header_cell($class, "");
     write_header_cell($class, "");
@@ -223,4 +237,5 @@
     foreach ($stages as &$stage) {
 
+        if ($stage == "burntool") continue;
         $reverting = getRevertStatus($db, $stage);
         $link = "czartool_labels.php?pass=" . $pass . "&proj=" . $proj . "&label=" . $selectedLabel . "&stage=" . $selectedStage . "&revertstage=" . $stage . "&revertmode=";
@@ -234,7 +249,6 @@
     echo "</tr>\n";
     echo "<tr><td></td>\n";
+    write_header_cell($class, " ");
     write_header_cell($class, "Label (in order of priority)");
-    write_header_cell($class, "Distributing?");
-    write_header_cell($class, "Publishing?");
     foreach ($stages as &$stage) {
         
@@ -254,5 +268,5 @@
 
     // write rows
-    foreach ($stdsLabels as &$stdsLabel) {
+    foreach ($labels as &$thisLabel) {
 
         $distributing = false;
@@ -260,67 +274,75 @@
         foreach ($distLabels as &$distLabel) {
 
-            if ($stdsLabel == $distLabel) { $distributing = true; break;}
+            if ($thisLabel == $distLabel) { $distributing = true; break;}
         }
         foreach ($pubLabels as &$pubLabel) {
 
-            if ($stdsLabel == $pubLabel) { $publishing = true; break;}
+            if ($thisLabel == $pubLabel) { $publishing = true; break;}
         }
 
         // create link to label summary page for each label
-        if ($stdsLabel == $selectedLabel) $link = "";
-        else $link = "czartool_labels.php?pass=" . $pass . "&proj=" . $proj . "&label=" . $stdsLabel . "&stage=" . $selectedStage;
+        if ($thisLabel == $selectedLabel) $link = "";
+        else $link = "czartool_labels.php?pass=" . $pass . "&proj=" . $proj . "&label=" . $thisLabel . "&stage=" . $selectedStage;
 
         echo "<tr><td></td>\n";
-        write_table_cell($class, '%s', $link, $stdsLabel);
-        write_table_cell($class, '%s', "", $distributing ? "yes" : "NO");
-        write_table_cell($class, '%s', "", $publishing ? "yes" : "NO");
+        $distPub = " ";
+        if ($distributing) $distPub = "D";
+        if ($publishing) $distPub = $distPub . "P";
+        write_table_cell($class, '%s', "", $distPub);
+
+        write_table_cell($class, '%s', $link, $thisLabel);
 
         $str = "";
         $anyFaults = false; 
 
-        $link = "chipProcessedImfile_failure.php?pass=" . $pass . "&proj=" . $proj . "&chipRun.label=" . $stdsLabel . "&chipRun.state=new";
-        getStateAndFaults($db, $stdsLabel, $selectedState, "chip", $str, $anyFaults);
+        $link = $defaultlink;
+        getStateAndFaults($db, $thisLabel, $selectedState, "burntool", $str, $anyFaults);
         write_table_cell($class, '%s', $anyFaults ? $link : "", $str);
 
-        $link = "camProcessedExp_failure.php?pass=" . $pass . "&proj=" . $proj . "&camRun.label=" . $stdsLabel . "&camRun.state=new";
-        getStateAndFaults($db, $stdsLabel, $selectedState, "cam", $str, $anyFaults);
+        $link = "failedChipProcessedImfile.php?pass=" . $pass . "&proj=" . $proj . "&chipRun.label=" . $thisLabel . "&chipRun.state=new";
+        getStateAndFaults($db, $thisLabel, $selectedState, "chip", $str, $anyFaults);
+        write_table_cell($class, '%s', $anyFaults ? $link : "", $str);
+
+        $link = "failedCamProcessedExp.php?pass=" . $pass . "&proj=" . $proj . "&camRun.label=" . $thisLabel . "&camRun.state=new";
+        getStateAndFaults($db, $thisLabel, $selectedState, "cam", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
 
+        $link =  "failedFakeProcessedImfile.php?pass=" . $pass . "&proj=" . $proj . "&fakeRun.label=" . $thisLabel . "&fakeRun.state=new";
+        getStateAndFaults($db, $thisLabel, $selectedState, "fake", $str, $anyFaults);
+        write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
+
+        $link = "failedWarpSkyfiles.php?pass=" . $pass . "&proj=" . $proj . "&warpRun.label=" . $thisLabel . "&warpRun.state=new";
+        getStateAndFaults($db, $thisLabel, $selectedState, "warp", $str, $anyFaults);
+        write_table_cell($class, '%s',  $anyFaults ? $link : "",  $str);
+
+        $link = "failedStackSkyfile.php?pass=" . $pass . "&proj=" . $proj . "&stackRun.label=" . $thisLabel . "&stackRun.state=new";
+        getStateAndFaults($db, $thisLabel, $selectedState, "stack", $str, $anyFaults);
+        write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
+
+        $link = "failedDiffSkyfile.php?pass=" . $pass . "&proj=" . $proj . "&diffRun.label=" . $thisLabel . "&diffRun.state=new";
+        getStateAndFaults($db, $thisLabel, $selectedState, "diff", $str, $anyFaults);
+        write_table_cell($class, '%s',  $anyFaults ? $link : "",  $str);
+
         $link = $defaultlink;
-        getStateAndFaults($db, $stdsLabel, $selectedState, "fake", $str, $anyFaults);
+        getStateAndFaults($db, $thisLabel, $selectedState, "magic", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
 
-        $link = "warpFailedSkyfiles.php?pass=" . $pass . "&proj=" . $proj . "&warpRun.label=" . $stdsLabel . "&warpRun.state=new";
-        getStateAndFaults($db, $stdsLabel, $selectedState, "warp", $str, $anyFaults);
-        write_table_cell($class, '%s',  $anyFaults ? $link : "",  $str);
-
-        $link = "stackFailedSkyfile.php?pass=" . $pass . "&proj=" . $proj . "&stackRun.label=" . $stdsLabel . "&stackRun.state=new";
-        getStateAndFaults($db, $stdsLabel, $selectedState, "stack", $str, $anyFaults);
+        $link = $defaultlink;
+        getStateAndFaults($db, $thisLabel, $selectedState, "magicDS", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
 
-        $link = "diffFailedSkyfile.php?pass=" . $pass . "&proj=" . $proj . "&diffRun.label=" . $stdsLabel . "&diffRun.state=new";
-        getStateAndFaults($db, $stdsLabel, $selectedState, "diff", $str, $anyFaults);
-        write_table_cell($class, '%s',  $anyFaults ? $link : "",  $str);
-
         $link = $defaultlink;
-        getStateAndFaults($db, $stdsLabel, $selectedState, "magic", $str, $anyFaults);
+        getStateAndFaults($db, $thisLabel, $selectedState, "dist", $str, $anyFaults);
         write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
 
-        $link = $defaultlink;
-        getStateAndFaults($db, $stdsLabel, $selectedState, "magicDS", $str, $anyFaults);
-        write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
-
-        $link = $defaultlink;
-        getStateAndFaults($db, $stdsLabel, $selectedState, "dist", $str, $anyFaults);
-        write_table_cell($class, '%s',  $anyFaults ? $link : "", $str);
-
         echo "</tr>\n";
     }
 
-    if ($selectedLabel == "all_labels") $link = "";
-    else  $link = "czartool_labels.php?pass=" . $pass . "&proj=" . $proj . "&label=all_labels&stage=".$selectedStage;
+    if ($selectedLabel == "all_".$server."_labels") $link = "";
+    else  $link = "czartool_labels.php?pass=" . $pass . "&proj=" . $proj . "&label=all_".$server."_labels&stage=".$selectedStage;
 
     echo "<tr><td></td>\n";
-    write_table_cell($class, '%s', $link, "All labels");
+    write_table_cell($class, '%s', "", " ");
+    write_table_cell($class, '%s', $link, "All $server labels");
 
     echo "</tr>\n";
Index: /branches/sc_branches/trunkTest/ippMonitor/raw/diskUsage.php
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/raw/diskUsage.php	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippMonitor/raw/diskUsage.php	(revision 29060)
@@ -0,0 +1,206 @@
+<?php 
+
+$restricted = 0;
+$TbyteAll = 0;
+
+include 'ipp.php';
+
+function table_section ($db, $WHERE, $TABLE) {
+
+  global $TbytesAll;
+
+  if ("$TABLE" == "rawExp") {
+    # $sql = "SELECT count(exp_id) as n, state, data_state FROM rawExp join rawImfile using (exp_id) $WHERE";
+    $sql = "SELECT count(exp_id) as n, data_state FROM rawImfile where data_state != 'lossy' and data_state != 'missing' group by data_state";
+    # 3GB per exposures (2 copies, compressed)
+    $unitSize = 50;
+  }
+
+  if ("$TABLE" == "chipRun") {
+    # $sql = "SELECT count(chip_id) as n, state, data_state FROM chipRun join chipProcessedImfile using (chip_id) $WHERE";
+    $sql = "SELECT count(chip_id) as n, data_state FROM chipProcessedImfile where data_state != 'cleaned' and data_state != 'purged' and data_state != 'scrubbed' group by data_state";
+    $unitSize = 60;
+  }
+
+  if ("$TABLE" == "warpRun") {
+    # $sql = "SELECT count(warp_id) as n, state, data_state FROM warpRun join warpSkyfile using (warp_id) $WHERE";
+    $sql = "SELECT count(warp_id) as n, data_state FROM warpSkyfile where data_state != 'cleaned' and data_state != 'purged' and data_state != 'scrubbed' group by data_state";
+    $unitSize = 80;
+  }
+
+  if ("$TABLE" == "diffRun") {
+    # $sql = "SELECT count(diff_id) as n, state, data_state FROM diffRun join diffSkyfile using (diff_id) $WHERE";
+    $sql = "SELECT count(diff_id) as n, data_state FROM diffSkyfile where data_state != 'cleaned' and data_state != 'purged' and data_state != 'scrubbed' group by data_state";
+    $unitSize = 80;
+  }
+
+  $FILTER = "distRun.clean = 1 and distRun.state != 'cleaned'";
+  if ("$TABLE" == "distRawClean") {
+    $sql = "SELECT count(dist_id) as n, distRun.state from distRun join distComponent using (dist_id) where distRun.stage = 'raw' and $FILTER group by distRun.state";
+    echo "<b>$sql</b>\n";
+    $unitSize = 0.5;
+  }
+  
+  if ("$TABLE" == "distChipClean") {
+    $sql = "SELECT count(dist_id) as n, distRun.state from distRun join distComponent using (dist_id) where distRun.stage = 'chip' and $FILTER group by distRun.state";
+    $unitSize = 0.5;
+  }
+
+  if ("$TABLE" == "distWarpClean") {
+    $sql = "SELECT count(dist_id) as n, distRun.state from distRun join distComponent using (dist_id) where distRun.stage = 'warp' and $FILTER  group by distRun.state";
+    $unitSize = 0.5;
+  }
+  
+  if ("$TABLE" == "distDiffClean") {
+    $sql = "SELECT count(dist_id) as n, distRun.state from distRun join distComponent using (dist_id) where distRun.stage = 'diff' and $FILTER  group by distRun.state";
+    $unitSize = 0.5;
+  }
+  
+  $FILTER = "distRun.clean = 0 and distRun.state != 'cleaned'";
+  if ("$TABLE" == "distRawFull") {
+    $sql = "SELECT count(dist_id) as n, distRun.state from distRun join distComponent using (dist_id) where distRun.stage = 'raw' and $FILTER  group by distRun.state";
+    $unitSize = 50;
+  }
+  
+  if ("$TABLE" == "distChipFull") {
+    $sql = "SELECT count(dist_id) as n, distRun.state from distRun join distComponent using (dist_id) where distRun.stage = 'chip' and $FILTER  group by distRun.state";
+    $unitSize = 60;
+  }
+  
+  if ("$TABLE" == "distWarpFull") {
+    $sql = "SELECT count(dist_id) as n, distRun.state from distRun join distComponent using (dist_id) where distRun.stage = 'warp' and $FILTER  group by distRun.state";
+    $unitSize = 80;
+  }
+  
+  if ("$TABLE" == "distDiffFull") {
+    $sql = "SELECT count(dist_id) as n, distRun.state from distRun join distComponent using (dist_id) where distRun.stage = 'diff' and $FILTER  group by distRun.state";
+    $unitSize = 80;
+  }
+
+  $qry = $db->query($sql);
+  if (dberror($qry)) {
+    echo "<tr><td><b>error reading $TABLE table</b></td></tr>\n";
+    echo "<tr><td><br><small><b> table query : $sql </b></small></td></tr>\n";
+  }
+  
+  $class = "list";
+  $nlines = 0;
+  
+  $TbytesSum = 0;
+
+  // list the results
+  while ($qry->fetchInto($row)) {
+    echo "<tr><td class=\"$class\"><b>$TABLE</b></td>\n";
+    // ** TABLE DATA **
+
+    $Tbytes = $row[0]*$unitSize/1000000.0;
+    $TbytesSum += $Tbytes;
+    $TbytesAll += $Tbytes;
+
+    write_table_cell ($class, '%s', "", $row[0]);
+    write_table_cell ($class, '%s', "", $row[1]);
+    write_table_cell ($class, '%s', "", $Tbytes);
+    write_table_cell ($class, '%s', "", $TbytesSum);
+    write_table_cell ($class, '%s', "", $TbytesAll);
+    echo "</tr>\n";
+    $nlines ++;
+  }
+  echo "<tr><td class\"$class\">------</td></tr>\n";
+
+  if ($nlines == 0) {
+    echo "<tr><td class\"$class\"><b>$TABLE</b></td><td>no match</td></tr>\n";
+  }
+}
+
+$ID = checkID ();
+
+// require an explicit project
+if (! $ID['proj']) { projectform ($ID); }
+
+$db = dbconnect($ID['proj']);
+
+if ($ID['menu']) {
+  $myMenu = $ID['menu'];
+} else {
+  $myMenu = "ipp.imfiles.dat";
+}
+
+menu($myMenu, 'Disk Usage', 'ipp.css', $ID['link'], $ID['proj']);
+
+echo "<p> Night Summary </p>\n";
+
+// set up the form
+echo "<form action=\"diskUsage.php\" method=\"POST\">\n";
+
+$restricted = 0;
+
+// define restrictions to the queries
+// ** TABLE RESTRICTIONS **
+$WHERE = check_restrict ('state', $WHERE, 'string', 1.0);
+
+// ensure no valid results
+if ($restricted == 0) {
+   $WHERE = "$WHERE WHERE (0 > 1)";
+}
+
+$WHERE = check_ordering ('state,label', $WHERE);
+
+// set up the table
+echo "<table class=list>\n";
+
+// echo "<tr><td></td>\n"; // first field is a label set below for the query rows only
+// ** TABLE HEADER **
+echo "<tr><td></td>\n";
+write_header_cell ("list", "N items");
+write_header_cell ("list", "state");
+write_header_cell ("list", "Tbytes");
+write_header_cell ("list", "Sum(TB)");
+write_header_cell ("list", "All(TB)");
+echo "</tr>\n";
+
+// query restriction form
+// echo "<tr>\n";
+// echo "<td class=list> <input type=\"text\" name=\"expID\"></td>\n";
+// ** TABLE QUERY ** (restictions)
+echo "<tr><td>Dataset</td>\n";
+write_query_row ('N items', 15, 'string');
+write_query_row ('state', 10, 'string');
+write_query_row ('Mbytes', 7, 'string');
+write_query_row ('Sum(MB)', 7, 'string');
+echo "</tr>\n";
+
+// query the database (limit is 10, but should be 1
+table_section($db, $WHERE, "rawExp");
+table_section($db, $WHERE, "chipRun");
+table_section($db, $WHERE, "warpRun");
+table_section($db, $WHERE, "diffRun");
+
+table_section($db, $WHERE, "distRawClean");
+table_section($db, $WHERE, "distChipClean");
+table_section($db, $WHERE, "distWarpClean");
+table_section($db, $WHERE, "distDiffClean");
+
+table_section($db, $WHERE, "distRawFull");
+table_section($db, $WHERE, "distChipFull");
+table_section($db, $WHERE, "distWarpFull");
+table_section($db, $WHERE, "distDiffFull");
+
+// close the table and form
+echo "</table>\n";
+echo "<input type=\"submit\" name=\"constraints\" value=\"refine search\">\n";
+$pass = $ID['pass'];
+$proj = $ID['proj'];
+$menu = $ID['menu'];
+echo "<input type=\"hidden\" name=\"pass\" value=\"$pass\">\n";
+echo "<input type=\"hidden\" name=\"proj\" value=\"$proj\">\n";
+echo "<input type=\"hidden\" name=\"menu\" value=\"$menu\">\n";
+echo "</form>\n";
+
+// ** TAIL CODE **
+
+echo "<small> WHERE: $WHERE<br><br></small>\n";
+echo "<small> SQL: $sql<br><br></small>\n";
+
+menu_end();
+
+?>
Index: /branches/sc_branches/trunkTest/ippMonitor/raw/ipp.imfiles.dat
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/raw/ipp.imfiles.dat	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippMonitor/raw/ipp.imfiles.dat	(revision 29060)
@@ -25,4 +25,16 @@
 
 menutop   | menutop      | plain   | &nbsp;                       | 
+menutop   | menutop      | link    | New failed chip              | failedChipProcessedImfile.php
+menutop   | menutop      | link    | New failed cam               | failedCamProcessedExp.php
+menutop   | menutop      | link    | New failed fake              | failedFakeProcessedImfile.php
+menutop   | menutop      | link    | New failed warp              | failedWarpSkyfiles.php
+menutop   | menutop      | link    | New failed stack             | failedStackSkyfile.php
+menutop   | menutop      | link    | New failed diff              | failedDiffSkyfile.php
+menutop   | menutop      | link    | New failed magic tree        | failedMagicTrees.php
+menutop   | menutop      | link    | New failed magic node        | failedMagicNodes.php
+menutop   | menutop      | link    | New failed magic mask        | failedMagicMasks.php
+
+menutop   | menutop      | plain   | &nbsp;                       | 
 menulink  | menuselect 	 | link    | Tables columns               | columns_in_db.php
 menulink  | menuselect 	 | link    | Clean /tmp directory         | cleanTmpDirectory.php
+menutop   | menutop      | link    | disk usage                   | diskUsage.php
Index: /branches/sc_branches/trunkTest/ippMonitor/scripts/generate
===================================================================
--- /branches/sc_branches/trunkTest/ippMonitor/scripts/generate	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippMonitor/scripts/generate	(revision 29060)
@@ -648,5 +648,5 @@
     foreach $word (@words) {
         $fword = &parse_fieldname ($word);
-        # print "field: $word -> $fword\n";
+#         print "field: $word -> $fword\n";
         push @outwords, $fword;
         if ($word =~ m|^\$|) {
@@ -660,6 +660,6 @@
     $opf{$name} = $outline;
 
-    # print "ops: $name : $ops{$name}\n";
-    # print "opf: $name : $opf{$name}\n";
+#     print "ops: $name : $ops{$name}\n";
+#     print "opf: $name : $opf{$name}\n";
 
     return 1;
Index: /branches/sc_branches/trunkTest/ippScripts/scripts/addstar_run.pl
===================================================================
--- /branches/sc_branches/trunkTest/ippScripts/scripts/addstar_run.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippScripts/scripts/addstar_run.pl	(revision 29060)
@@ -147,4 +147,9 @@
 	    
 	}
+        else {
+
+            $minidvodb_path = $dvodbReal;
+        }
+
 unless ($no_op) {
    	    print $dvodbReal;
Index: /branches/sc_branches/trunkTest/ippScripts/scripts/automate_stacks.pl
===================================================================
--- /branches/sc_branches/trunkTest/ippScripts/scripts/automate_stacks.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippScripts/scripts/automate_stacks.pl	(revision 29060)
@@ -46,4 +46,5 @@
 my ( $check_stacks, $queue_stacks, $check_sweetspot, $queue_sweetspot, $check_diffs, $queue_diffs, $clean_old);
 my ( $check_detrends, $queue_detrends, $check_dqstats, $queue_dqstats);
+my ( $confirm_stacks, $check_confirm_stacks );
 
 GetOptions(
@@ -70,4 +71,6 @@
     'check_stacks'         => \$check_stacks,
     'queue_stacks'         => \$queue_stacks,
+    'confirm_stacks'       => \$confirm_stacks,
+    'check_confirm_stacks' => \$check_confirm_stacks,
     'check_sweetspot'      => \$check_sweetspot,
     'queue_sweetspot'      => \$queue_sweetspot,
@@ -120,5 +123,6 @@
     defined $queue_chips or defined $queue_stacks or $queue_sweetspot or $queue_detrends or $queue_dqstats or 
     defined $check_chips or defined $check_stacks or $check_sweetspot or $check_detrends or $check_dqstats or
-    defined $test_mode or defined $clean_old or defined $check_mode;
+    defined $test_mode or defined $clean_old or defined $check_mode or
+    defined $confirm_stacks;
 
 # Configurable parameters from our config file.
@@ -132,4 +136,5 @@
 my %stackable_list = ();
 my %reduction_class = ();
+my %macro_formats = ();
 my @unrecoverable_quality = ();
 my @detrend_list = ();
@@ -181,4 +186,16 @@
     elsif (${ $entry }{name} eq 'UNRECOVERABLE_QUALITY') {
         push @unrecoverable_quality, ${ $entry }{value};
+    }
+    elsif (${ $entry }{name} eq 'MACRO_DEFINITIONS') {
+	my @macro_data = @{ ${ $entry }{value} };
+	my $this_mode = '';
+	foreach my $mentry (@macro_data) {
+	    if (${ $mentry }{name} eq 'PROC_MODE') {
+		$this_mode = ${ $mentry }{value};
+	    }
+	    elsif (${ $mentry }{name} eq 'MACRO') {
+		$macro_formats{$this_mode} = ${ $mentry }{value};
+	    }
+	}
     }
     elsif (${ $entry }{name} eq 'TARGETS') {
@@ -306,4 +323,7 @@
 	print "CLEAN: $z $clean_commands{$z} $clean_retention{$z}\n";
     }
+    foreach $z (keys (%macro_formats)) {
+	print "MACROS: $z $macro_formats{$z}\n";
+    }
     
 }
@@ -385,4 +405,17 @@
 	$metadata_out{nsState} = 'STACKING_POSSIBLE_ERROR';
     }
+    return_metadata($date);
+    exit(0);
+}
+
+if (defined($check_confirm_stacks) || defined($test_mode) || defined($check_mode)) {
+    $metadata_out{nsState} = 'CONFIRM_STACKING';
+    &confirm_stacks($date,"pretend");
+    return_metadata($date);
+    unless (defined($test_mode) || defined($check_mode)) { exit(0); }
+}
+if (defined($confirm_stacks)) {
+    $metadata_out{nsState} = 'CONFIRM_STACKING';
+    &confirm_stacks($date);
     return_metadata($date);
     exit(0);
@@ -582,5 +615,5 @@
     $metadata_out{btN} = $N - 1;
     $metadata_out{btNCounter} = 0;
-
+    add_to_macro_list('define_burntool',1,$date);
     return(0);
 }
@@ -589,4 +622,5 @@
 # Chips
 ################################################################################
+
 
 sub construct_chiptool_cmd {
@@ -680,4 +714,5 @@
     }
     $metadata_out{nsState} = 'TOWARP';
+
     return(0);
 }
@@ -696,9 +731,9 @@
         if ($Nexposures == 0) {
 	    print STDERR "execute_chips: Target $target on $date had no exposures.\n";
-	    next;
+#	    next;
         }
         if ($Nalready != 0) {
 	    print STDERR "execute_chips: Not queueing $target on $date due to already existing exposures.\n";
-            next;
+#            next;
         }
         if ($Nimfiles != $Nburntooled) {
@@ -712,4 +747,11 @@
             chip_queue($date,$target);
         }
+	if (defined($pretend)) {
+	    add_to_macro_list('check_chips',$stackable_list{$target},$date,$target);
+	}
+	else {
+	    add_to_macro_list('queue_chips',$stackable_list{$target},$date,$target);
+	}
+		    
     }
     if ($exposures == 0) {
@@ -717,4 +759,5 @@
     }
 }
+
 
 #
@@ -742,14 +785,4 @@
     my $date = shift;
     
-#     my $db = init_gpc_db();
-#     my $trunc_date = $date; $trunc_date =~ s/-//g;
-
-#     my $where = " label LIKE '%.nightlyscience' AND data_group' ";
-#     my $chip_sth = "SELECT * from chipRun WHERE (state = 'full' OR state = 'new' OR state = 'cleaned') AND $where ";
-#     my $cam_sth = "SELECT * from camRun WHERE state = 'full' AND $where ";
-
-#     my $chip_ref = $db->selectall_arrayref( $chip_sth );
-#     my $cam_ref = $db->selectall_arrayref( $cam_sth );
-    
     my $command = construct_dqstats_cmd($date) . ' -pretend ';
     my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
@@ -762,5 +795,5 @@
     my @input_exposures = split /\n/, (join '', @$stdout_buf);
 
-    return($#input_exposures + 1,1,1); # $#{ $chip_ref } + 1, $#{ $cam_ref } + 1);
+    return($#input_exposures + 1,1,1); 
 }
  
@@ -791,4 +824,10 @@
 	unless(defined($pretend)) {
 	    dqstats_queue($date);
+	}
+	if (defined($pretend)) {
+	    add_to_macro_list('check_dqstats',1,$date);
+	}
+	else {
+	    add_to_macro_list('queue_dqstats',1,$date);
 	}
     }
@@ -887,4 +926,10 @@
 	    detrend_queue($date,$target);
 	}
+	if (defined($pretend)) {
+	    add_to_macro_list('check_detrends',1,$date,$target,"dettool");
+	}
+	else {
+	    add_to_macro_list('queue_detrends',1,$date,$target,"dettool");
+	}
     }
     if ($exposures == 0) {
@@ -1023,4 +1068,10 @@
 	$metadata_out{nsState} = 'SS_DONE';
 	sweetspot_queue($date);
+    }
+    if (defined($pretend)) {
+	add_to_macro_list('check_sweetspot',1,$date);
+    }
+    else {
+	add_to_macro_list('queue_sweetspot',1,$date);
     }
 }
@@ -1173,4 +1224,10 @@
                     stack_queue($date,$target,$filter);
                 }
+		if (defined($pretend)) {
+		    add_to_macro_list('check_stacks',$stackable_list{$target},$date,$target,$filter);
+		}
+		else {
+		    add_to_macro_list('queue_stacks',$stackable_list{$target},$date,$target,$filter);
+		}
             }
         }
@@ -1181,4 +1238,55 @@
 
 }
+
+sub post_stack_queue {
+    my $date = shift;
+    my $target = shift;
+
+    my ($label,$workdir,$obs_mode,$object,$comment,$tess_id,$dist_group,$data_group,$reduction) = get_tool_parameters($date,$target);
+    # check warp stage == chip stage
+    my $db = init_gpc_db();
+
+    my $trunc_date = $date; $trunc_date =~ s/-//g;
+
+    my $where = " label = '$label' AND data_group = '$data_group' ";
+
+    my $stack_full_sth = "SELECT * from stackRun where $where ";
+    my $stack_done_sth = "SELECT * from stackRun LEFT JOIN stackSumSkyfile USING(stack_id) WHERE $where ";
+    $stack_done_sth .= " AND ((state = 'full') OR (state = 'new' && fault != 0)) ";
+
+    my $stack_full_ref = $db->selectall_arrayref( $stack_full_sth );
+    my $stack_done_ref = $db->selectall_arrayref( $stack_done_sth );
+
+    return($#{ $stack_full_ref } + 1, $#{ $stack_done_ref } + 1);
+}
+
+sub confirm_stacks {
+    my $date = shift;
+    my $pretend = shift;
+    
+    foreach my $target (@target_list) {
+        if ($stackable_list{$target} == 1) {
+	    my ($Nstacks, $Nattempted) = post_stack_queue($date,$target);
+	    if ($Nstacks != $Nattempted) {
+		if ($debug == 1) {
+		    print STDERR "confirm_stacks: Target $target on $date is not done stacking. $Nstacks $Nattempted\n"
+		}
+		if ($metadata_out{nsState} eq 'CONFIRM_STACKING') {
+		    $metadata_out{nsState} = 'STACKING';
+		}
+		    
+		next;
+	    }
+	    if ($metadata_out{nsState} eq 'CONFIRM_STACKING') {
+		if (defined($pretend)) {
+		    add_to_macro_list('check_confirm_stacks',$stackable_list{$target},$date,$target);
+		}
+		else {
+		    add_to_macro_list('confirm_stacks',$stackable_list{$target},$date,$target);
+		}
+	    }
+	}
+    }
+}	    
 
 #
@@ -1233,47 +1341,27 @@
 
     foreach my $mode (@mode_list) {
-# 	if ((exists($clean_alternate{$mode})) && ($clean_alternate{$mode} eq 'A')) {
-# 	    my ($cleaning_date,$command) = construct_cleantool_args($date,"",$mode);
-# 	    if ($cleaning_date eq 'no clean') {
-# 		next;
-# 	    }
-# 	    print STDERR "$command\n";
-# 	    if (!(defined($pretend) || $debug == 1)) {
-# #           print STDERR "BEAR IS DRIVING!?\n";
-# 		my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-# 		    run ( command => $command, verbose => $verbose );
-# 		unless ($success) {
-# 		    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-# 		    &my_die("Unable to perform cleantool ($command): $error_code", 0,0,$date, $PS_EXIT_SYS_ERROR);
-# 		}
-# 	    }
-# 	}
-# 	else {
-	    foreach my $target (@target_list) {
-		if (exists($noclean_list{$target})) {
-		    next;
+	foreach my $target (@target_list) {
+	    if (exists($noclean_list{$target})) {
+		next;
+	    }
+	    my ($cleaning_date,$command) = construct_cleantool_args($date,$target,$mode);
+	    if ($cleaning_date eq 'no clean') {
+		next;
+	    }		
+	    print STDERR "$command\n";
+	    if (!(defined($pretend) || $debug == 1)) {
+#           print STDERR "BEAR IS DRIVING!?\n";
+		my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+		    run ( command => $command, verbose => $verbose );
+		unless ($success) {
+		    $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
+		    &my_die("Unable to perform cleantool ($command): $error_code", 0,0,$date, $PS_EXIT_SYS_ERROR);
 		}
-		my ($cleaning_date,$command) = construct_cleantool_args($date,$target,$mode);
-		if ($cleaning_date eq 'no clean') {
-		    next;
-		}		
-		print STDERR "$command\n";
-		if (!(defined($pretend) || $debug == 1)) {
-#           print STDERR "BEAR IS DRIVING!?\n";
-		    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
-			run ( command => $command, verbose => $verbose );
-		    unless ($success) {
-			$error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
-			&my_die("Unable to perform cleantool ($command): $error_code", 0,0,$date, $PS_EXIT_SYS_ERROR);
-		    }
-		}
-	    }
-# 	}
+		add_to_macro_list('clean_old',1,$date,$target,$mode);
+	    }
+	}
     }
     return(0);
 }
-
-
-
 
 #
@@ -1324,4 +1412,42 @@
     my $workdir = 'neb://@HOST@.0/' . $dbname . "/detverify.nt/${workdir_date}/${lc_type}${internal_filter}";
     return($label,$workdir,$det_filter,$exp_type,$det_type,$ref_det_id,$ref_iter,$maxN);
+}
+
+sub add_to_macro_list {
+    my $proc_mode = shift;
+    my $do_or_do_not = shift;
+    my $date = shift;
+    my $target = shift;
+    my $mode = shift;
+
+    if ((defined($macro_formats{$proc_mode}))&&($do_or_do_not)) {
+	unless (defined($metadata_out{N_MACROS})) {
+	    $metadata_out{N_MACROS} = 0;
+	}
+	my $N = $metadata_out{N_MACROS};
+	$metadata_out{"ns${N}Macro"} = $macro_formats{$proc_mode};
+	print STDERR "WORKING ON A MACRO: ns${N}Macro $proc_mode $macro_formats{$proc_mode}\n";
+	if (defined($date)&&(defined($target))) {
+
+	    my ($label,$workdir,$obs_mode,$object,$comment,$tess_id,$dist_group,$data_group,$reduction) 
+		= get_tool_parameters($date,$target);
+	    $metadata_out{"ns${N}Macro"} =~ s/\@LABEL\@/$label/;
+	    $metadata_out{"ns${N}Macro"} =~ s/\@WORKDIR\@/$workdir/;
+	    $metadata_out{"ns${N}Macro"} =~ s/\@OBS_MODE\@/$obs_mode/;
+	    $metadata_out{"ns${N}Macro"} =~ s/\@OBJECT\@/$object/;
+	    $metadata_out{"ns${N}Macro"} =~ s/\@COMMENT\@/$comment/;
+	    $metadata_out{"ns${N}Macro"} =~ s/\@TESS_ID\@/$tess_id/;
+	    $metadata_out{"ns${N}Macro"} =~ s/\@DIST_GROUP\@/$dist_group/;
+	    $metadata_out{"ns${N}Macro"} =~ s/\@DATA_GROUP\@/$data_group/;
+	    $metadata_out{"ns${N}Macro"} =~ s/\@REDUCTION\@/$reduction/;
+	}
+	if (defined($mode)) {
+	    $metadata_out{"ns${N}Macro"} =~ s/\@EXTRA\@/$mode/;
+	}
+	if (defined($date)) {
+	    $metadata_out{"ns${N}Macro"} =~ s/\@DATE\@/$date/;
+	}
+	$metadata_out{N_MACROS} ++;
+    }
 }
 
Index: /branches/sc_branches/trunkTest/ippScripts/scripts/dist_advancerun.pl
===================================================================
--- /branches/sc_branches/trunkTest/ippScripts/scripts/dist_advancerun.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippScripts/scripts/dist_advancerun.pl	(revision 29060)
@@ -67,4 +67,5 @@
 my $stacktool   = can_run('stacktool') or (warn "Can't find stacktool" and $missing_tools = 1);
 my $bgtool = can_run('bgtool') or (warn "Can't find bgtool" and $missing_tools = 1);
+my $staticskytool = can_run('staticskytool') or (warn "Can't find staticskytool" and $missing_tools = 1);
 if ($missing_tools) {
     &my_die("Can't find required tools.", $dist_id, $PS_EXIT_CONFIG_ERROR);
@@ -108,4 +109,8 @@
     $list_mode = "-sumskyfile";
     $component_key = "skycell_id";
+} elsif ($stage eq "sky") {
+    $tool_cmd = "$staticskytool -sky_id";
+    $list_mode = "-result";
+    $component_key = "";
 } elsif ($stage eq "diff") {
     $tool_cmd = "$difftool -diff_id";
Index: /branches/sc_branches/trunkTest/ippScripts/scripts/dist_bundle.pl
===================================================================
--- /branches/sc_branches/trunkTest/ippScripts/scripts/dist_bundle.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippScripts/scripts/dist_bundle.pl	(revision 29060)
@@ -53,4 +53,7 @@
                       'PPSTACK.OUTPUT.MASK' => 'mask',
                       'PPSTACK.OUTPUT.VARIANCE' => 'variance' );
+my %sky_cleaned   = ( 'PSPHOT.STACK.OUTPUT.IMAGE' => 'image',
+                      'PSPHOT.STACK.OUTPUT.MASK' => 'mask',
+                      'PSPHOT.STACK.OUTPUT.VARIANCE' => 'variance' );
 
 
@@ -420,4 +423,6 @@
     } elsif ($stage eq "stack") {
         $type = $stack_cleaned{$rule};
+    } elsif ($stage eq "sky") {
+        $type = $sky_cleaned{$rule};
     } else {
         &my_die("$stage is not a valid stage", $component, $PS_EXIT_CONFIG_ERROR);
@@ -500,4 +505,6 @@
     } elsif ($stage eq "stack") {
         $config_file_rule = "PPSTACK.CONFIG";
+    } elsif ($stage eq "sky") {
+        $config_file_rule = "PSPHOT.STACK.CONFIG";
     } else {
         &my_die("$stage is not a valid stage", $component, $PS_EXIT_CONFIG_ERROR);
Index: /branches/sc_branches/trunkTest/ippScripts/scripts/dist_make_fileset.pl
===================================================================
--- /branches/sc_branches/trunkTest/ippScripts/scripts/dist_make_fileset.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippScripts/scripts/dist_make_fileset.pl	(revision 29060)
@@ -223,5 +223,5 @@
     my $dbname = shift;
 
-    if (($stage eq 'stack') or ($stage eq 'diff') or ($stage eq 'SSdiff')) {
+    if (($stage eq 'stack') or ($stage eq 'diff') or ($stage eq 'SSdiff') or $stage eq 'sky') {
         return "";
     }
Index: /branches/sc_branches/trunkTest/ippScripts/scripts/staticsky.pl
===================================================================
--- /branches/sc_branches/trunkTest/ippScripts/scripts/staticsky.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippScripts/scripts/staticsky.pl	(revision 29060)
@@ -99,4 +99,6 @@
 my $nInputs = @$files;
 
+my $configuration = $ipprc->filename("PSPHOT.STACK.CONFIG", $outroot);
+
 foreach my $file (@$files) {
     print $listFile "INPUT   METADATA\n";
@@ -161,5 +163,5 @@
     $command .= " -threads $threads" if defined $threads;
     $command .= " -recipe PSPHOT $recipe_psphot";
-    # $command .= " -dumpconfig $configuration";
+    $command .= " -dumpconfig $configuration";
     # $command .= " -tracedest $traceDest -log $logDest";
     # $command .= " -dbname $dbname" if defined $dbname;
Index: /branches/sc_branches/trunkTest/ippTasks/nightly_stacks.pro
===================================================================
--- /branches/sc_branches/trunkTest/ippTasks/nightly_stacks.pro	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippTasks/nightly_stacks.pro	(revision 29060)
@@ -88,4 +88,7 @@
     active true
   end
+  task ns.stacks.confirm
+    active true
+  end
 end
 
@@ -155,4 +158,5 @@
 $ns_stackPAGE = 0
 $ns_RstackPAGE = 0
+$ns_CstackPAGE = 0
 
 book init nsData
@@ -431,4 +435,11 @@
     end
 
+    book getword nsData $options:0 nsNmacros -var ns_Nmacros
+    for i 0 $ns_Nmacros
+	sprintf macroName "ns%dMacro" $i
+	book getword nsData $options:0 $macroName -var macroCmd
+	$macroCmd
+    end
+
     if ($VERBOSE > 2)
 	book listbook nsData
@@ -486,4 +497,11 @@
     ipptool2book stdout nsData -uniq -key date
 
+    book getword nsData $options:0 nsNmacros -var ns_Nmacros
+    for i 0 $ns_Nmacros
+	sprintf macroName "ns%dMacro" $i
+	book getword nsData $options:0 $macroName -var macroCmd
+	$macroCmd
+    end
+
     if ($VERBOSE > 2)
 	book listbook nsData
@@ -541,4 +559,11 @@
     ipptool2book stdout nsData -uniq -key date
 
+    book getword nsData $options:0 nsNmacros -var ns_Nmacros
+    for i 0 $ns_Nmacros
+	sprintf macroName "ns%dMacro" $i
+	book getword nsData $options:0 $macroName -var macroCmd
+	$macroCmd
+    end
+
     if ($VERBOSE > 2)
 	book listbook nsData
@@ -562,4 +587,5 @@
 # Check to see if the warps are finished and so we can make stacks.
 #
+
 task              ns.stacks.run
   host            local
@@ -595,4 +621,73 @@
 # We've queued up stacking. We're done with this date, so don't reload the page.
     ipptool2book stdout nsData -uniq -key date
+
+    book getword nsData $options:0 nsNmacros -var ns_Nmacros
+    for i 0 $ns_Nmacros
+	sprintf macroName "ns%dMacro" $i
+	book getword nsData $options:0 $macroName -var macroCmd
+	$macroCmd
+    end
+
+    if ($VERBOSE > 2)
+	book listbook nsData
+    end
+  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
+
+#
+# Confirm that all the stacks that can be built have been built, or at least attempted.
+#
+task              ns.stacks.confirm
+  host            local
+  periods         -poll $LOADPOLL
+  periods         -exec $LOADEXEC
+  periods         -timeout 120
+  npending        1
+
+  task.exec
+     stdout NULL
+     stderr $LOGDIR/ns.stacks.log
+
+     book getpage nsData $ns_CstackPAGE -var date
+     book getword nsData $date nsState -var ns_STATE
+     book npages nsData -var Npages
+
+     if ($VERBOSE > 5)
+	echo "ns.stacks.confirm: " $ns_CstackPAGE $date $ns_STATE $Npages
+     end
+
+     $ns_CstackPAGE ++
+     if ($ns_CstackPAGE >= $Npages) set ns_CstackPAGE = 0
+     option $date
+
+     if ("$ns_STATE" != "STACKING") break
+     $run = automate_stacks.pl --confirm_stacks --date $date
+     command $run
+   end
+  # success
+  task.exit   0
+#    convert 'stdout' to book format
+    book delpage nsData $options:0
+    ipptool2book stdout nsData -uniq -key date
+
+    book getword nsData $options:0 nsNmacros -var ns_Nmacros
+    for i 0 $ns_Nmacros
+	sprintf macroName "ns%dMacro" $i
+	book getword nsData $options:0 $macroName -var macroCmd
+	$macroCmd
+    end
+
     if ($VERBOSE > 2)
 	book listbook nsData
@@ -650,4 +745,11 @@
     ipptool2book stdout nsBurntool -uniq -key date
     book setword nsData $options:0 nsState "QUEUEBURNING"
+
+    book getword nsData $options:0 nsNmacros -var ns_Nmacros
+    for i 0 $ns_Nmacros
+	sprintf macroName "ns%dMacro" $i
+	book getword nsData $options:0 $macroName -var macroCmd
+	$macroCmd
+    end
 
     if ($VERBOSE > 2)
@@ -766,4 +868,12 @@
     # Set the job state for success.
     book setword nsBurntool $options:0 $options:2 FINISHED
+
+    book getword nsData $options:0 nsNmacros -var ns_Nmacros
+    for i 0 $ns_Nmacros
+	sprintf macroName "ns%dMacro" $i
+	book getword nsData $options:0 $macroName -var macroCmd
+	$macroCmd
+    end
+
     if ($VERBOSE > 2)
 	book listbook nsData
Index: /branches/sc_branches/trunkTest/ippToPsps/perl/checkOdmStatus.pl
===================================================================
--- /branches/sc_branches/trunkTest/ippToPsps/perl/checkOdmStatus.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippToPsps/perl/checkOdmStatus.pl	(revision 29060)
@@ -32,13 +32,13 @@
 }
 if (!defined $singleBatch) {
-    print "* OPTIONAL: a single batch                  -b                   (default = none)\n";
+    print "* OPTIONAL: a single batch                  -b <batchNum>        (default = none)\n";
 }
 if (!defined $fromTime) {
     $fromTime = "2010-01-01";
-    print "* OPTIONAL: from time                       -f                   (default = $fromTime)\n";
+    print "* OPTIONAL: from time                       -f <dateTime>        (default = $fromTime)\n";
 }
 if (!defined $toTime) {
     $toTime = "2099-12-31";
-    print "* OPTIONAL: to time                         -t                   (default = $toTime)\n";
+    print "* OPTIONAL: to time                         -t <dateTime>        (default = $toTime)\n";
 }
 if (!defined $verbose) {
@@ -110,5 +110,5 @@
 
     my $response = $ua->post($odmUrl,
-            [batchNameFilter => $batchFilter,
+            [batchNameFilter => "%".$batchFilter,
             statusFilter => $statusFilter,
             fromFilter => "2010-01-01",
Index: /branches/sc_branches/trunkTest/ippToPsps/src/ippToPspsBatchDetection.c
===================================================================
--- /branches/sc_branches/trunkTest/ippToPsps/src/ippToPspsBatchDetection.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippToPsps/src/ippToPspsBatchDetection.c	(revision 29060)
@@ -326,34 +326,38 @@
             fits_write_col(this->fitsOut, TLONG, IMAGEMETA_NDETECT, 1, 1, 1, &numDetectionsOut, &status);
 
-            // detections
-            ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "Detection", false);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_OBJID, 1, 1, nDet, objID, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_DETECTID, 1, 1, nDet, detectID, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IPPOBJID, 1, 1, nDet, ippObjID, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IPPDETECTID, 1, 1, nDet, ippDetectID, &status);
-            fits_write_col(this->fitsOut, TBYTE, DETECTION_FILTERID, 1, 1, nDet, filterIDs, &status);
-            fits_write_col(this->fitsOut, TBYTE, DETECTION_SURVEYID, 1, 1, nDet, surveyIDs, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IMAGEID, 1, 1, nDet, imageID, &status);
-            fits_write_col(this->fitsOut, TDOUBLE, DETECTION_OBSTIME, 1, 1, nDet, obsTimes, &status);
-            fits_write_col(this->fitsOut, TFLOAT, DETECTION_INSTFLUX, 1, 1, nDet, instFlux, &status);
-            fits_write_col(this->fitsOut, TFLOAT, DETECTION_INSTFLUXERR, 1, 1, nDet, instFluxErr, &status);
-            fits_write_col(this->fitsOut, TFLOAT, DETECTION_PEAKADU, 1, 1, nDet, peakFlux, &status);
-            fits_write_col(this->fitsOut, TSTRING, DETECTION_ASSOCDATE, 1, 1, nDet, assocDate, &status); 
-            fits_write_col(this->fitsOut, TLONGLONG, DETECTION_INFOFLAG, 1, 1, nDet, flags, &status); 
-            if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
-
-            // skinny object
-            ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "SkinnyObject", false);
-            fits_write_col(this->fitsOut, TLONGLONG, SKINNYOBJECT_OBJID, 1, 1, nDet, objID, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, SKINNYOBJECT_IPPOBJID, 1, 1, nDet, ippObjID, &status);
-            fits_write_col(this->fitsOut, TBYTE, SKINNYOBJECT_SURVEYID, 1, 1, nDet, surveyIDs, &status);
-            if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
-
-            // object calibration color
-            ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "ObjectCalColor", false);
-            fits_write_col(this->fitsOut, TLONGLONG, OBJECTCALCOLOR_OBJID, 1, 1, nDet, objID, &status);
-            fits_write_col(this->fitsOut, TLONGLONG, OBJECTCALCOLOR_IPPOBJID, 1, 1, nDet, ippObjID, &status);
-            fits_write_col(this->fitsOut, TBYTE, OBJECTCALCOLOR_FILTERID, 1, 1, nDet, filterIDs, &status);
-            if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
+            // avoid writing out an empty table of detections
+            if (numDetectionsOut > 0) {
+
+                // detections
+                ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "Detection", false);
+                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_OBJID, 1, 1, nDet, objID, &status);
+                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_DETECTID, 1, 1, nDet, detectID, &status);
+                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IPPOBJID, 1, 1, nDet, ippObjID, &status);
+                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IPPDETECTID, 1, 1, nDet, ippDetectID, &status);
+                fits_write_col(this->fitsOut, TBYTE, DETECTION_FILTERID, 1, 1, nDet, filterIDs, &status);
+                fits_write_col(this->fitsOut, TBYTE, DETECTION_SURVEYID, 1, 1, nDet, surveyIDs, &status);
+                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_IMAGEID, 1, 1, nDet, imageID, &status);
+                fits_write_col(this->fitsOut, TDOUBLE, DETECTION_OBSTIME, 1, 1, nDet, obsTimes, &status);
+                fits_write_col(this->fitsOut, TFLOAT, DETECTION_INSTFLUX, 1, 1, nDet, instFlux, &status);
+                fits_write_col(this->fitsOut, TFLOAT, DETECTION_INSTFLUXERR, 1, 1, nDet, instFluxErr, &status);
+                fits_write_col(this->fitsOut, TFLOAT, DETECTION_PEAKADU, 1, 1, nDet, peakFlux, &status);
+                fits_write_col(this->fitsOut, TSTRING, DETECTION_ASSOCDATE, 1, 1, nDet, assocDate, &status); 
+                fits_write_col(this->fitsOut, TLONGLONG, DETECTION_INFOFLAG, 1, 1, nDet, flags, &status); 
+                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
+
+                // skinny object
+                ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "SkinnyObject", false);
+                fits_write_col(this->fitsOut, TLONGLONG, SKINNYOBJECT_OBJID, 1, 1, nDet, objID, &status);
+                fits_write_col(this->fitsOut, TLONGLONG, SKINNYOBJECT_IPPOBJID, 1, 1, nDet, ippObjID, &status);
+                fits_write_col(this->fitsOut, TBYTE, SKINNYOBJECT_SURVEYID, 1, 1, nDet, surveyIDs, &status);
+                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
+
+                // object calibration color
+                ippToPspsConfig_writeTable(this->config, fitsIn, this->fitsOut, nDet, "ObjectCalColor", false);
+                fits_write_col(this->fitsOut, TLONGLONG, OBJECTCALCOLOR_OBJID, 1, 1, nDet, objID, &status);
+                fits_write_col(this->fitsOut, TLONGLONG, OBJECTCALCOLOR_IPPOBJID, 1, 1, nDet, ippObjID, &status);
+                fits_write_col(this->fitsOut, TBYTE, OBJECTCALCOLOR_FILTERID, 1, 1, nDet, filterIDs, &status);
+                if (numOfDuplicates||numInvalidFlux) fits_delete_rowlist(this->fitsOut, removeList, numOfDuplicates+numInvalidFlux, &status);
+            }
 
             psLogMsg("ippToPsps", PS_LOG_INFO,
Index: /branches/sc_branches/trunkTest/ippTools/share/Makefile.am
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/share/Makefile.am	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippTools/share/Makefile.am	(revision 29060)
@@ -153,4 +153,5 @@
 	disttool_definebyquery_fake.sql \
 	disttool_definebyquery_raw.sql \
+	disttool_definebyquery_sky.sql \
 	disttool_definebyquery_stack.sql \
 	disttool_definebyquery_warp.sql \
@@ -166,4 +167,5 @@
 	disttool_pending_fake.sql \
 	disttool_pending_raw.sql \
+	disttool_pending_sky.sql \
 	disttool_pending_stack.sql \
 	disttool_pending_warp.sql \
@@ -328,4 +330,7 @@
 	staticskytool_definebyquery_select.sql \
 	staticskytool_definebyquery_inputs.sql \
+	staticskytool_export_run.sql \
+	staticskytool_export_input.sql \
+	staticskytool_export_result.sql \
 	staticskytool_inputs.sql \
 	staticskytool_todo.sql \
Index: /branches/sc_branches/trunkTest/ippTools/share/disttool_definebyquery_sky.sql
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/share/disttool_definebyquery_sky.sql	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippTools/share/disttool_definebyquery_sky.sql	(revision 29060)
@@ -0,0 +1,27 @@
+SELECT DISTINCT
+    'sky' as stage,
+    staticskyRun.sky_id AS stage_id,
+    CAST(0 AS SIGNED) AS magicked,
+    -- run tag in the form 'sky.$skycell_id.$stack_id'
+    CONCAT_WS('.', 'sky', stackRun.skycell_id, convert(staticskyRun.sky_id, CHAR)) as run_tag,
+    staticskyRun.label,
+    staticskyRun.data_group,
+    distTarget.dist_group,
+    distTarget.target_id,
+    distTarget.clean
+FROM staticskyRun
+JOIN staticskyResult USING(sky_id)
+JOIN staticskyInput USING(sky_id)
+JOIN stackRun using(stack_id)
+JOIN distTarget ON distTarget.stage = 'sky'
+    AND staticskyRun.dist_group = distTarget.dist_group
+JOIN rcInterest USING(target_id)
+LEFT JOIN distRun ON (distRun.stage_id = sky_id)
+    AND distRun.target_id = distTarget.target_id
+    -- JOIN hook %s
+WHERE  distTarget.state = 'enabled'
+    AND rcInterest.state = 'enabled'
+    AND distRun.dist_id IS NULL
+    AND ((staticskyRun.state = 'full') OR (distTarget.clean AND staticskyRun.state = 'cleaned'))
+    -- we shouldn't need to check fault. If faulted it shouldn't be full
+    AND (staticskyResult.fault = 0 AND staticskyResult.quality = 0)
Index: /branches/sc_branches/trunkTest/ippTools/share/disttool_pending_sky.sql
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/share/disttool_pending_sky.sql	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippTools/share/disttool_pending_sky.sql	(revision 29060)
@@ -0,0 +1,50 @@
+SELECT DISTINCT
+    distRun.dist_id,
+    distRun.label,
+    distTarget.dist_group,
+    stage,
+    stage_id,
+    stackRun.skycell_id AS component,
+    clean,
+    rawExp.camera,
+    CONCAT_WS('.', outroot, CONVERT(distRun.dist_id, CHAR)) as outdir,
+    staticskyResult.path_base,
+    CAST(NULL AS CHAR(255)) as chip_path_base,
+    staticskyRun.state,
+    staticskyRun.state AS data_state,
+    staticskyResult.quality,
+    1 AS no_magic,
+    0 AS magicked
+FROM distRun
+JOIN distTarget USING(target_id, stage, clean)
+JOIN staticskyRun
+    ON stage_id = sky_id
+JOIN staticskyResult
+    USING(sky_id)
+JOIN staticskyInput
+    USING(sky_id)
+JOIN stackRun 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 = 'sky'
+    AND distComponent.dist_id IS NULL
+    AND (staticskyRun.state = 'full' OR (distRun.clean AND staticskyRun.state = 'cleaned'))
+    AND (staticskyResult.fault = 0 AND staticskyResult.quality = 0)
Index: /branches/sc_branches/trunkTest/ippTools/share/disttool_toadvance.sql
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/share/disttool_toadvance.sql	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippTools/share/disttool_toadvance.sql	(revision 29060)
@@ -240,4 +240,25 @@
         AND distComponent.fault = 0
 UNION
+-- staticsky stage
+-- NOTE this assumes that there is only one component per staticskyRun
+-- (one skycell)
+SELECT
+    distRun.dist_id,
+    stage,
+    stage_id,
+    outroot,
+    label,
+    clean
+    FROM distRun
+    JOIN staticskyResult on stage_id = sky_id
+    LEFT JOIN distComponent
+        ON distRun.dist_id = distComponent.dist_id
+    WHERE
+        distRun.state = 'new'
+        AND distRun.fault = 0
+        AND distRun.stage = 'sky'
+        AND distComponent.component IS NOT NULL
+        AND distComponent.fault = 0
+UNION
 -- SSdiff stage
 SELECT
Index: /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_input.sql
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_input.sql	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_input.sql	(revision 29060)
@@ -0,0 +1,1 @@
+SELECT staticskyInput.* FROM staticskyInput
Index: /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_result.sql
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_result.sql	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_result.sql	(revision 29060)
@@ -0,0 +1,1 @@
+SELECT staticskyResult.* FROM staticskyResult
Index: /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_run.sql
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_run.sql	(revision 29060)
+++ /branches/sc_branches/trunkTest/ippTools/share/staticskytool_export_run.sql	(revision 29060)
@@ -0,0 +1,1 @@
+SELECT staticskyRun.* from staticskyRun
Index: /branches/sc_branches/trunkTest/ippTools/share/staticskytool_result.sql
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/share/staticskytool_result.sql	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippTools/share/staticskytool_result.sql	(revision 29060)
@@ -1,11 +1,12 @@
-SELECT
+SELECT DISTINCT
     staticskyResult.*,
     staticskyRun.state,
-    staticskyRun.tess_id,
-    staticskyRun.skycell_id,
-    staticskyRun.filter,
     staticskyRun.workdir,
     staticskyRun.label,
+    stackRun.tess_id,
+    stackRun.skycell_id,
+    stackRun.filter
 FROM staticskyRun
-JOIN staticskyResult
-USING(stack_id)
+JOIN staticskyResult USING(sky_id)
+JOIN staticskyInput USING(sky_id)
+JOIN stackRun using(stack_id)
Index: /branches/sc_branches/trunkTest/ippTools/src/disttool.c
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/src/disttool.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippTools/src/disttool.c	(revision 29060)
@@ -329,4 +329,21 @@
         // stack stage doesn't require magic
         no_magic = true;
+    } else if (!strcmp(stage, "sky")) {
+        magicRunType = "staticskyRun";
+        query = pxDataGet("disttool_definebyquery_sky.sql");
+        if (!query) {
+            psError(PXTOOLS_ERR_SYS, false, "failed to retreive SQL statement");
+            psFree(where);
+            return false;
+        }
+
+        if (label) {
+            psStringAppend(&query, " AND (staticskyRun.label = '%s')", label);
+        }
+        if (dist_group) {
+            psStringAppend(&query, " AND (sticskyRun.dist_group = '%s')", dist_group);
+        }
+        // (static)sky stage doesn't require magic
+        no_magic = true;
     } else if (!strcmp(stage, "SSdiff")) {
       magicRunType = "diffRun";
Index: /branches/sc_branches/trunkTest/ippTools/src/staticskytool.c
===================================================================
--- /branches/sc_branches/trunkTest/ippTools/src/staticskytool.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippTools/src/staticskytool.c	(revision 29060)
@@ -727,5 +727,4 @@
 bool exportrunMode(pxConfig *config)
 {
-# if (0)
   typedef struct ExportTable {
     char tableName[80];
@@ -737,5 +736,5 @@
   PS_ASSERT_PTR_NON_NULL(config, NULL);
 
-  PXOPT_LOOKUP_S64(det_id, config->args, "-stack_id", true,  false);
+  PXOPT_LOOKUP_S64(det_id, config->args, "-sky_id", true,  false);
   PXOPT_LOOKUP_STR(outfile, config->args, "-outfile", true,  false);
   PXOPT_LOOKUP_BOOL(clean, config->args, "-clean", false);
@@ -753,10 +752,10 @@
   }
   psMetadata *where = psMetadataAlloc();
-  PXOPT_COPY_S64(config->args, where, "-stack_id", "stack_id", "==");
+  PXOPT_COPY_S64(config->args, where, "-sky_id", "sky_id", "==");
 
   ExportTable tables [] = {
-    {"stackRun", "staticskytool_export_run.sql"},
-    {"stackInputSkyfile", "staticskytool_export_input_skyfile.sql"},
-    {"stackSumSkyfile", "staticskytool_export_sum_skyfile.sql"},
+    {"staticskyRun", "staticskytool_export_run.sql"},
+    {"staticskyInput", "staticskytool_export_input.sql"},
+    {"staticskyResult", "staticskytool_export_result.sql"},
   };
 
@@ -800,6 +799,6 @@
 
     if (clean) {
-        if (!strcmp(tables[i].tableName, "stackRun")) {
-            if (!pxSetStateCleaned("stackRun", "state", output)) {
+        if (!strcmp(tables[i].tableName, "staticskyRun")) {
+            if (!pxSetStateCleaned("staticskyRun", "state", output)) {
                 psFree(output);
                 psError(PS_ERR_UNKNOWN, false, "pxSetStateClean failed for table %s",  tables[i].tableName);
@@ -821,5 +820,4 @@
     fclose (f);
 
-# endif
     return true;
 }
Index: /branches/sc_branches/trunkTest/ippconfig/gpc1/ppMerge.config
===================================================================
--- /branches/sc_branches/trunkTest/ippconfig/gpc1/ppMerge.config	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippconfig/gpc1/ppMerge.config	(revision 29060)
@@ -60,4 +60,15 @@
 # END
 
+# DARK.ORDINATES	METADATA
+#  	TEMP	METADATA
+#  		ORDER	S32	1
+# 		RULE	STR	CHIP.TEMP
+#  	END
+#  	TEMP2	METADATA
+#  		ORDER	S32	1
+# 		RULE	STR	CHIP.TEMP * CHIP.TEMP
+#  	END
+# END
+
 # Ordinates for fitting dark current as function of darktime and fpa temp:
 # Counts = C0 + (CT0 + CT1*Temp)*exptime
Index: /branches/sc_branches/trunkTest/ippconfig/recipes/filerules-split.mdc
===================================================================
--- /branches/sc_branches/trunkTest/ippconfig/recipes/filerules-split.mdc	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippconfig/recipes/filerules-split.mdc	(revision 29060)
@@ -209,4 +209,5 @@
 PSPHOT.STACK.OUTPUT.VARIANCE OUTPUT {OUTPUT}.{FILE.ID}.wt.fits        VARIANCE        NONE       FPA        TRUE      NONE
 PSPHOT.STACK.OUTPUT          OUTPUT {OUTPUT}.{FILE.ID}.cmf            CMF             NONE       FPA        TRUE      NONE
+PSPHOT.STACK.CONFIG          OUTPUT {OUTPUT}.psphotStack.mdc          TEXT            NONE       FPA        TRUE      NONE
                                                      
 SOURCE.PLOT.RAW.MOMENTS      OUTPUT {OUTPUT}.{CHIP.NAME}.mnt.png      KAPA            NONE       CHIP       TRUE      NONE
Index: /branches/sc_branches/trunkTest/ippconfig/recipes/fitstypes.mdc
===================================================================
--- /branches/sc_branches/trunkTest/ippconfig/recipes/fitstypes.mdc	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippconfig/recipes/fitstypes.mdc	(revision 29060)
@@ -107,4 +107,6 @@
 	BSCALE		F32	0.1	# Disk is stored as 1/10th sec
 	BZERO		F32	3276.8	# Store unsigned zero as zero
+	# switch to NONE to work around ticket 1411
+	#COMPRESSION	STR	NONE
 	COMPRESSION	STR	GZIP
 	TILE.X		S32	0
Index: /branches/sc_branches/trunkTest/ippconfig/recipes/nightly_science.config
===================================================================
--- /branches/sc_branches/trunkTest/ippconfig/recipes/nightly_science.config	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippconfig/recipes/nightly_science.config	(revision 29060)
@@ -37,4 +37,73 @@
 FILTERS STR z.00000
 FILTERS STR y.00000
+
+UNRECOVERABLE_QUALITY MULTI
+UNRECOVERABLE_QUALITY S16 4007
+
+MACRO_DEFINITIONS MULTI
+#MACRO_DEFINITIONS METADATA
+#  PROC_MODE STR check_chips
+#  MACRO     STR echo survey.del.destreak @LABEL@
+#END
+MACRO_DEFINITIONS METADATA
+  PROC_MODE STR queue_chips
+  MACRO     STR survey.del.destreak @LABEL@
+END
+MACRO_DEFINITIONS METADATA
+  PROC_MODE STR confirm_stacks
+  MACRO     STR survey.add.destreak @LABEL@ /data/ipp053.0/gpc1_destreak
+END
+#MACRO_DEFINITIONS METADATA
+#  PROC_MODE STR check_confirm_stacks
+#  MACRO     STR echo survey.add.destreak @LABEL@ /data/ipp053.0/gpc1_destreak
+#END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR clean_old
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR check_registration
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR define_burntool
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR queue_burntool
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR check_stacks
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR queue_stacks
+#   MACRO     STR
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR check_sweetspot
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR queue_sweetspot
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR check_dqstats
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR queue_dqstats
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR check_detrends
+#   MACRO     STR 
+# END
+# MACRO_DEFINITIONS METADATA
+#   PROC_MODE STR queue_detrends
+#   MACRO     STR 
+# END
 
 TARGETS MULTI
Index: /branches/sc_branches/trunkTest/ippconfig/recipes/ppSim.config
===================================================================
--- /branches/sc_branches/trunkTest/ippconfig/recipes/ppSim.config	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippconfig/recipes/ppSim.config	(revision 29060)
@@ -70,22 +70,23 @@
 
 GALAXY.LUM	  F32	-0.8		# Stellar luminosity function slope
-GALAXY.MAG	  F32	11.0		# Brightest magnitude for fake stars
-GALAXY.DENSITY	  F32	6.0		# Galaxy density (per square degree) at the brightest magnitude
-
-GALAXY.RMAJOR.MIN F32	2.0		# Minimum semi-major axis for galaxy models
+GALAXY.MAG	  F32	15.0		# Brightest magnitude for fake stars
+GALAXY.DENSITY	  F32	5.0		# Galaxy density (per square degree) at the brightest magnitude
+
+GALAXY.RMAJOR.MIN F32	5.0		# Minimum semi-major axis for galaxy models
 GALAXY.RMAJOR.MAX F32	10.0		# Maximum semi-major axis for galaxy models
 
 GALAXY.ARATIO.MIN F32	1.0		# Minimum axis ratio for galaxy models
-GALAXY.ARATIO.MAX F32	0.2		# Maximum axis ratio for galaxy models
+GALAXY.ARATIO.MAX F32	0.5		# Maximum axis ratio for galaxy models
 
 GALAXY.INDEX.MIN F32    0.25		# Minimum Sersic index for galaxy models
-GALAXY.INDEX.MAX F32	0.500           # Maximum Sersic index for galaxy models
+GALAXY.INDEX.MAX F32	1.000           # Maximum Sersic index for galaxy models
 
 GALAXY.THETA.MIN F32    0.0		# Minimum position angle for galaxy models
 GALAXY.THETA.MAX F32	3.14            # Maximum position angle for galaxy models
 
-GALAXY.GRID      BOOL   FALSE		# Generate a (regular) grid of galaxy models?
-GALAXY.GRID.DX   S32    200             # Spacing between galaxies in grid in x
-GALAXY.GRID.DY   S32    200             # Spacing between galaxies in grid in y
+GALAXY.GRID        BOOL   FALSE		# Generate a (regular) grid of galaxy models?
+GALAXY.GRID.DX     S32    100             # Spacing between galaxies in grid in x
+GALAXY.GRID.DY     S32    200             # Spacing between galaxies in grid in y
+GALAXY.GRID.RANDOM BOOL   FALSE		# randomize shape parameters in grid (or sequence?)
 
 GALAXY.MODEL     STR    PS_MODEL_GAUSS
Index: /branches/sc_branches/trunkTest/ippconfig/recipes/ppSub.config
===================================================================
--- /branches/sc_branches/trunkTest/ippconfig/recipes/ppSub.config	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippconfig/recipes/ppSub.config	(revision 29060)
@@ -15,5 +15,5 @@
 SYS.ERR		F32	0.1		# Relative systematic error in images
 SKY.ERR		F32	0.0		# Relative systematic error in images
-NORM.FRAC	F32	0.03		# Fraction of window for normalisation window
+NORM.FRAC	F32	0.01		# Fraction of window for normalisation window
 COVAR.FRAC	F32	0.01		# Fraction of kernel to truncate before calculating covariance
 
@@ -28,4 +28,6 @@
 MASKSTAT.ADVISORY   U32 0x080
 
+INPUT.MATCH.RADIUS F32  20.0
+INPUT.MATCH.MIN.SN F32  10.0
 
 LOW.THRESHOLD	F32	4.0	        # Mask pixels below this threshold (std dev)
@@ -57,5 +59,5 @@
 INNER		S32	5		# Inner half-size for SPAM and FRIES kernels
 RINGS.ORDER	S32	2		# Polynomial order for RINGS kernels
-PENALTY		F32	1.0		# Penalty for wideness
+PENALTY		F32	16.0		# Penalty for wideness
 BIN1		S32	4		# Binning factor for first level
 BIN2		S32	4		# Binning factor for second level
Index: /branches/sc_branches/trunkTest/ippconfig/recipes/psphot.config
===================================================================
--- /branches/sc_branches/trunkTest/ippconfig/recipes/psphot.config	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippconfig/recipes/psphot.config	(revision 29060)
@@ -90,5 +90,15 @@
 
 PSF_FIT_ITER                        S32   50              # Maximum number of fitting iterations for PSF
-PSF_FIT_TOL                         F32   0.01            # Fit tolerance for PSF
+PSF_FIT_MIN_TOL                     F32   0.01            # Fit tolerance for PSF
+PSF_FIT_MAX_TOL                     F32   2.00            # Fit tolerance for PSF
+
+PSF_FIT_MIN_VALID_FLUX              F32  -100000000.0     # minimum allow flux for fitted source
+PSF_FIT_MAX_VALID_FLUX              F32  +100000000.0     # maximum allow flux for fitted source
+
+# the following is used to require a minimum quality of fit before
+# stopping based on the tolerance.  be careful of using this in
+# conjunction with non-poisson errors (POISSON.ERRORS.LMM) or with
+# pooly determined errors
+PSF_FIT_MAX_CHISQ                   F32  20.00            # require chisq / DOF to reach this level before giving up
 
 # PSF model parameters : choose the PSF model
@@ -113,4 +123,5 @@
 PSF.FAKE.ALLOW                      BOOL  FALSE           # Allow use of fake PSFs when having trouble?
 
+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
@@ -138,5 +149,5 @@
  
 # this model is used for approximate subtraction in the main object analysis step
-EXT_MODEL                           STR   PS_MODEL_QGAUSS
+EXT_MODEL                           STR   PS_MODEL_SERSIC
 EXT_FIT_NSIGMA                      F32   1               # significance for pixel included in fit
 EXT_FIT_PADDING                     F32   5               # extra annulus to use for fit 
@@ -145,5 +156,12 @@
 
 EXT_FIT_ITER                        S32   20              # Maximum number of fitting iterations for EXT
-EXT_FIT_TOL                         F32   0.01            # Fit tolerance for EXT
+EXT_FIT_MIN_TOL                     F32   0.01            # Fit tolerance for EXT
+EXT_FIT_MAX_TOL                     F32   2.00            # Fit tolerance for EXT
+
+# the following is used to require a minimum quality of fit before
+# stopping based on the tolerance.  be careful of using this in
+# conjunction with non-poisson errors (POISSON.ERRORS.LMM) or with
+# pooly determined errors
+EXT_FIT_MAX_CHISQ                   F32  20.00            # require chisq / DOF to reach this level before giving up
 
 # extended source aperture-like measurements
@@ -170,5 +188,7 @@
  #PGAUSS_PSF  EXTENDED_SOURCE_MODEL  PS_MODEL_PGAUSS   20.0    TRUE
  #QGAUSS_PSF  EXTENDED_SOURCE_MODEL  PS_MODEL_QGAUSS   20.0    TRUE
- SERSIC_PSF  EXTENDED_SOURCE_MODEL  PS_MODEL_SERSIC   20.0    TRUE
+ EXP_PCM  EXTENDED_SOURCE_MODEL  PS_MODEL_EXP      20.0    TRUE
+ DEV_PCM  EXTENDED_SOURCE_MODEL  PS_MODEL_DEV      20.0    TRUE
+ SER_PCM  EXTENDED_SOURCE_MODEL  PS_MODEL_SERSIC   20.0    TRUE
 END
 
@@ -224,5 +244,5 @@
 PCM_BOX_SIZE                        S32   8
 
-NOISE.FACTOR                        F32   5.0
+NOISE.FACTOR                        F32  10.0
 NOISE.SIZE                          F32   2.0
 
@@ -307,10 +327,9 @@
 # Extended source fit parameters
 STACKPHOT                             METADATA
+  EXTENDED_SOURCE_FITS                BOOL  TRUE  # perform any of the aperture-like measurements?
   EXTENDED_SOURCE_ANALYSIS            BOOL  TRUE  # perform any of the aperture-like measurements?
   EXTENDED_SOURCE_SN_LIM              F32   20.0
   EXTENDED_SOURCE_PETROSIAN           BOOL  TRUE
-  EXTENDED_SOURCE_ISOPHOTAL           BOOL  FALSE
   EXTENDED_SOURCE_ANNULI              BOOL  TRUE
-  EXTENDED_SOURCE_KRON                BOOL  FALSE
   PSPHOT.STACK.MATCH.PSF.SOURCE       STR   AUTO # which inputs to convolve? (RAW, CNV, AUTO)
   PSPHOT.STACK.TARGET.PSF.AUTO        BOOL  F    # automatically determine target PSF size?
@@ -319,4 +338,8 @@
   RADIAL_APERTURES_SN_LIM             F32   0.0  # S/N limit for radial aperture calculation
   OUTPUT.FORMAT                       STR   PS1_SV1
+
+  EXT_FIT_MAX_RADIUS                  F32   50.0
+  PSF_MODEL                           STR   PS_MODEL_GAUSS 
+  EXT_MODEL                           STR   PS_MODEL_SERSIC
 END
 
@@ -343,5 +366,4 @@
   DIFF_STATS			    BOOL TRUE	       # Calculate diff-specific stats
   OUTPUT.FORMAT		            STR  PS1_DV1       # Format of output file
-
 END
 
Index: /branches/sc_branches/trunkTest/ippconfig/simtest/format.config
===================================================================
--- /branches/sc_branches/trunkTest/ippconfig/simtest/format.config	(revision 29059)
+++ /branches/sc_branches/trunkTest/ippconfig/simtest/format.config	(revision 29060)
@@ -69,6 +69,6 @@
 	CELL.X0		S32	0
 	CELL.Y0		S32	0
-	CELL.XSIZE	S32	1024
-	CELL.YSIZE	S32	1024
+	CELL.XSIZE	S32	1000
+	CELL.YSIZE	S32	1000
 	CELL.XWINDOW	S32	0
 	CELL.YWINDOW	S32	0
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimArguments.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimArguments.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimArguments.c	(revision 29060)
@@ -55,4 +55,6 @@
     psMetadataAddStr(arguments,  PS_LIST_TAIL, "-galmodel", 0, "Type of Galaxy model", NULL);
     psMetadataAddS32(arguments,  PS_LIST_TAIL, "-bin", 0, "Binning in x and y", 1);
+    psMetadataAddS32(arguments,  PS_LIST_TAIL, "-nx", 0, "cell x-size in pixels", 0);
+    psMetadataAddS32(arguments,  PS_LIST_TAIL, "-ny", 0, "cell y-size in pixels", 0);
     psMetadataAddBool(arguments, PS_LIST_TAIL, "+photom", 0, "Perform photometry on fake sources", false);
 
@@ -197,4 +199,7 @@
     ppSimArgToRecipeS32(&status,  options, "BINNING",       arguments, "-bin");
 
+    ppSimArgToRecipeS32(&status,  config->arguments, "NX.CELL", arguments, "-nx");
+    ppSimArgToRecipeS32(&status,  config->arguments, "NY.CELL", arguments, "-ny");
+
     if (type == PPSIM_TYPE_OBJECT) {
         // Load values required for adding stars
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimCreate.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimCreate.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimCreate.c	(revision 29060)
@@ -26,6 +26,22 @@
     }
 
+    assert (config->camera);
+
+    // int nx = psMetadataLookupS32 (&status, config->arguments, "NX.CELL");
+    // if (nx) {
+    //   psMetadata *defaults = psMetadataLookupPtr(&status, config->camera, "DEFAULTS");
+    //   psMetadataLookupS32 (&status, defaults, "CELL.XSIZE");
+    //   psAssert (status, "CELL.XSIZE should be in DEFAULTS");
+    //   psMetadataAddF32(defaults, PS_LIST_TAIL, "CELL.XSIZE", PS_META_REPLACE, "", nx);
+    // }
+    // int ny = psMetadataLookupS32 (&status, config->arguments, "NY.CELL");
+    // if (ny) {
+    //   psMetadata *defaults = psMetadataLookupPtr(&status, config->camera, "DEFAULTS");
+    //   psMetadataLookupS32 (&status, defaults, "CELL.YSIZE");
+    //   psAssert (status, "CELL.YSIZE should be in DEFAULTS");
+    //   psMetadataAddF32(defaults, PS_LIST_TAIL, "CELL.YSIZE", PS_META_REPLACE, "", ny);
+    // }
+
     // generate the fpa structure used by the output camera (determined from INPUT or specified)
-    assert (config->camera);
     fpa = pmFPAConstruct(config->camera, config->cameraName); // FPA to contain the observation
     if (!fpa) {
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimInsertGalaxies.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimInsertGalaxies.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimInsertGalaxies.c	(revision 29060)
@@ -1,4 +1,14 @@
 # include "ppSim.h"
 static char *defaultModel = "PS_MODEL_SERSIC";
+
+float imageSum (psImage *image) {
+    float sum = 0.0;
+    for (int iy = 0; iy < image->numRows; iy++) {
+	for (int ix = 0; ix < image->numCols; ix++) {
+	    sum += image->data.F32[iy][ix];
+	}
+    }
+    return sum;
+}
 
 bool ppSimInsertGalaxies (pmReadout *readout, psImage *expCorr, psArray *galaxies, pmConfig *config) {
@@ -84,4 +94,11 @@
     psArray *sources = sources = detections->allSources;
 
+    // output filename
+    char outname[1024];
+    char *outroot = psMetadataLookupStr(&mdok, config->arguments, "OUTPUT");
+    sprintf (outname, "%s.dat", outroot);
+
+    FILE *outfile = fopen (outname, "a");
+
     // add sources to the readout image & weight
     for (long i = 0; i < galaxies->n; i++) {
@@ -131,11 +148,13 @@
 
 	// XXX let the flux limit be a user-defined number of sky sigmas (not just 1.0)
-	float radius = model->modelRadius (model->params, roughNoise);
+	float radius = model->modelRadius (model->params, 0.1*roughNoise);
 	radius = PS_MAX (radius, 1.0);
 	// XXX the exp(-r^0.25) models can go way out if allowed...
-	radius = PS_MIN (radius, 150.0); 
+	radius = PS_MIN (radius, 300.0); 
 
 	// construct a source, with model flux pixels set, based on the model
 	pmSource *source = pmSourceFromModel (model, readout, radius, PM_SOURCE_TYPE_EXTENDED);
+
+	galaxy->flux = model->modelFlux (model->params);
 
 	// XXX set the mag & err values (should this be done in pmSourceFromModel?)
@@ -145,44 +164,18 @@
 	source->errMag = sqrt(Area*PS_SQR(roughNoise) + galaxy->flux) / galaxy->flux;	
 	
-	// XXX add the sources to a source array
+	// insert the source flux in the image
+	float sum1 = imageSum(source->pixels);
+	pmSourceAddWithOffset (source, PM_MODEL_OP_FULL, 0xff, dX, dY);
+	float sum2 = imageSum(source->pixels);
+	float flux = sum2 - sum1;
 
-# if (0)	
-	if (CONVOLVED_FIT) {
+	// fprintf (stderr, "flux: %f, sum1: %f, sum2: %f, flux2: %f, dflux: %f\n", galaxy->flux, sum1, sum2, sum2 - sum1, galaxy->flux - sum2 + sum1);
 
-	    // select the PSF (XXX : move out of loop)
-	    pmPSF *psfModel = psMetadataLookupPtr (&mdok, chip->analysis, "PSPHOT.PSF");
-	    assert (psf);
-	    
-	    // supply the psf to the source (normalized?)
-	    source->modelPSF = pmModelFromPSFforXY (psfModel, xChip, yChip, 1.0);
+	float par8 = (model->params->n == 8) ? model->params->data.F32[7] : 0.0;
+	fprintf (outfile, "%8.3f %8.3f %10.2f  %2d  %7.3f %5.3f  %5.3f %5.3f %5.3f %5.3f\n", galaxy->x, galaxy->y, flux, 1, source->psfMag, source->errMag, axes.major, axes.minor, axes.theta, par8);
 
-	    // instantiate the psf flux
-	    pmSourceCachePSF (source, maskVal);
-
-	    // convert the cached cached psf model for this source to a psKernel
-	    // XXX for the moment, hard-wire the kernel to be 5x5 (2 pix radius)
-	    // XXX for the moment, hard-wire the kernel to be 9x9 (4 pix radius)
-	    psKernel *psf = psphotKernelFromPSF (source, psfSize);
-
-	    // instantiate the source model flux
-	    // XXX this may need to handle the offset?
-	    pmSourceCacheModel (source, maskVal);
-
-	    // make a storage buffer for the output image
-	    psImage *buffer = psImageCopy (source->modelFlux, PS_TYPE_F32);
-
-	    // convolve the psf image with the model image
-	    psImageConvolveDirect (buffer, source->modelFlux, psf);
-
-	    // save the result back in the source
-	    psFree (source->modelFlux);
-	    source->modelFlux = buffer;
-	}
-# endif
-
-	// insert the source flux in the image
-	pmSourceAddWithOffset (source, PM_MODEL_OP_FULL, 0xff, dX, dY);
 	psArrayAdd (sources, 100,source);
     }
+    fclose (outfile);
 
     // XXX many leaks in here, i think 
@@ -191,3 +184,2 @@
     return true;
 }
-
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimInsertStars.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimInsertStars.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimInsertStars.c	(revision 29060)
@@ -105,11 +105,4 @@
         float flux = star->flux * expCorr->data.F32[(int)yCell][(int)xCell];
 
-	// if psfConvolve is TRUE, we will (elsewhere) convolve the image we a PSF
-	// in this case, simply place delta functions in the image
-	if (psfConvolve) {
-	    readout->image->data.F32[(int)(yCell)][(int)(xCell)] += flux;
-	    continue;
-	}
-
 	// instantiate a model for the PSF at this location, set desired flux
 	pmModel *model = pmModelFromPSFforXY (psf, xChip, yChip, 1.0);
@@ -125,26 +118,35 @@
 	// XXX i should be applying the gain and the correct effective area
 	psEllipseAxes axes = pmPSF_ModelToAxes (model->params->data.F32, 20.0);
-	psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
+	float Area = 2.0 * M_PI * axes.major * axes.minor;
 
-	// this value is the pure (input) flux, and is saved in the output source cmf files
 	source->psfMag = -2.5*log10(star->flux);
 	source->errMag = sqrt(Area*PS_SQR(roughNoise) + flux) / flux;
+	
+	// set the expected model errors
+	model->dparams->data.F32[PM_PAR_I0] = source->errMag * model->params->data.F32[PM_PAR_I0];
 
-	fprintf (outfile, "%8.3f %8.3f  %10.2f  %7.3f %5.3f\n", star->x, star->y, star->flux, source->psfMag, source->errMag);
+	float par8 = (model->params->n == 8) ? model->params->data.F32[7] : 0.0;
+	fprintf (outfile, "%8.3f %8.3f %10.2f  %2d  %7.3f %5.3f  %5.3f %5.3f %5.3f %5.3f\n", star->x, star->y, star->flux, 0, source->psfMag, source->errMag, axes.major, axes.minor, axes.theta, par8);
 
-	// insert the source flux in the image
-	pmSourceAddWithOffset (source, PM_MODEL_OP_FULL, 0xff, dX, dY);
-
-	// insert the source flux in the noise image
-	pmSourceAddWithOffset (source, PM_MODEL_OP_FULL | PM_MODEL_OP_NOISE, 0xff, dX, dY);
-
-	// Blow away the image parts of the source, which makes the memory explode
-	RESET(source->pixels);
-	RESET(source->variance);
-	RESET(source->maskObj);
-	RESET(source->maskView);
-	RESET(source->modelFlux);
-	RESET(source->psfImage);
-	RESET(source->blends);
+	// if psfConvolve is TRUE, we will (elsewhere) convolve the image we a PSF
+	// in this case, simply place delta functions in the image
+	if (psfConvolve) {
+	    readout->image->data.F32[(int)(yCell)][(int)(xCell)] += flux;
+	} else {
+	    // insert the source flux in the image
+	    pmSourceAddWithOffset (source, PM_MODEL_OP_FULL, 0xff, dX, dY);
+	    
+	    // insert the source flux in the noise image
+	    pmSourceAddWithOffset (source, PM_MODEL_OP_FULL | PM_MODEL_OP_NOISE, 0xff, dX, dY);
+	    
+	    // Blow away the image parts of the source, which makes the memory explode
+	    RESET(source->pixels);
+	    RESET(source->variance);
+	    RESET(source->maskObj);
+	    RESET(source->maskView);
+	    RESET(source->modelFlux);
+	    RESET(source->psfImage);
+	    RESET(source->blends);
+	}
 
 	// add the sources to the source array
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimMakeGalaxies.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimMakeGalaxies.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimMakeGalaxies.c	(revision 29060)
@@ -18,4 +18,5 @@
     int galaxyGridDX 	  = psMetadataLookupS32(&mdok, recipe, "GALAXY.GRID.DX"); // Density of fakes
     int galaxyGridDY 	  = psMetadataLookupS32(&mdok, recipe, "GALAXY.GRID.DY"); // Density of fakes
+    bool galaxyGridRandom = psMetadataLookupBool(&mdok, recipe, "GALAXY.GRID.RANDOM"); // Density of fakes
     
     float galaxyRmajorMax = psMetadataLookupF32(&mdok, recipe, "GALAXY.RMAJOR.MAX"); // Density of fakes
@@ -43,4 +44,11 @@
 
     if (galaxyDensity <= 0) return true;
+
+    if (galaxyGridRandom) {
+	long A, B;
+	A = time(NULL);
+	for (B = 0; A == time(NULL); B++);
+	srand48(B);
+    }
 
     // Size of FPA
@@ -81,8 +89,8 @@
 	psLogMsg("ppSim", PS_LOG_INFO, "Adding grid of %ld galaxies\n", num);
 
-	float galaxyIndexSlope = (galaxyIndexMax - galaxyIndexMin) / num;
-	float galaxyThetaSlope = (galaxyThetaMax - galaxyThetaMin) / num;
-	float galaxyARatioSlope = (galaxyARatioMax - galaxyARatioMin) / num;
-	float galaxyRmajorSlope = (galaxyRmajorMax - galaxyRmajorMin) / num;
+	float galaxyIndexSlope = (galaxyIndexMax - galaxyIndexMin);
+	float galaxyThetaSlope = (galaxyThetaMax - galaxyThetaMin);
+	float galaxyARatioSlope = (galaxyARatioMax - galaxyARatioMin);
+	float galaxyRmajorSlope = (galaxyRmajorMax - galaxyRmajorMin);
 
 	int i = 0;
@@ -96,10 +104,36 @@
 		galaxy->y    = iy;
 
-		galaxy->peak = 20000;
+		galaxy->peak = 1000;
 
-		galaxy->index = (galaxyIndexMin  + i * galaxyIndexSlope);
-		galaxy->Rmaj  = (galaxyRmajorMin + i * galaxyRmajorSlope);
-		galaxy->Rmin  = (galaxyARatioMin + i * galaxyARatioSlope) * galaxy->Rmaj;
-		galaxy->theta = (galaxyThetaMin  + i * galaxyThetaSlope);
+		// galaxyIndex from user should be for function of this form: exp(-r^(1/n))
+		// galaxy->index = (1/2n)
+
+		float rndValue;
+
+		rndValue = galaxyGridRandom ? drand48() : i / num;
+		float index = (galaxyIndexMin  + rndValue * galaxyIndexSlope);
+		galaxy->index = 0.5/index; // factor of 0.5 because the Sersic model creates exp(-z^n), not exp(-r^n)
+
+		rndValue = galaxyGridRandom ? drand48() : i / num;
+		float scale = (galaxyRmajorMin + rndValue * galaxyRmajorSlope);
+
+		// for a sersic model, 
+                float bn = 1.9992*index - 0.3271;
+                float fR = 1.0 / (sqrt(2.0) * pow (bn, index));
+                float Io = exp(bn);
+
+		galaxy->Rmaj  = scale;
+
+		rndValue = galaxyGridRandom ? drand48() : i / num;
+		galaxy->Rmin  = (galaxyARatioMin + rndValue * galaxyARatioSlope) * galaxy->Rmaj;
+
+		rndValue = galaxyGridRandom ? drand48() : i / num;
+		galaxy->theta = (galaxyThetaMin  + rndValue * galaxyThetaSlope);
+
+		// galaxy->peak *= Io;
+
+		if (0) {
+		    fprintf (stderr, "Rmaj: %f, scale: %f, index: %f, bn: %f, Ro: %f, Io: %f\n", galaxy->Rmaj, scale, index, bn, fR, Io);
+		}
 
 		psArrayAdd (galaxies, 100, galaxy);
@@ -124,14 +158,28 @@
 	    galaxy->y    = psRandomUniform(rng) * ySize; // y position
 
-	    galaxy->flux = pow ((double)((i + 1) / norm), (double) (1.0 / galaxyLum));
+	    float index = (sqrt(psRandomUniform(rng)) * galaxyIndexSlope  + galaxyIndexMin);
+	    galaxy->index = 0.5/index; // factor of 0.5 because the Sersic model creates exp(-z^n), not exp(-r^n)
 
-	    galaxy->index = (psRandomUniform(rng) * galaxyIndexSlope  + galaxyIndexMin);
+	    float scale = (psRandomUniform(rng) * galaxyRmajorSlope + galaxyRmajorMin);
+
+	    // for a sersic model, 
+	    float bn = 1.9992*index - 0.3271;
+	    float fR = 1.0 / (sqrt(2.0) * pow (bn, index));
+	    float Io = exp(bn);
+
+	    galaxy->Rmaj  = scale;
+
+	    galaxy->Rmin  = (PS_SQR(psRandomUniform(rng)) * galaxyARatioSlope + galaxyARatioMin) * galaxy->Rmaj;
+
 	    galaxy->theta = (psRandomUniform(rng) * galaxyThetaSlope  + galaxyThetaMin);
-	    galaxy->Rmaj  = (psRandomUniform(rng) * galaxyRmajorSlope + galaxyRmajorMin);
-	    galaxy->Rmin  = (psRandomUniform(rng) * galaxyARatioSlope + galaxyARatioMin) * galaxy->Rmaj;
 
+	    // the flux is only approximately correct (scaling of the peak is wrong)
+	    // elsewhere (ppSimInsertGalaxies.c) we calculate the true galaxy flux
 	    galaxy->flux = expf((logf(i + 1) - logf(norm)) / galaxyLum); // Peak flux
 	    galaxy->peak = galaxy->flux / (2.0*M_PI*PS_SQR(seeing));
-	    // galaxy->peak = 5000;
+
+	    if (0) {
+	      fprintf (stderr, "Rmaj: %f, scale: %f, index: %f, bn: %f, Ro: %f, Io: %f\n", galaxy->Rmaj, scale, index, bn, fR, Io);
+	    }
 
 	    psArrayAdd (galaxies, 100, galaxy);
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadout.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadout.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadout.c	(revision 29060)
@@ -69,5 +69,5 @@
     psArray *fakeSources = psArrayAlloc (injectedSources->n);
     for (int i = 0; i < injectedSources->n; i++) {
-      fakeSources->data[i] = pmSourceCopy (injectedSources->data[i]);
+      fakeSources->data[i] = pmSourceCopyData (injectedSources->data[i]);
     }
 
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadoutFake.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadoutFake.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadoutFake.c	(revision 29060)
@@ -40,5 +40,5 @@
     psArray *fakeSources = psArrayAlloc (injectedSources->n);
     for (int i = 0; i < injectedSources->n; i++) {
-      fakeSources->data[i] = pmSourceCopy (injectedSources->data[i]);
+      fakeSources->data[i] = pmSourceCopyData (injectedSources->data[i]);
     }
 
@@ -47,5 +47,5 @@
     psArray *realSources = psArrayAlloc (realMeasuredSources->n);
     for (int i = 0; i < realMeasuredSources->n; i++) {
-        realSources->data[i] = pmSourceCopy (realMeasuredSources->data[i]);
+        realSources->data[i] = pmSourceCopyData (realMeasuredSources->data[i]);
     }
 
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadoutForce.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadoutForce.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimPhotomReadoutForce.c	(revision 29060)
@@ -46,5 +46,5 @@
     psArray *realSources = psArrayAlloc (realMeasuredSources->n);
     for (int i = 0; i < realMeasuredSources->n; i++) {
-        realSources->data[i] = pmSourceCopy (realMeasuredSources->data[i]);
+        realSources->data[i] = pmSourceCopyData (realMeasuredSources->data[i]);
     }
 
Index: /branches/sc_branches/trunkTest/ppSim/src/ppSimSmoothReadout.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSim/src/ppSimSmoothReadout.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSim/src/ppSimSmoothReadout.c	(revision 29060)
@@ -7,5 +7,5 @@
     // XXX use these defaults?
     // float minGauss = 0.1;
-    float nSigma = 3.0;
+    float nSigma = 4.0;
     float sigma = psMetadataLookupF32(&status, recipe, "SEEING"); // Seeing SIGMA (pixels)
 
@@ -28,2 +28,6 @@
 // 4*pi*SIGMA_SMTH^2, but for measurements based on apertures comparable to or larger than the
 // smoothing kernel, the effective per-pixel variance is maintained.
+
+
+// XXX this only allows for Gaussian PSFs.  To extend this, we need to convolve with an image
+// of the PSF model
Index: /branches/sc_branches/trunkTest/ppSub/src/Makefile.am
===================================================================
--- /branches/sc_branches/trunkTest/ppSub/src/Makefile.am	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSub/src/Makefile.am	(revision 29060)
@@ -39,4 +39,5 @@
 	ppSubDefineOutput.c		\
 	ppSubExtras.c			\
+	ppSubFlagNeighbors.c		\
 	ppSubMakePSF.c			\
 	ppSubMatchPSFs.c		\
Index: /branches/sc_branches/trunkTest/ppSub/src/ppSub.h
===================================================================
--- /branches/sc_branches/trunkTest/ppSub/src/ppSub.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSub/src/ppSub.h	(revision 29060)
@@ -175,4 +175,8 @@
     );
 
+bool ppSubFlagNeighbors(pmConfig *config, pmFPAview *view, psArray *sources, bool matchRef);
+bool ppSubMatchSources (psArray *objects, psArray *sources, float RADIUS, float MIN_SN);
+bool ppSubSetSourceImageIDs (psArray *sources, int imageID);
+
 ///@}
 #endif
Index: /branches/sc_branches/trunkTest/ppSub/src/ppSubBackground.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSub/src/ppSubBackground.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSub/src/ppSubBackground.c	(revision 29060)
@@ -67,15 +67,17 @@
     for (int y = 0; y < numRows; y++) {
         for (int x = 0; x < numCols; x++) {
+	    // special case 1: NAN the masked pixels
             if (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskBad) {
-                image->data.F32[y][x] = 0.0;
-            } else {
-                float value = psImageUnbinPixel(x + 0.5, y + 0.5, modelImage, binning); // Background value
-                if (!isfinite(value)) {
-                    image->data.F32[y][x] = NAN;
-                    mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= maskBad;
-                } else {
-                    image->data.F32[y][x] -= value;
-                }
-            }
+                image->data.F32[y][x] = NAN;
+		continue;
+            } 
+	    // special case 1: NAN & mask pixels without a valid background model
+	    float value = psImageUnbinPixel(x + 0.5, y + 0.5, modelImage, binning); // Background value
+	    if (!isfinite(value)) {
+	      image->data.F32[y][x] = NAN;
+	      mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= maskBad;
+	      continue;
+	    } 
+	    image->data.F32[y][x] -= value;
         }
     }
Index: /branches/sc_branches/trunkTest/ppSub/src/ppSubFlagNeighbors.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSub/src/ppSubFlagNeighbors.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/ppSub/src/ppSubFlagNeighbors.c	(revision 29060)
@@ -0,0 +1,256 @@
+/** @file ppSubFlagNeighbors.c
+ *
+ *  @ingroup ppSub
+ *  @author EAM, IfA
+ *  @date $Date: 2009-02-18 00:31:20 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <psphot.h>
+
+#include "ppSub.h"
+
+// match the diff sources to the detections from the positive or negative input images
+// matchRef : false if this is the standard diff image, true if this is the inverse (in-ref vs ref-in)
+// this is needed to choose which value is positive and which is negative relative to the difference
+bool ppSubFlagNeighbors(pmConfig *config, pmFPAview *view, psArray *sources, bool matchRef) {
+
+    bool status;
+
+    psAssert(config, "Require config");
+    psAssert(view, "Require config");
+    psAssert (sources, "missing sources?");
+
+    // Look up recipe values
+    psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, PPSUB_RECIPE); // should this be psphot?
+    psAssert(recipe, "We checked this earlier, so it should be here.");
+
+    float radius = psMetadataLookupF32(&status, recipe, "INPUT.MATCH.RADIUS");
+    psAssert (status, "cannot find INPUT.MATCH.RADIUS");
+
+    float minSN  = psMetadataLookupF32(&status, recipe, "INPUT.MATCH.MIN.SN");
+    psAssert (status, "cannot find INPUT.MATCH.MIN.SN");
+
+    // Input sources
+    pmReadout *inSourceRO = pmFPAfileThisReadout(config->files, view, "PPSUB.INPUT.SOURCES");
+    pmDetections *inDetections = inSourceRO ? psMetadataLookupPtr(NULL, inSourceRO->analysis, "PSPHOT.DETECTIONS") : NULL; // Input sources
+    if (!inDetections) {
+        psWarning("Unable to filter detections based on image A.");
+    }
+
+    pmReadout *refSourceRO = pmFPAfileThisReadout(config->files, view, "PPSUB.REF.SOURCES");
+    pmDetections *refDetections = refSourceRO ? psMetadataLookupPtr(NULL, refSourceRO->analysis, "PSPHOT.DETECTIONS") : NULL; // Ref sources
+    if (!refDetections) {
+        psWarning("Unable to filter detections based on image B.");
+    }
+    if (!inDetections && !refDetections) {
+	return true;
+    }
+
+    psArray *inSources = inDetections->allSources;
+    psAssert (inSources, "missing inSources?");
+
+    psArray *refSources = refDetections->allSources;
+    psAssert (refSources, "missing refSources?");
+
+    ppSubSetSourceImageIDs(sources, 0);
+    ppSubSetSourceImageIDs(inSources, 1);
+    ppSubSetSourceImageIDs(refSources, 2);
+
+    // define the objects from the diff sources (1-to-1)
+    psArray *objects = psArrayAllocEmpty(sources->n);
+    for (int i = 0; i < sources->n; i++) {
+        pmSource *src = sources->data[i]; 
+	pmPhotObj *obj = pmPhotObjAlloc();
+	pmPhotObjAddSource(obj, src);
+	psArrayAdd (objects, 100, obj);
+	psFree (obj);
+    }
+
+    // Match the sources to both inSources and refSources.  We want to find the closest source
+    // in the positive source lists to each source in the diff source list.
+    // XXX we need to either (a) apply S/N and other filters before we pass the in/ref sources
+    // to this function, or (b) add those filters in the function
+    ppSubMatchSources (objects, inSources, radius, minSN);
+    ppSubMatchSources (objects, refSources, radius, minSN);
+    
+    // now mark or flag the sources with matches that meet some criterion
+    for (int i = 0; i < objects->n; i++) {
+        pmPhotObj *obj = objects->data[i]; 
+
+	// the first entry should be from image 0 (the diff image).
+	// we should have only 1 of 4 possible results:
+	// a) only one entry -- the diff source (no positive matches)
+	// b) 2 matches -- diff and a source from image 1 
+	// c) 2 matches -- diff and a source from image 2
+	// d) 3 matches -- diff and a source from image 1 & 2
+
+	switch (obj->sources->n) {
+	  case 1: {
+	      pmSource *source = obj->sources->data[0];
+	      psAssert (source->imageID == 0, "error in pmPhotObj construction: first entry is not image ID 0");
+	      break;
+	  }
+	  case 2: {
+	      pmSource *source = obj->sources->data[0];
+	      psAssert (source->imageID == 0, "error in pmPhotObj construction: first entry not 0 (case 2)");
+
+	      pmSource *sourceM1 = obj->sources->data[1];
+	      psAssert ((sourceM1->imageID == 1) || (sourceM1->imageID == 2), "error in pmPhotObj construction (second entry is not from 1 or 2");
+
+	      // only one match.  set a flag?
+	      source->mode2 |= PM_SOURCE_MODE2_DIFF_WITH_SINGLE;
+	      if (source->diffStats) {
+		  // which is match need an xor here...
+		  bool positive = !matchRef && (sourceM1->imageID == 1);
+		  positive |= matchRef && (sourceM1->imageID == 2);
+		  float SN1 = isfinite(sourceM1->errMag) ? 1.0 / sourceM1->errMag : NAN;
+		  if (positive) {
+		      source->diffStats->SNp = SN1;
+		      source->diffStats->Rp  = hypot(source->peak->xf - sourceM1->peak->xf, source->peak->yf - sourceM1->peak->yf);
+		  } else {
+		      source->diffStats->SNm = SN1;
+		      source->diffStats->Rm  = hypot(source->peak->xf - sourceM1->peak->xf, source->peak->yf - sourceM1->peak->yf);
+		  }
+	      }
+	      break;
+	  }
+	  case 3: {
+	      pmSource *source = obj->sources->data[0];
+	      psAssert (source->imageID == 0, "error in pmPhotObj construction: first entry not 0 (case 3)");
+
+	      pmSource *sourceM1 = obj->sources->data[1];
+	      pmSource *sourceM2 = obj->sources->data[2];
+	      psAssert ((sourceM1->imageID == 1) || (sourceM1->imageID == 2), "error in pmPhotObj construction (case 3.1)");
+	      psAssert ((sourceM2->imageID == 1) || (sourceM2->imageID == 2), "error in pmPhotObj construction (case 3.2)");
+	      psAssert (sourceM1->imageID != sourceM2->imageID, "error in pmPhotObj construction (case 3.3)");
+
+	      source->mode2 |= PM_SOURCE_MODE2_DIFF_WITH_DOUBLE;
+	      if (source->diffStats) {
+		  // which is match need an xor here...
+		  bool positive = !matchRef && (sourceM1->imageID == 1);
+		  positive |= matchRef && (sourceM1->imageID == 2);
+		  float SN1 = isfinite(sourceM1->errMag) ? 1.0 / sourceM1->errMag : NAN;
+		  float SN2 = isfinite(sourceM2->errMag) ? 1.0 / sourceM2->errMag : NAN;
+		  if (positive) {
+		      source->diffStats->SNp = SN1;
+		      source->diffStats->Rp  = hypot(source->peak->xf - sourceM1->peak->xf, source->peak->yf - sourceM1->peak->yf);
+		      source->diffStats->SNm = SN2;
+		      source->diffStats->Rm  = hypot(source->peak->xf - sourceM2->peak->xf, source->peak->yf - sourceM2->peak->yf);
+		  } else {
+		      source->diffStats->SNp = SN2;
+		      source->diffStats->Rp  = hypot(source->peak->xf - sourceM2->peak->xf, source->peak->yf - sourceM2->peak->yf);
+		      source->diffStats->SNm = SN1;
+		      source->diffStats->Rm  = hypot(source->peak->xf - sourceM1->peak->xf, source->peak->yf - sourceM1->peak->yf);
+		  }
+	      }
+	      break;
+	  }
+	  default:
+	    psAbort ("error in pmPhotObj construction (unexpected matches)");
+	}
+    }
+    psFree (objects);
+    return true;
+}
+
+// XXX based on psphotMatchSourcesToObjects
+# define NEXT1 { i++; continue; } 
+# define NEXT2 { j++; continue; } 
+bool ppSubMatchSources (psArray *objects, psArray *sources, float RADIUS, float MIN_SN) { 
+ 
+    float dx, dy; 
+ 
+    float RADIUS2 = RADIUS*RADIUS;
+
+    // sort the source list by X 
+    sources = psArraySort (sources, pmSourceSortByX); 
+    objects = psArraySort (objects, pmPhotObjSortByX); 
+ 
+    // match sources to existing objects
+
+    psLogMsg ("psphot", PS_LOG_DETAIL, "attempt to match sources (%ld vs %ld) (SN > %f)", sources->n, objects->n, MIN_SN);
+
+    int nMatch = 0;
+    int i = 0;
+    int j = 0;
+    for (i = j = 0; (i < sources->n) && (j < objects->n); ) { 
+ 
+        pmSource  *src = sources->data[i]; 
+        pmPhotObj *obj = objects->data[j]; 
+ 
+        if (!src) NEXT1; 
+        if (!src->peak) NEXT1; 
+        if (!finite(src->peak->xf)) NEXT1; 
+        if (!finite(src->peak->yf)) NEXT1; 
+        if (!finite(src->peak->SN)) NEXT1; 
+        if (src->peak->SN < MIN_SN) NEXT1; 
+ 
+        if (!obj) NEXT2; 
+        if (!finite(obj->x)) NEXT2; 
+        if (!finite(obj->y)) NEXT2; 
+ 
+        dx = src->peak->xf - obj->x; 
+        if (dx < -1.02*RADIUS) NEXT1; 
+        if (dx > +1.02*RADIUS) NEXT2; 
+ 
+        // we are within match range, look for closest match to object j
+	int Imin = -1;
+	float Rmin = RADIUS2;
+        for (int I = i; (dx < +1.02*RADIUS) && (I < sources->n); I++) { 
+ 
+	    src = sources->data[I]; 
+	    
+	    if (!src) NEXT1; 
+	    if (!src->peak) NEXT1; 
+	    if (!finite(src->peak->xf)) NEXT1; 
+	    if (!finite(src->peak->yf)) NEXT1; 
+	    if (!finite(src->peak->SN)) NEXT1; 
+	    if (src->peak->SN < MIN_SN) NEXT1; 
+
+	    dx = src->peak->xf - obj->x; 
+            dy = src->peak->yf - obj->y; 
+ 
+            float dr = dx*dx + dy*dy; 
+            if (dr > RADIUS2) continue; 
+	    if (dr > Rmin) continue;
+	    Rmin = dr;
+	    Imin  = I;
+	    // fprintf (stderr, "j: %d, I: %d, Imin: %d, dr: %f, dx: %f, dy: %f\n", j, I, Imin, dr, dx, dy);
+	}
+
+	// no match, try next object
+	if (Imin == -1) {
+	    // fprintf (stderr, "*** missed j: %d, Imin: %d, obj x,y: %f, %f\n", j, Imin, obj->x, obj->y);
+	    j++;
+	    continue;
+	}
+	src = sources->data[Imin]; 
+
+	fprintf (stderr, "j: %d, Imin: %d, obj x,y: %f, %f  src x,y: %f, %f, SN: %f, ID: %d\n", j, Imin, obj->x, obj->y, src->peak->xf, src->peak->yf, src->peak->SN, src->id);
+
+	// add source to object
+	pmPhotObjAddSource (obj, src);
+	nMatch ++;
+        j++; 
+    } 
+
+    psLogMsg ("psphot", PS_LOG_DETAIL, "matched sources (%d matches)", nMatch);
+    return true;
+} 
+
+bool ppSubSetSourceImageIDs (psArray *sources, int imageID) {
+
+    for (int i = 0; i < sources->n; i++) {
+	pmSource *source = sources->data[i];
+	source->imageID = imageID;
+    }
+    return true;
+}
Index: /branches/sc_branches/trunkTest/ppSub/src/ppSubLoop.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSub/src/ppSubLoop.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSub/src/ppSubLoop.c	(revision 29060)
@@ -17,6 +17,16 @@
 #include <pslib.h>
 #include <psmodules.h>
+#include <psphot.h>
 
 #include "ppSub.h"
+
+bool dumpout(pmConfig *config, char *name) 
+{
+  pmFPAview *view = ppSubViewReadout(); // View to readout
+  pmReadout *out = pmFPAfileThisReadout(config->files, view, "PPSUB.OUTPUT");
+  psphotSaveImage (NULL, out->image, name);
+  return true;
+}
+
 
 bool ppSubLoop(ppSubData *data)
@@ -105,4 +115,5 @@
         return false;
     }
+    // dumpout(config, "diff.1.fits");
 
     // Close convolved files
@@ -111,4 +122,5 @@
         return false;
     }
+    // dumpout(config, "diff.2a.fits");
 
     // Higher order background subtraction using psphot
@@ -117,4 +129,5 @@
         return false;
     }
+    // dumpout(config, "diff.2b.fits");
 
     // Perform Variance correction (rescale within a modest range)
@@ -123,4 +136,5 @@
         return false;
     }
+    // dumpout(config, "diff.2c.fits");
 
     if (data->quality) {
@@ -138,4 +152,5 @@
         return false;
     }
+    // dumpout(config, "diff.3.fits");
 
     if (!ppSubFilesIterateUp(config, PPSUB_FILES_PHOT_SUB)) {
@@ -157,4 +172,5 @@
       }
     }
+    // dumpout(config, "diff.4.fits");
     
     // generate the binned image used to write the jpeg
@@ -204,4 +220,5 @@
     } else {
         // Close subtraction files
+	// dumpout(config, "diff.5.fits");
         if (!ppSubFilesIterateUp(config, PPSUB_FILES_SUB)) {
             psError(PPSUB_ERR_IO, false, "Unable to close subtraction files.");
Index: /branches/sc_branches/trunkTest/ppSub/src/ppSubReadoutPhotometry.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSub/src/ppSubReadoutPhotometry.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSub/src/ppSubReadoutPhotometry.c	(revision 29060)
@@ -97,4 +97,10 @@
     psAssert (sources, "missing sources?");
 
+    // a likely source of false positives is poor subtractions.  this results in
+    // detections in the wings (or cores) of bright(er) stars found in both images.
+    // flag detections based on their distance from the bright(er) input sources.
+    bool matchRef = !strcasecmp(name, "PPSUB.INVERSE");
+    ppSubFlagNeighbors (config, view, sources, matchRef);
+
     if (data->stats) {
         bool mdok;
Index: /branches/sc_branches/trunkTest/ppSub/src/ppSubReadoutSubtract.c
===================================================================
--- /branches/sc_branches/trunkTest/ppSub/src/ppSubReadoutSubtract.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/ppSub/src/ppSubReadoutSubtract.c	(revision 29060)
@@ -51,9 +51,16 @@
     outRO->variance = (psImage*)psBinaryOp(outRO->variance, minuend->variance, "+", subtrahend->variance);
 
+    // NAN the masked pixels in the diff image (pixels masked in A are not yet NAN'ed in B)
+    psImageMaskType maskVal = pmConfigMaskGet("MASK.VALUE", config) | pmConfigMaskGet("BLANK", config); // Bits to mask in inputs
+    for (int iy = 0; iy < outRO->image->numRows; iy++) {
+	for (int ix = 0; ix < outRO->image->numCols; ix++) {
+	    if ((outRO->mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal) == 0) continue;
+	    outRO->image->data.F32[iy][ix] = NAN;
+	}
+    }
+
     // Measure the variance scales
     psStats *varStats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for variance images
     psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS);           // Random number generator
-    psImageMaskType maskVal = pmConfigMaskGet("MASK.VALUE", config) |
-        pmConfigMaskGet("BLANK", config); // Bits to mask in inputs
     psImageBackground(varStats, NULL, minuend->variance, minuend->mask, maskVal, rng);
     float minuendVar = varStats->robustMedian; // Mean variance for minuend
Index: /branches/sc_branches/trunkTest/psLib/src/fft/psImageFFT.c
===================================================================
--- /branches/sc_branches/trunkTest/psLib/src/fft/psImageFFT.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psLib/src/fft/psImageFFT.c	(revision 29060)
@@ -23,4 +23,5 @@
 #include <pthread.h>
 
+#include "psAbort.h"
 #include "psAssert.h"
 #include "psError.h"
@@ -532,2 +533,328 @@
     return out;
 }
+
+void psKernelFFTFree(psKernelFFT *kernel) {
+
+    if (!kernel->fft) return;
+    
+    bool threaded = psThreadPoolSize(); // Are we running threaded?
+
+    FFTW_LOCK;
+    fftwf_free(kernel->fft);
+    FFTW_UNLOCK;
+
+    return;
+}
+
+psKernelFFT *psKernelFFTAlloc(const psKernel *input) {
+
+    psKernelFFT *kernel = psAlloc(sizeof(psKernelFFT));
+    psMemSetDeallocator(kernel, (psFreeFunc)psKernelFFTFree);
+
+    kernel->fft = NULL;
+
+    kernel->xMin = input->xMin;
+    kernel->xMax = input->xMax;
+    kernel->yMin = input->yMin;
+    kernel->yMax = input->yMax;
+
+    kernel->paddedCols = 0;
+    kernel->paddedRows = 0;
+
+    return kernel;
+}
+
+// generate the FFTed kernel image appropriate to be used for convolution of the given input image
+psKernelFFT *psImageConvolveKernelInit(const psImage *in, const psKernel *kernel)
+{
+    PS_ASSERT_IMAGE_NON_NULL(in, NULL);
+    PS_ASSERT_IMAGE_TYPE(in, PS_TYPE_F32, NULL);
+    PS_ASSERT_KERNEL_NON_NULL(kernel, NULL);
+
+    bool threaded = psThreadPoolSize(); // Are we running threaded?
+
+    int numCols = in->numCols, numRows = in->numRows; // Size of image
+    int xMin = kernel->xMin, xMax = kernel->xMax, yMin = kernel->yMin, yMax = kernel->yMax; // Kernel sizes
+
+    // Need to pad the kernel (and later the input image) to protect from wrap-around effects
+    if (xMax - xMin > numCols || yMax - yMin > numRows) {
+        // Cannot pad the image if the kernel is larger.
+        psError(PS_ERR_BAD_PARAMETER_SIZE, true,
+                _("Kernel cannot extend further than input image size (%dx%d vs %dx%d)."),
+                xMax, yMax, numCols, numRows);
+        return NULL;
+    }
+
+    int paddedCols = numCols + PS_MAX(-xMin, xMax); // Number of columns in padded image
+    int paddedRows = numRows + PS_MAX(-yMin, yMax); // Number of rows in padded image
+
+#if CONVOLVE_FFT_BINARY_SIZE
+    // Make the size an integer power of two
+    {
+        int twoCols, twoRows;           // Size that is a factor of two
+        for (twoCols = 1; twoCols <= paddedCols && twoCols < INT_MAX - 1; twoCols <<= 1); // No action
+        for (twoRows = 1; twoRows <= paddedRows && twoRows < INT_MAX - 1; twoRows <<= 1); // No action
+        if (paddedCols > twoCols || paddedRows > twoRows) {
+            psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Unable to scale size (%dx%d) up to factor of two",
+                    paddedCols, paddedRows);
+            return NULL;
+        }
+        paddedCols = twoCols;
+        paddedRows = twoRows;
+    }
+#endif
+
+    int numPadded = paddedCols * paddedRows; // Number of pixels in padded image
+
+    // Create data array containing the padded kernel
+    FFTW_LOCK;
+    psF32 *data = fftwf_malloc(numPadded * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); // Data for FFTW
+    FFTW_UNLOCK;
+
+    // Generate the padded kernel image.  We could generate the padded kernel image using
+    // memcpy, but by going pixel by pixel we can apply the normalisation that corrects for the
+    // FFT renormalisation.  By applying it to the kernel here, we save applying it to the
+    // output image(s).
+
+    // copy kernel into data array
+    psF32 *dataPtr = data;              // Pointer into FFTW data
+    float norm = 1.0 / (float)(paddedRows * paddedCols); // Normalisation to correct for FFT
+
+    int xNegMin = PS_MIN(-1, xMin), xNegMax = PS_MIN(-1, xMax); // Min and max for x when negative
+    int xPosMin = PS_MAX(0, xMin), xPosMax = PS_MAX(0, xMax); // Min and max for x when positive
+    int yNegMin = PS_MIN(-1, yMin), yNegMax = PS_MIN(-1, yMax); // Min and max for x when negative
+    int yPosMin = PS_MAX(0, yMin), yPosMax = PS_MAX(0, yMax); // Min and max for x when positive
+    int blankCols = xNegMin + paddedCols - xPosMax - 1; // Number of columns between kernel extrema
+    int blankRows = (yNegMin + paddedRows - yPosMax - 1) * paddedCols; // Rows between kernel extrema
+    size_t blankColBytes = blankCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes in blankCols
+    for (int y = yPosMin; y <= yPosMax; y++) {
+        // y is positive
+        for (int x = xPosMin; x <= xPosMax; x++, dataPtr++) {
+            // x is positive
+            *dataPtr = kernel->kernel[y][x] * norm;
+        }
+        // Columns between kernel extrema
+        memset(dataPtr, 0, blankColBytes);
+        dataPtr += blankCols;
+        for (int x = xNegMin; x <= xNegMax; x++, dataPtr++) {
+            // x is negative
+            *dataPtr = kernel->kernel[y][x] * norm;
+        }
+    }
+    // Rows between kernel extrema
+    memset(dataPtr, 0, blankRows * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+    dataPtr += blankRows;
+    for (int y = yNegMin; y <= yNegMax; y++) {
+        // y is negative
+        for (int x = xPosMin; x <= xPosMax; x++, dataPtr++) {
+            // x is positive
+            *dataPtr = kernel->kernel[y][x] * norm;
+        }
+        // Columns between kernel extrema
+        memset(dataPtr, 0, blankColBytes);
+        dataPtr += blankCols;
+        for (int x = xNegMin; x <= xNegMax; x++, dataPtr++) {
+            // x is negative
+            *dataPtr = kernel->kernel[y][x] * norm;
+        }
+    }
+
+#if 0
+    {
+        // Use this for inspecting the result of copying the kernel
+        psImage *test = psImageAlloc(paddedCols, paddedRows, PS_TYPE_F32);
+        psFree(test->p_rawDataBuffer);
+        test->p_rawDataBuffer = data;
+        test->data.V[0] = test->p_rawDataBuffer;
+        for (int y = 1; y < paddedRows; y++) {
+            test->data.V[y] = (psPtr)((int8_t *)test->data.V[y - 1] + paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+        }
+        // View image here or write to disk
+        test->p_rawDataBuffer = NULL;
+        psFree(test);
+    }
+#endif
+
+    // Do the forward FFT
+    // Note that the FFT images have different size from the input
+    FFTW_LOCK;
+    fftwf_complex *fft = fftwf_malloc((paddedCols/2 + 1) * paddedRows * sizeof(fftwf_complex)); // FFT
+    FFTW_UNLOCK;
+
+    FFTW_LOCK;
+    fftwf_plan plan = fftwf_plan_dft_r2c_2d(paddedRows, paddedCols, data, fft, FFTW_PLAN_RIGOR);
+    FFTW_UNLOCK;
+
+    fftwf_execute(plan);
+
+    FFTW_LOCK;
+    fftwf_destroy_plan(plan);
+    fftwf_free(data);
+    FFTW_UNLOCK;
+
+    psKernelFFT *output = psKernelFFTAlloc(kernel);
+    output->fft = fft;
+    output->paddedCols = paddedCols;
+    output->paddedRows = paddedRows;
+
+    return output;
+}
+
+psImage *psImageConvolveKernel(psImage *out, const psImage *in, const psImage *mask, psImageMaskType maskVal, const psKernelFFT *kernel)
+{
+    PS_ASSERT_IMAGE_NON_NULL(in, NULL);
+    PS_ASSERT_IMAGE_TYPE(in, PS_TYPE_F32, NULL);
+    PS_ASSERT_PTR_NON_NULL(kernel, NULL);
+    PS_ASSERT_PTR_NON_NULL(kernel->fft, NULL);
+    if (mask) {
+        PS_ASSERT_IMAGE_NON_NULL(mask, NULL);
+        PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_IMAGE_MASK, NULL);
+        PS_ASSERT_IMAGES_SIZE_EQUAL(mask, in, NULL);
+    }
+
+    bool threaded = psThreadPoolSize(); // Are we running threaded?
+
+    int numCols = in->numCols, numRows = in->numRows; // Size of image
+    int xMin = kernel->xMin, xMax = kernel->xMax, yMin = kernel->yMin, yMax = kernel->yMax; // Kernel sizes
+
+    // Need to pad the input image to protect from wrap-around effects
+    if (xMax - xMin > numCols || yMax - yMin > numRows) {
+        // Cannot pad the image if the kernel is larger.
+        psError(PS_ERR_BAD_PARAMETER_SIZE, true, _("Kernel cannot extend further than input image size (%dx%d vs %dx%d)."), xMax, yMax, numCols, numRows);
+        return NULL;
+    }
+
+    int paddedCols = numCols + PS_MAX(-xMin, xMax); // Number of columns in padded image
+    int paddedRows = numRows + PS_MAX(-yMin, yMax); // Number of rows in padded image
+
+#if CONVOLVE_FFT_BINARY_SIZE
+    // Make the size an integer power of two
+    {
+        int twoCols, twoRows;           // Size that is a factor of two
+        for (twoCols = 1; twoCols <= paddedCols && twoCols < INT_MAX - 1; twoCols <<= 1); // No action
+        for (twoRows = 1; twoRows <= paddedRows && twoRows < INT_MAX - 1; twoRows <<= 1); // No action
+        if (paddedCols > twoCols || paddedRows > twoRows) {
+            psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Unable to scale size (%dx%d) up to factor of two",
+                    paddedCols, paddedRows);
+            return NULL;
+        }
+        paddedCols = twoCols;
+        paddedRows = twoRows;
+    }
+#endif
+
+    if (paddedCols != kernel->paddedCols) {
+	psAbort(_("Image is inconsistent with allocated kernel"));
+    }	
+    if (paddedRows != kernel->paddedRows) {
+        psAbort(_("Image is inconsistent with allocated kernel"));
+    }	
+
+    int numPadded = paddedCols * paddedRows; // Number of pixels in padded image
+
+    // Create data array containing the padded image
+    FFTW_LOCK;
+    psF32 *data = fftwf_malloc(numPadded * PSELEMTYPE_SIZEOF(PS_TYPE_F32)); // Data for FFTW
+    FFTW_UNLOCK;
+    psF32 *dataPtr = data;              // Pointer into FFTW data
+    psF32 **imageData = in->data.F32;   // Pointer into image data
+
+    // Copy image into data array
+    size_t goodBytes = numCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes per image row
+    size_t padBytes = (paddedCols - numCols) * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes to pad
+    for (int y = 0; y < numRows; y++, dataPtr += paddedCols, imageData++) {
+        memcpy(dataPtr, *imageData, goodBytes);
+        memset(dataPtr + numCols, 0, padBytes);
+    }
+    memset(dataPtr, 0, (paddedRows - numRows) * paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+
+#if 0
+    {
+        // Use this for inspecting the result of copying the image
+        psImage *test = psImageAlloc(paddedCols, paddedRows, PS_TYPE_F32);
+        psFree(test->p_rawDataBuffer);
+        test->p_rawDataBuffer = data;
+        test->data.V[0] = test->p_rawDataBuffer;
+        for (int y = 1; y < paddedRows; y++) {
+            test->data.V[y] = (psPtr)((int8_t *)test->data.V[y - 1] +
+                                      paddedCols * PSELEMTYPE_SIZEOF(PS_TYPE_F32));
+        }
+        // View image here
+        test->p_rawDataBuffer = NULL;
+        psFree(test);
+    }
+#endif
+
+    // Mask bad pixels (which may be NANs), lest they infect everything
+    if (mask && maskVal) {
+        for (int y = 0; y < numRows; y++) {
+            for (int x = 0; x < numCols; x++) {
+                if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) {
+                    data[x + paddedCols * y] = 0;
+                }
+            }
+        }
+    }
+
+    // Do the forward FFT
+    // Note that the FFT images have different size from the input
+    FFTW_LOCK;
+    fftwf_complex *fft = fftwf_malloc((paddedCols/2 + 1) * paddedRows * sizeof(fftwf_complex)); // FFT
+    FFTW_UNLOCK;
+
+    int fftCols = paddedCols/2 + 1, fftRows = paddedRows; // Size of FFT images
+    int fftPixels = fftCols * fftRows;  // Number of pixels in FFT image
+
+    FFTW_LOCK;
+    fftwf_plan forward = fftwf_plan_dft_r2c_2d(paddedRows, paddedCols, data, fft, FFTW_PLAN_RIGOR);
+    FFTW_UNLOCK;
+
+    fftwf_execute(forward);
+
+    FFTW_LOCK;
+    fftwf_destroy_plan(forward);
+    FFTW_UNLOCK;
+
+    fftwf_complex *kernelFFT = kernel->fft;
+
+    // Multiply the two transforms
+    for (int i = 0; i < fftPixels; i++) {
+        // (a + bi) * (c + di) = (ac - bd) + (bc + ad)i
+#if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I)
+        // C99 complex support
+        fft[i] *= kernelFFT[i];
+#else
+        // FFTW's backup complex support
+        float imageReal = fft[i][0], imageImag = fft[i][1];
+        float kernelReal = kernelFFT[i][0], kernelImag = kernelFFT[i][1];
+        fft[i][0] = imageReal * kernelReal - imageImag * kernelImag;
+        fft[i][1] = imageImag * kernelReal + imageReal * kernelImag;
+#endif
+    }
+
+    // Do the backward FFT
+    FFTW_LOCK;
+    fftwf_plan backward = fftwf_plan_dft_c2r_2d(paddedRows, paddedCols, fft, data, FFTW_PLAN_RIGOR);
+    FFTW_UNLOCK;
+
+    fftwf_execute(backward);
+
+    FFTW_LOCK;
+    fftwf_destroy_plan(backward);
+    fftwf_free(fft);
+    FFTW_UNLOCK;
+
+    // Copy into the target, without the padding
+    out = psImageRecycle(out, numCols, numRows, PS_TYPE_F32);
+    psF32 **outData = out->data.F32;    // Pointer into output
+    dataPtr = data;                     // Reset to start
+    for (int y = 0; y < numRows; y++, outData++, dataPtr += paddedCols) {
+        memcpy(*outData, dataPtr, goodBytes);
+    }
+
+    FFTW_LOCK;
+    fftwf_free(data);
+    FFTW_UNLOCK;
+
+    return out;
+}
Index: /branches/sc_branches/trunkTest/psLib/src/fft/psImageFFT.h
===================================================================
--- /branches/sc_branches/trunkTest/psLib/src/fft/psImageFFT.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psLib/src/fft/psImageFFT.h	(revision 29060)
@@ -15,4 +15,14 @@
 #include "psImage.h"
 #include "psImageConvolve.h"
+
+typedef struct {
+    void *fft;
+    int xMin;                          ///< Most negative x index
+    int yMin;                          ///< Most negative y index
+    int xMax;                          ///< Most positive x index
+    int yMax;                          ///< Most positive y index
+    int paddedCols;
+    int paddedRows;
+} psKernelFFT;
 
 /// @addtogroup MathOps Mathematical Operations
@@ -71,6 +81,26 @@
     const psImage *mask,                ///< Corresponding mask
     psImageMaskType maskVal,		///< Value to mask
-    const psKernel *kernel              ///< kernel to colvolve with
+    const psKernel *kernel              ///< kernel to convolve with
+    );
+
+/// Allocate an the psKernelFFT structure
+psKernelFFT *psKernelFFTAlloc(
+    const psKernel *input		///< kernel to convolve with
 );
+
+/// Generate an FFT'ed kernel suitable for convolution with the given image
+psKernelFFT *psImageConvolveKernelInit(
+    const psImage *in,			///< representative image to convolve
+    const psKernel *kernel		///< kernel to convolve with
+    );
+
+/// Convolve the given image with the pre-FFT'ed kernel
+psImage *psImageConvolveKernel(
+    psImage *out,			///< Output image, or NULL
+    const psImage *in,			///< Image to convolve
+    const psImage *mask,		///< Corresponding mask
+    psImageMaskType maskVal,		///< Value to mask
+    const psKernelFFT *kernel		///< kernel to convolve with
+    );
 
 /// @}
Index: /branches/sc_branches/trunkTest/psLib/src/jpeg/psImageJpeg.c
===================================================================
--- /branches/sc_branches/trunkTest/psLib/src/jpeg/psImageJpeg.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psLib/src/jpeg/psImageJpeg.c	(revision 29060)
@@ -7,4 +7,5 @@
 #include <string.h>
 
+#include <kapa.h>
 #include "psMemory.h"
 #include "psImage.h"
@@ -134,4 +135,144 @@
     return psImageJpegColormapSet (map, "greyscale");
 }
+
+// XXX need to fix library references for this (psLib does not depend on libkapa)
+# if (0)
+// XXX Add colormap bar with scale (min -> max)
+// XXX Add option to plot the source overlay (pass in bDrawBuffer populated with points?)
+// XXX need to update bDraw APIs to pass in/out structure and avoid the local static 
+bool psImageJpegNew(const psImageJpegColormap *map, const psImage *image, const char *filename,
+                 float min, float max)
+{
+    PS_ASSERT_PTR_NON_NULL(map, false);
+    PS_ASSERT_IMAGE_NON_NULL(image, false);
+    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
+    PS_ASSERT_VECTOR_NON_NULL(map->red, false);
+    PS_ASSERT_VECTOR_NON_NULL(map->green, false);
+    PS_ASSERT_VECTOR_NON_NULL(map->blue, false);
+    PS_ASSERT_PTR_NON_NULL(filename, false);
+    PS_ASSERT_INT_POSITIVE(strlen(filename), false);
+    PS_ASSERT_FLOAT_REAL(min, false);
+    PS_ASSERT_FLOAT_REAL(max, false);
+
+    float zero, scale;
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+
+    long pixel;
+    JSAMPLE *jpegLine;   // Points to data for current line
+    JSAMPROW jpegLineList[1];  // pointer to JSAMPLE row[s]
+    JSAMPLE *jpegImage;
+    JSAMPLE *outPix;
+
+    /* JPEG init calls */
+    cinfo.err = jpeg_std_error (&jerr);
+    jpeg_create_compress (&cinfo);
+
+    /* open file, prep for jpeg */
+    FILE *f = fopen(filename, "w");
+    if (!f) {
+	psError(PS_ERR_IO, true, "failed to open %s for output\n", filename);
+	return false;
+    }
+    jpeg_stdio_dest(&cinfo, f);
+
+    /* set up color jpeg buffers */
+    int quality = 75;
+    cinfo.image_width = image->numCols; // image width and height, in pixels
+    cinfo.image_height = image->numRows;
+    cinfo.input_components = 3;
+    cinfo.in_color_space = JCS_RGB;
+    jpeg_set_defaults (&cinfo);
+    jpeg_set_quality (&cinfo, quality, true); // limit to baseline-JPEG values
+    jpeg_start_compress (&cinfo, true);
+
+    psU8 *Rpix = map->red->data.U8;
+    psU8 *Gpix = map->green->data.U8;
+    psU8 *Bpix = map->blue->data.U8;
+
+    if (max == min) {
+	zero = min - 0.1;
+	scale = 256.0/0.2;
+    } else {
+	zero = min;
+	scale = 256.0/(max - min);
+    }
+
+    int dx = image->numCols;
+    int dy = image->numRows;
+
+    // output image buffer and line buffer
+    jpegLine = psAlloc (3*dx*sizeof(JSAMPLE));
+    jpegImage = psAlloc (3*dx*dy*sizeof(JSAMPLE));
+
+    // first copy the image data into the output buffer 
+    for (int j = 0; j < dy; j++) {
+	psF32 *row = image->data.F32[j];
+
+	outPix = jpegLine;
+	for (int i = 0; i < dx; i++, outPix += 3) {
+	    if (isfinite(row[i])) {
+		pixel = PS_JPEG_SCALEVALUE(row[i],zero,scale);
+		outPix[0] = Rpix[pixel];
+		outPix[1] = Gpix[pixel];
+		outPix[2] = Bpix[pixel];
+	    } else {
+		// XXX NAN value should be set per-color map
+		outPix[0] = 0x00;
+		outPix[1] = 0xff;
+		outPix[2] = 0x00;
+	    }
+	}
+	memcpy (&jpegImage[j*3*dx], jpegLine, 3*dx);
+    }
+
+    bDrawBuffer *bdbuf = bDrawBufferCreate(dx, dy);
+    bDrawSetBuffer(bdbuf);
+    bDrawColor red = KapaColorByName("red");
+    bDrawSetStyle (red, 1, 0);
+    bDrawCircle(40.0, 20.0, 3.0);
+
+    {
+	int Npalette;
+	png_color *palette = KapaPNGPalette (&Npalette);
+	bDrawColor white = KapaColorByName ("white");
+	for (int j = 0; j < dy; j++) {
+	    for (int i = 0; i < dx; i++) {
+		bDrawColor color = bdbuf[0].pixels[j][i];
+		if (color == white) continue;
+		jpegImage[j*3*dx + 3*i + 0] = palette[color].red;
+		jpegImage[j*3*dx + 3*i + 1] = palette[color].green;
+		jpegImage[j*3*dx + 3*i + 2] = palette[color].blue;
+	    }
+	}
+    }
+    bDrawBufferFree (bdbuf);
+
+    // write out the image buffer
+    for (int j = 0; j < image->numRows; j++) {
+	jpegLineList[0] = &jpegImage[j*3*dx];
+	if (jpeg_write_scanlines(&cinfo, jpegLineList, 1) == 0) {
+	    psError(PS_ERR_IO, true, "Unable to write line %d to JPEG", j);
+	    psFree(jpegLine);
+	    psFree(jpegImage);
+	    fclose(f);
+	    return false;
+	}
+    }
+
+    jpeg_finish_compress(&cinfo);
+    if (fclose(f) == EOF) {
+	psError(PS_ERR_IO, true, "Failed to close %s", filename);
+	psFree(jpegLine);
+	psFree(jpegImage);
+	return false;
+    }
+    jpeg_destroy_compress(&cinfo);
+
+    psFree(jpegLine);
+    psFree(jpegImage);
+    return true;
+}
+# endif
 
 bool psImageJpeg(const psImageJpegColormap *map, const psImage *image, const char *filename,
Index: /branches/sc_branches/trunkTest/psLib/src/math/psMinimizeLMM.c
===================================================================
--- /branches/sc_branches/trunkTest/psLib/src/math/psMinimizeLMM.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psLib/src/math/psMinimizeLMM.c	(revision 29060)
@@ -441,4 +441,7 @@
     }
 
+    // number of degrees of freedom for this fit
+    int nDOF = dy->n - params->n;
+
     // calculate initial alpha and beta, set chisq (min->value)
     min->value = psMinLM_SetABX(alpha, beta, params, paramMask, x, y, dy, func);
@@ -456,12 +459,14 @@
     }
 
-    // iterate until the tolerance is reached, or give up
-    while ((min->iter < min->maxIter) && ((min->lastDelta > min->tol) || !isfinite(min->lastDelta))) {
+    // iterate until: (a) nIter = min->iter or (b) (chisq / ndof) < maxChisq and deltaChisq < minTol (but don't stop unless Chisq is finite)
+    bool done = (min->iter >= min->maxIter);
+    while (!done) {
         psTrace("psLib.math", 5, "Iteration number %d.  (max iterations is %d).\n", min->iter, min->maxIter);
-        psTrace("psLib.math", 5, "Last delta is %f.  Min->tol is %f.\n", min->lastDelta, min->tol);
+        psTrace("psLib.math", 5, "Last delta is %f.  stop if < %f, accept if < %f\n", min->lastDelta, min->minTol, min->maxTol);
 
         // set a new guess for Alpha, Beta, Params
         if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, checkLimits, lambda, &dLinear)) {
             min->iter ++;
+	    if (min->iter >=  min->maxIter) break;
             lambda *= 10.0;
             continue;
@@ -482,4 +487,5 @@
         if (isnan(Chisq)) {
             min->iter ++;
+	    if (min->iter >= min->maxIter) break;
             lambda *= 10.0;
             continue;
@@ -492,9 +498,7 @@
         psF32 rho = (min->value - Chisq) / dLinear;
 
-        psTrace("psLib.math", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f\n", min->value,
-                Chisq, min->lastDelta, dLinear, rho, lambda);
-
-        psTrace("psLib.math.dLinear", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f\n", min->value,
-                Chisq, min->lastDelta, dLinear, rho, lambda);
+        psTrace("psLib.math", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f, nDOF: %d\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda, nDOF);
+
+        psTrace("psLib.math.dLinear", 5, "last chisq: %f, new chisq %f, delta: %f, dLinear: %f, rho: %f, lambda: %f\n", min->value, Chisq, min->lastDelta, dLinear, rho, lambda);
 
         // dump some useful info if trace is defined
@@ -506,5 +510,5 @@
         /* rho is positive if the new chisq is smaller; allow for some insignificant change (slight negative rho) */
         if (rho >= -1e-6) {
-            min->lastDelta = (min->value - Chisq) / (dy->n - params->n);
+            min->lastDelta = (min->value - Chisq) / nDOF;
             min->value = Chisq;
             alpha  = psImageCopy(alpha, Alpha, PS_TYPE_F32);
@@ -516,4 +520,12 @@
         }
         min->iter++;
+
+	done = (min->iter >= min->maxIter);
+	
+	// check for convergence:
+	float chisqDOF = Chisq / nDOF;
+	if (!isfinite(min->maxChisqDOF) || ((chisqDOF < min->maxChisqDOF) && isfinite(min->lastDelta))) {
+	    done |= (min->lastDelta < min->minTol);
+	}
     }
     psTrace("psLib.math", 5, "chisq: %f, last delta: %f, Niter: %d\n", min->value, min->lastDelta, min->iter);
@@ -549,10 +561,12 @@
         psFree(dy);
     }
-    if (min->iter == min->maxIter) {
-        psTrace("psLib.math", 3, "---- end (false) ----\n");
-        return(false);
-    }
-    psTrace("psLib.math", 3, "---- end (true) ----\n");
-    return(true);
+
+    // if the last improvement was at least as good as maxTol, accept the fit:
+    if (min->lastDelta <= min->maxTol) {
+	psTrace("psLib.math", 6, "---- end (true) ----\n");
+        return(true);
+    }
+    psTrace("psLib.math", 6, "---- end (false) ----\n");
+    return(false);
 }
 
@@ -588,6 +602,5 @@
 }
 
-psMinimization *psMinimizationAlloc(int maxIter,
-                                    float tol)
+psMinimization *psMinimizationAlloc(int maxIter, float minTol, float maxTol)
 {
     PS_ASSERT_INT_NONNEGATIVE(maxIter, NULL);
@@ -595,9 +608,13 @@
     psMinimization *min = psAlloc(sizeof(psMinimization));
     psMemSetDeallocator(min, (psFreeFunc)minimizationFree);
+
     P_PSMINIMIZATION_SET_MAXITER(min,maxIter);
-    P_PSMINIMIZATION_SET_TOL(min,tol);
+    P_PSMINIMIZATION_SET_MIN_TOL(min,minTol);
+    P_PSMINIMIZATION_SET_MAX_TOL(min,maxTol);
+
     min->value = 0.0;
     min->iter = 0;
     min->lastDelta = NAN;
+    min->maxChisqDOF = NAN;
 
     return(min);
Index: /branches/sc_branches/trunkTest/psLib/src/math/psMinimizeLMM.h
===================================================================
--- /branches/sc_branches/trunkTest/psLib/src/math/psMinimizeLMM.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psLib/src/math/psMinimizeLMM.h	(revision 29060)
@@ -33,6 +33,7 @@
 #define PS_MAX_LMM_ITERATIONS 100
 #define PS_MAX_MINIMIZE_ITERATIONS 100
-#define P_PSMINIMIZATION_SET_MAXITER(m,val) *(int*)&m->maxIter = val
-        #define P_PSMINIMIZATION_SET_TOL(m,val) *(float*)&m->tol = val
+#define P_PSMINIMIZATION_SET_MAXITER(m,val) { *(int*)&m->maxIter  = val; }
+#define P_PSMINIMIZATION_SET_MIN_TOL(m,val) { *(float*)&m->minTol = val; }
+#define P_PSMINIMIZATION_SET_MAX_TOL(m,val) { *(float*)&m->maxTol = val; }
 
                 typedef enum {
@@ -75,9 +76,11 @@
 typedef struct
 {
-    const int maxIter;                 ///< Convergence limit
-    const float tol;                   ///< Error Tolerance
+    const int maxIter;			///< Convergence limit
+    const float minTol;			///< Convergence Tolerance (stop if we reach this value)
+    const float maxTol;			///< Max Tolerance (accept fit if last improvement was this good)
     float value;                       ///< Value of function at minimum
     int iter;                          ///< Number of iterations to date
     float lastDelta;                   ///< The last difference for the fit
+    float maxChisqDOF;		       ///< for Chisq minimization, require that we reach here before checking tolerance
 }
 psMinimization;
@@ -102,5 +105,6 @@
 psMinimization *psMinimizationAlloc(
     int maxIter,                       ///< Number of minimization iterations to perform.
-    float tol                          ///< Requested error tolerance
+    float minTol,		       ///< stop if tolerance is less than this
+    float maxTol		       ///< accept fit if tolerance is less than this
 ) PS_ATTR_MALLOC;
 
Index: /branches/sc_branches/trunkTest/psLib/src/math/psMinimizePowell.c
===================================================================
--- /branches/sc_branches/trunkTest/psLib/src/math/psMinimizePowell.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psLib/src/math/psMinimizePowell.c	(revision 29060)
@@ -457,5 +457,5 @@
 
         mul = bracket->data.F32[1];
-        if ((fabs(a-b) < min->tol) && (fabs(b-c) < min->tol)) {
+        if ((fabs(a-b) < min->minTol) && (fabs(b-c) < min->minTol)) {
             PS_VECTOR_ADD_MULTIPLE(params, paramMask, line, params, mul);
             min->value = func(params, coords);
@@ -524,5 +524,5 @@
     psTrace("psLib.math", 4, "---- psMinimizePowell() begin ----\n");
     psTrace("psLib.math", 6, "min->maxIter is %d\n", min->maxIter);
-    psTrace("psLib.math", 6, "min->tol is %f\n", min->tol);
+    psTrace("psLib.math", 6, "min->minTol is %f\n", min->minTol);
 
     if (paramMask == NULL) {
@@ -573,6 +573,8 @@
         for (i=0;i<numDims;i++) {
             if (myParamMask->data.PS_TYPE_VECTOR_MASK_DATA[i] == 0) {
+
                 P_PSMINIMIZATION_SET_MAXITER((&dummyMin),PS_MINIMIZE_POWELL_LINEMIN_MAX_ITERATIONS);
-                *(float*)&dummyMin.tol = PS_MINIMIZE_POWELL_LINEMIN_ERROR_TOLERANCE;
+		P_PSMINIMIZATION_SET_MIN_TOL((&dummyMin),PS_MINIMIZE_POWELL_LINEMIN_ERROR_TOLERANCE);
+
                 mul = LineMin(&dummyMin, Q, ((psVector *) v->data[i]),
                               myParamMask, coords, func);
@@ -677,5 +679,5 @@
 
         // 8: Go to step 3 until the change is less than some tolerance.
-        if (fabs(baseFuncVal - currFuncVal) <= min->tol) {
+        if (fabs(baseFuncVal - currFuncVal) <= min->minTol) {
             psFree(v);
             psFree(pQP);
Index: /branches/sc_branches/trunkTest/psLib/src/math/psStats.c
===================================================================
--- /branches/sc_branches/trunkTest/psLib/src/math/psStats.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psLib/src/math/psStats.c	(revision 29060)
@@ -1211,5 +1211,5 @@
 
         // Fit a Gaussian to the data.
-        psMinimization *minimizer = psMinimizationAlloc(100, 0.01); // The minimizer information
+        psMinimization *minimizer = psMinimizationAlloc(100, 0.01, 1.0); // The minimizer information
         psVector *params = psVectorAlloc(2, PS_TYPE_F32); // Parameters for the Gaussian
         // Initial guess for the mean (index 0) and var (index 1).
Index: /branches/sc_branches/trunkTest/psLib/test/math/Makefile.am
===================================================================
--- /branches/sc_branches/trunkTest/psLib/test/math/Makefile.am	(revision 29059)
+++ /branches/sc_branches/trunkTest/psLib/test/math/Makefile.am	(revision 29060)
@@ -49,5 +49,6 @@
 	tap_psMinimizePowell \
 	tap_psSpline1D \
-	tap_psPolynomialMD
+	tap_psPolynomialMD \
+	tap_psPolynomialMD_sampleDark
 
 #	tap_psRandom
Index: /branches/sc_branches/trunkTest/psLib/test/math/data/polyMD.dat
===================================================================
--- /branches/sc_branches/trunkTest/psLib/test/math/data/polyMD.dat	(revision 29060)
+++ /branches/sc_branches/trunkTest/psLib/test/math/data/polyMD.dat	(revision 29060)
@@ -0,0 +1,5000 @@
+0 -76.6453006733 0 -0 0 1000 
+0 -72.3008076439 0 -0 0 1000 
+0 -76.8023579484 0 -0 0 1000 
+0 -76.8077040466 0 -0 0 1000 
+0 -75.6415950097 0 -0 0 1000 
+0 -82.6267142952 0 -0 0 1000 
+0 -75.951186959 0 -0 0 1000 
+0 -78.3036737875 0 -0 0 1000 
+0 -75.1696793985 0 -0 0 1000 
+0 -75.3412046981 0 -0 0 1000 
+0 -73.8333456324 0 -0 0 1000 
+0 -76.9069591238 0 -0 0 1000 
+0 -75.7393664898 0 -0 0 1000 
+0 -80.8127713284 0 -0 0 1000 
+0 -76.1937768649 0 -0 0 1000 
+0 -76.2219302919 0 -0 0 1000 
+0 -83.7481620914 0 -0 0 1000 
+0 -73.8610296014 0 -0 0 1000 
+0 -84.6768324061 0 -0 0 1000 
+0 -81.3967391426 0 -0 0 1000 
+0 -77.9057396658 0 -0 0 1000 
+0 -81.0415808534 0 -0 0 1000 
+0 -75.7363551074 0 -0 0 1000 
+0 -71.0077733552 0 -0 0 1000 
+0 -81.5855532314 0 -0 0 1000 
+0 -73.8004770641 0 -0 0 1000 
+0 -80.838355319 0 -0 0 1000 
+0 -82.5265015708 0 -0 0 1000 
+0 -79.1586092358 0 -0 0 1000 
+0 -78.5442355877 0 -0 0 1000 
+0 -77.0861025003 0 -0 0 1000 
+0 -81.3208409548 0 -0 0 1000 
+0 -84.7825278691 0 -0 0 1000 
+0 -83.5558774581 0 -0 0 1000 
+0 -76.6603200765 0 -0 0 1000 
+0 -80.4031007257 0 -0 0 1000 
+0 -77.6595096609 0 -0 0 1000 
+0 -80.3796663573 0 -0 0 1000 
+0 -73.8607148234 0 -0 0 1000 
+0 -72.8589405946 0 -0 0 1000 
+0 -76.5695668928 0 -0 0 1000 
+0 -72.4543336393 0 -0 0 1000 
+0 -76.1969868837 0 -0 0 1000 
+0 -77.5854209062 0 -0 0 1000 
+0 -80.4883891502 0 -0 0 1000 
+0 -82.3194394617 0 -0 0 1000 
+0 -78.9985732402 0 -0 0 1000 
+0 -71.0305256264 0 -0 0 1000 
+0 -83.3486210627 0 -0 0 1000 
+0 -75.0906176359 0 -0 0 1000 
+0 -82.6866213972 0 -0 0 1000 
+0 -71.6015492361 0 -0 0 1000 
+0 -72.8633957388 0 -0 0 1000 
+0 -74.3008838495 0 -0 0 1000 
+0 -78.9261414693 0 -0 0 1000 
+0 -73.2261181428 0 -0 0 1000 
+0 -71.7440724159 0 -0 0 1000 
+0 -76.8566799837 0 -0 0 1000 
+0 -82.8011391534 0 -0 0 1000 
+0 -80.7786554547 0 -0 0 1000 
+0 -74.3807792172 0 -0 0 1000 
+0 -84.2442329191 0 -0 0 1000 
+0 -71.3341094845 0 -0 0 1000 
+0 -81.1887089591 0 -0 0 1000 
+0 -77.9631944585 0 -0 0 1000 
+0 -73.2451010557 0 -0 0 1000 
+0 -70.7100171556 0 -0 0 1000 
+0 -77.6282849532 0 -0 0 1000 
+0 -70.276770487 0 -0 0 1000 
+0 -82.0460673226 0 -0 0 1000 
+0 -81.5233738308 0 -0 0 1000 
+0 -73.2263292634 0 -0 0 1000 
+0 -75.7711953727 0 -0 0 1000 
+0 -83.5400402938 0 -0 0 1000 
+0 -80.0079416136 0 -0 0 1000 
+0 -74.9135604192 0 -0 0 1000 
+0 -79.5463077241 0 -0 0 1000 
+0 -70.8591967113 0 -0 0 1000 
+0 -72.247764958 0 -0 0 1000 
+0 -74.7844025797 0 -0 0 1000 
+0 -83.297061281 0 -0 0 1000 
+0 -78.3227158123 0 -0 0 1000 
+0 -84.7246061428 0 -0 0 1000 
+0 -72.4398265121 0 -0 0 1000 
+0 -76.99273655 0 -0 0 1000 
+0 -76.3482199255 0 -0 0 1000 
+0 -84.6025022838 0 -0 0 1000 
+0 -74.2011497466 0 -0 0 1000 
+0 -76.7037994198 0 -0 0 1000 
+0 -74.813173408 0 -0 0 1000 
+0 -83.9602700413 0 -0 0 1000 
+0 -77.5565610563 0 -0 0 1000 
+0 -82.9281192189 0 -0 0 1000 
+0 -76.4703546916 0 -0 0 1000 
+0 -77.7856780119 0 -0 0 1000 
+0 -78.3062336803 0 -0 0 1000 
+0 -80.4803138895 0 -0 0 1000 
+0 -74.4460805717 0 -0 0 1000 
+0 -78.1721315775 0 -0 0 1000 
+0 -84.3359153006 0 -0 0 1000 
+0 -72.2955456432 0 -0 0 1000 
+0 -84.4727294561 0 -0 0 1000 
+0 -73.4946410434 0 -0 0 1000 
+0 -84.8909947524 0 -0 0 1000 
+0 -84.7420294585 0 -0 0 1000 
+0 -73.235507659 0 -0 0 1000 
+0 -78.7742665318 0 -0 0 1000 
+0 -70.4020348558 0 -0 0 1000 
+0 -74.4428468932 0 -0 0 1000 
+0 -81.2201815431 0 -0 0 1000 
+0 -81.309972632 0 -0 0 1000 
+0 -70.9780416743 0 -0 0 1000 
+0 -79.4635117133 0 -0 0 1000 
+0 -72.4221349418 0 -0 0 1000 
+0 -71.5078275488 0 -0 0 1000 
+0 -71.4253519835 0 -0 0 1000 
+0 -70.6413696173 0 -0 0 1000 
+0 -74.6717073889 0 -0 0 1000 
+0 -84.6668157448 0 -0 0 1000 
+0 -72.2486268437 0 -0 0 1000 
+0 -79.0087146571 0 -0 0 1000 
+0 -84.6160508238 0 -0 0 1000 
+0 -72.9883951703 0 -0 0 1000 
+0 -71.3673289733 0 -0 0 1000 
+0 -78.7139776417 0 -0 0 1000 
+0 -84.309062168 0 -0 0 1000 
+0 -72.9166404051 0 -0 0 1000 
+0 -74.9481491704 0 -0 0 1000 
+0 -82.6731196742 0 -0 0 1000 
+0 -74.1492830646 0 -0 0 1000 
+0 -73.9438167291 0 -0 0 1000 
+0 -76.6636714064 0 -0 0 1000 
+0 -82.8132048244 0 -0 0 1000 
+0 -76.5876076869 0 -0 0 1000 
+0 -78.5420976057 0 -0 0 1000 
+0 -77.0832914619 0 -0 0 1000 
+0 -73.2069125871 0 -0 0 1000 
+0 -84.6344314221 0 -0 0 1000 
+0 -71.9185645989 0 -0 0 1000 
+0 -74.6678191677 0 -0 0 1000 
+0 -71.4734910459 0 -0 0 1000 
+0 -79.0273589859 0 -0 0 1000 
+0 -74.8034346908 0 -0 0 1000 
+0 -80.7487135116 0 -0 0 1000 
+0 -80.4494783488 0 -0 0 1000 
+0 -81.7892466822 0 -0 0 1000 
+0 -75.6395906066 0 -0 0 1000 
+0 -70.8415621292 0 -0 0 1000 
+0 -78.5506910342 0 -0 0 1000 
+0 -80.3912816499 0 -0 0 1000 
+0 -82.967015422 0 -0 0 1000 
+0 -81.9768860933 0 -0 0 1000 
+0 -76.2728757227 0 -0 0 1000 
+0 -80.4317276113 0 -0 0 1000 
+0 -82.8138487263 0 -0 0 1000 
+0 -75.3759164923 0 -0 0 1000 
+0 -84.5575535354 0 -0 0 1000 
+0 -72.5082433936 0 -0 0 1000 
+0 -84.794808252 0 -0 0 1000 
+0 -83.5915651316 0 -0 0 1000 
+0 -70.0055871173 0 -0 0 1000 
+0 -76.1762839246 0 -0 0 1000 
+0 -82.8591034864 0 -0 0 1000 
+0 -73.152936837 0 -0 0 1000 
+0 -80.2056261506 0 -0 0 1000 
+0 -80.6896250472 0 -0 0 1000 
+0 -80.1582766444 0 -0 0 1000 
+0 -70.1635693768 0 -0 0 1000 
+0 -80.387721553 0 -0 0 1000 
+0 -79.7687399304 0 -0 0 1000 
+0 -70.9573368338 0 -0 0 1000 
+0 -76.2179279892 0 -0 0 1000 
+0 -79.672048974 0 -0 0 1000 
+0 -79.3614476335 0 -0 0 1000 
+0 -81.4809255909 0 -0 0 1000 
+0 -82.3169389772 0 -0 0 1000 
+0 -70.8949815524 0 -0 0 1000 
+0 -80.1864300707 0 -0 0 1000 
+0 -74.8640115126 0 -0 0 1000 
+0 -70.2215598809 0 -0 0 1000 
+0 -78.2239579804 0 -0 0 1000 
+0 -72.4879737856 0 -0 0 1000 
+0 -81.210828787 0 -0 0 1000 
+0 -80.314216404 0 -0 0 1000 
+0 -84.9610875583 0 -0 0 1000 
+0 -81.5993641403 0 -0 0 1000 
+0 -81.106644325 0 -0 0 1000 
+0 -75.6126776383 0 -0 0 1000 
+0 -82.3537269212 0 -0 0 1000 
+0 -74.5980933234 0 -0 0 1000 
+0 -75.6777812434 0 -0 0 1000 
+0 -84.0615052468 0 -0 0 1000 
+0 -76.2269862947 0 -0 0 1000 
+0 -74.0394165317 0 -0 0 1000 
+0 -72.5625879584 0 -0 0 1000 
+0 -75.7151381978 0 -0 0 1000 
+0 -70.5050343011 0 -0 0 1000 
+0 -72.7424043624 0 -0 0 1000 
+0 -78.4992924192 0 -0 0 1000 
+0 -73.417126459 0 -0 0 1000 
+0 -71.4500522992 0 -0 0 1000 
+0 -78.1567204125 0 -0 0 1000 
+0 -74.9186153699 0 -0 0 1000 
+0 -77.2057938104 0 -0 0 1000 
+0 -73.8027498206 0 -0 0 1000 
+0 -82.5067528961 0 -0 0 1000 
+0 -84.1654552795 0 -0 0 1000 
+0 -78.9621056961 0 -0 0 1000 
+0 -70.1176246682 0 -0 0 1000 
+0 -80.7559243072 0 -0 0 1000 
+0 -70.1838460372 0 -0 0 1000 
+0 -83.9257818586 0 -0 0 1000 
+0 -73.9388924812 0 -0 0 1000 
+0 -72.2870953541 0 -0 0 1000 
+0 -72.554796988 0 -0 0 1000 
+0 -84.1963894516 0 -0 0 1000 
+0 -80.1266038687 0 -0 0 1000 
+0 -84.8996951156 0 -0 0 1000 
+0 -81.252748694 0 -0 0 1000 
+0 -82.403569473 0 -0 0 1000 
+0 -79.5124203633 0 -0 0 1000 
+0 -79.3909001988 0 -0 0 1000 
+0 -77.9115372613 0 -0 0 1000 
+0 -80.4616017593 0 -0 0 1000 
+0 -73.1144662821 0 -0 0 1000 
+0 -76.2428281641 0 -0 0 1000 
+0 -72.4964004818 0 -0 0 1000 
+0 -71.9457404954 0 -0 0 1000 
+0 -72.6723698996 0 -0 0 1000 
+0 -74.1719061898 0 -0 0 1000 
+0 -81.2492507233 0 -0 0 1000 
+0 -75.7593172901 0 -0 0 1000 
+0 -71.1569369585 0 -0 0 1000 
+0 -75.9175514485 0 -0 0 1000 
+0 -82.4978777617 0 -0 0 1000 
+0 -83.6603014017 0 -0 0 1000 
+0 -79.8718702771 0 -0 0 1000 
+0 -74.3279065031 0 -0 0 1000 
+0 -73.2367499078 0 -0 0 1000 
+0 -83.0332407375 0 -0 0 1000 
+0 -83.583693873 0 -0 0 1000 
+0 -79.7290877877 0 -0 0 1000 
+0 -71.3415991442 0 -0 0 1000 
+0 -81.3173218577 0 -0 0 1000 
+0 -73.9048164173 0 -0 0 1000 
+0 -70.6953294596 0 -0 0 1000 
+0 -80.3690758752 0 -0 0 1000 
+0 -82.4143464466 0 -0 0 1000 
+0 -73.6058597874 0 -0 0 1000 
+0 -73.6402651727 0 -0 0 1000 
+0 -76.3166366042 0 -0 0 1000 
+0 -72.5230146438 0 -0 0 1000 
+0 -84.1674917919 0 -0 0 1000 
+0 -83.3597381749 0 -0 0 1000 
+0 -80.6298037166 0 -0 0 1000 
+0 -70.3899463031 0 -0 0 1000 
+0 -79.2976706333 0 -0 0 1000 
+0 -71.5249421562 0 -0 0 1000 
+0 -76.5004558645 0 -0 0 1000 
+0 -76.2858987478 0 -0 0 1000 
+0 -78.2641901488 0 -0 0 1000 
+0 -77.6679730088 0 -0 0 1000 
+0 -75.9104405332 0 -0 0 1000 
+0 -81.8508179637 0 -0 0 1000 
+0 -72.2295921443 0 -0 0 1000 
+0 -82.9522416908 0 -0 0 1000 
+0 -73.4522425417 0 -0 0 1000 
+0 -72.6874784873 0 -0 0 1000 
+0 -75.6588930304 0 -0 0 1000 
+0 -83.7755122544 0 -0 0 1000 
+0 -72.1685137932 0 -0 0 1000 
+0 -83.4949395703 0 -0 0 1000 
+0 -74.7112892798 0 -0 0 1000 
+0 -71.3270633871 0 -0 0 1000 
+0 -72.1639158595 0 -0 0 1000 
+0 -82.0349105847 0 -0 0 1000 
+0 -83.0643177846 0 -0 0 1000 
+0 -70.6917280665 0 -0 0 1000 
+0 -84.6780182769 0 -0 0 1000 
+0 -84.1220411517 0 -0 0 1000 
+0 -83.1702357931 0 -0 0 1000 
+0 -81.0570707238 0 -0 0 1000 
+0 -73.4921270511 0 -0 0 1000 
+0 -84.5694201826 0 -0 0 1000 
+0 -71.655158575 0 -0 0 1000 
+0 -76.3960661968 0 -0 0 1000 
+0 -79.7542101367 0 -0 0 1000 
+0 -83.9400969828 0 -0 0 1000 
+0 -75.665384109 0 -0 0 1000 
+0 -76.5423263069 0 -0 0 1000 
+0 -81.5259848804 0 -0 0 1000 
+0 -82.5317658468 0 -0 0 1000 
+0 -82.9941007151 0 -0 0 1000 
+0 -84.48977966 0 -0 0 1000 
+0 -81.0193069097 0 -0 0 1000 
+0 -81.1230472285 0 -0 0 1000 
+0 -70.9151984918 0 -0 0 1000 
+0 -75.6909748351 0 -0 0 1000 
+0 -71.7329460268 0 -0 0 1000 
+0 -79.1448426692 0 -0 0 1000 
+0 -73.7671964602 0 -0 0 1000 
+0 -80.0206980225 0 -0 0 1000 
+0 -82.6164726329 0 -0 0 1000 
+0 -79.5084512675 0 -0 0 1000 
+0 -84.5054872916 0 -0 0 1000 
+0 -81.3528499928 0 -0 0 1000 
+0 -83.2692533906 0 -0 0 1000 
+0 -83.8635516441 0 -0 0 1000 
+0 -74.039448204 0 -0 0 1000 
+0 -72.5726155639 0 -0 0 1000 
+0 -83.776537524 0 -0 0 1000 
+0 -81.5044391496 0 -0 0 1000 
+0 -75.134852875 0 -0 0 1000 
+0 -75.5326080532 0 -0 0 1000 
+0 -71.5415006872 0 -0 0 1000 
+0 -70.0633525549 0 -0 0 1000 
+0 -84.7619528408 0 -0 0 1000 
+0 -73.4462331274 0 -0 0 1000 
+0 -73.795222004 0 -0 0 1000 
+0 -74.9872417041 0 -0 0 1000 
+0 -79.854210655 0 -0 0 1000 
+0 -78.4949675379 0 -0 0 1000 
+0 -74.9623470128 0 -0 0 1000 
+0 -70.1914566686 0 -0 0 1000 
+0 -77.6887188638 0 -0 0 1000 
+0 -80.7751900346 0 -0 0 1000 
+0 -73.7882051481 0 -0 0 1000 
+0 -77.2137438804 0 -0 0 1000 
+0 -72.2617114487 0 -0 0 1000 
+0 -82.9068608409 0 -0 0 1000 
+0 -72.8561003751 0 -0 0 1000 
+0 -79.2884046007 0 -0 0 1000 
+0 -79.6942755862 0 -0 0 1000 
+0 -76.7185740045 0 -0 0 1000 
+0 -76.5571979662 0 -0 0 1000 
+0 -82.5479199621 0 -0 0 1000 
+0 -71.5255342042 0 -0 0 1000 
+0 -76.9747802878 0 -0 0 1000 
+0 -79.6388344955 0 -0 0 1000 
+0 -70.7028137742 0 -0 0 1000 
+0 -78.7224516811 0 -0 0 1000 
+0 -84.4503985799 0 -0 0 1000 
+0 -73.522252226 0 -0 0 1000 
+0 -84.10567336 0 -0 0 1000 
+0 -82.9243989496 0 -0 0 1000 
+0 -80.1303276631 0 -0 0 1000 
+0 -78.7228985029 0 -0 0 1000 
+0 -77.7683689581 0 -0 0 1000 
+0 -70.24220805 0 -0 0 1000 
+0 -79.5268891237 0 -0 0 1000 
+0 -72.9538558433 0 -0 0 1000 
+0 -77.2595177533 0 -0 0 1000 
+0 -72.3192826309 0 -0 0 1000 
+0 -75.1929528016 0 -0 0 1000 
+0 -83.0771244492 0 -0 0 1000 
+0 -72.1896684353 0 -0 0 1000 
+0 -81.1381678433 0 -0 0 1000 
+0 -80.3540200138 0 -0 0 1000 
+0 -71.6729361783 0 -0 0 1000 
+0 -80.3127004054 0 -0 0 1000 
+0 -72.5997033167 0 -0 0 1000 
+0 -82.096093402 0 -0 0 1000 
+0 -83.0117328923 0 -0 0 1000 
+0 -83.8923274108 0 -0 0 1000 
+0 -82.4214942657 0 -0 0 1000 
+0 -75.9005972241 0 -0 0 1000 
+0 -72.9777128879 0 -0 0 1000 
+0 -79.5517825514 0 -0 0 1000 
+0 -79.6840710607 0 -0 0 1000 
+0 -75.2014047837 0 -0 0 1000 
+0 -80.5508821021 0 -0 0 1000 
+0 -78.1327793339 0 -0 0 1000 
+0 -78.0110246159 0 -0 0 1000 
+0 -75.5062820463 0 -0 0 1000 
+0 -71.803412296 0 -0 0 1000 
+0 -82.3173558082 0 -0 0 1000 
+0 -74.0959865264 0 -0 0 1000 
+0 -83.9454948695 0 -0 0 1000 
+0 -73.7060017586 0 -0 0 1000 
+0 -73.7345048708 0 -0 0 1000 
+0 -74.1050768181 0 -0 0 1000 
+0 -70.6193032641 0 -0 0 1000 
+0 -84.0241755597 0 -0 0 1000 
+0 -77.6944876276 0 -0 0 1000 
+0 -81.4870012887 0 -0 0 1000 
+0 -70.0645562398 0 -0 0 1000 
+0 -78.0694973251 0 -0 0 1000 
+0 -71.4199573264 0 -0 0 1000 
+0 -72.3411025202 0 -0 0 1000 
+0 -76.5652066585 0 -0 0 1000 
+0 -75.3660632156 0 -0 0 1000 
+0 -84.9176528719 0 -0 0 1000 
+0 -71.7312365418 0 -0 0 1000 
+0 -73.9245136677 0 -0 0 1000 
+0 -82.4111065889 0 -0 0 1000 
+0 -73.3412423774 0 -0 0 1000 
+0 -70.0233686405 0 -0 0 1000 
+0 -83.9958422835 0 -0 0 1000 
+0 -81.6158790106 0 -0 0 1000 
+0 -84.6093226527 0 -0 0 1000 
+0 -81.378389754 0 -0 0 1000 
+0 -82.5477821042 0 -0 0 1000 
+0 -84.378135177 0 -0 0 1000 
+0 -84.0776490387 0 -0 0 1000 
+0 -72.1881070626 0 -0 0 1000 
+0 -74.496891513 0 -0 0 1000 
+0 -75.6826062266 0 -0 0 1000 
+0 -82.5270456415 0 -0 0 1000 
+0 -83.3190416237 0 -0 0 1000 
+0 -82.7724566473 0 -0 0 1000 
+0 -81.9759931661 0 -0 0 1000 
+0 -79.5644178513 0 -0 0 1000 
+0 -83.1710799875 0 -0 0 1000 
+0 -72.942587425 0 -0 0 1000 
+0 -78.5965700269 0 -0 0 1000 
+0 -79.5807711156 0 -0 0 1000 
+0 -75.4898085012 0 -0 0 1000 
+0 -74.6057325913 0 -0 0 1000 
+0 -81.2369002183 0 -0 0 1000 
+0 -78.6446713401 0 -0 0 1000 
+0 -84.644266264 0 -0 0 1000 
+0 -75.5778836488 0 -0 0 1000 
+0 -75.716009661 0 -0 0 1000 
+0 -70.5003270734 0 -0 0 1000 
+0 -77.3257682562 0 -0 0 1000 
+0 -72.240580213 0 -0 0 1000 
+0 -70.3723219862 0 -0 0 1000 
+0 -82.1952208515 0 -0 0 1000 
+0 -77.7963818341 0 -0 0 1000 
+0 -72.4811783655 0 -0 0 1000 
+0 -71.2515646784 0 -0 0 1000 
+0 -76.6823808081 0 -0 0 1000 
+0 -73.4537203812 0 -0 0 1000 
+0 -83.393175518 0 -0 0 1000 
+0 -75.7486458451 0 -0 0 1000 
+0 -77.067002947 0 -0 0 1000 
+0 -84.4462052398 0 -0 0 1000 
+0 -76.0148017124 0 -0 0 1000 
+0 -78.7162496147 0 -0 0 1000 
+0 -71.4268733977 0 -0 0 1000 
+0 -78.8122239348 0 -0 0 1000 
+0 -76.588314727 0 -0 0 1000 
+0 -75.2257993205 0 -0 0 1000 
+0 -81.4021875868 0 -0 0 1000 
+0 -75.3981869499 0 -0 0 1000 
+0 -78.1058264083 0 -0 0 1000 
+0 -72.0618119248 0 -0 0 1000 
+0 -77.9848336266 0 -0 0 1000 
+0 -72.9829897402 0 -0 0 1000 
+0 -80.7710168505 0 -0 0 1000 
+0 -79.7549598927 0 -0 0 1000 
+0 -84.2425394043 0 -0 0 1000 
+0 -79.2765790817 0 -0 0 1000 
+0 -83.7163629731 0 -0 0 1000 
+0 -72.0719382513 0 -0 0 1000 
+0 -77.5826409212 0 -0 0 1000 
+0 -79.0230860685 0 -0 0 1000 
+0 -77.1547452597 0 -0 0 1000 
+0 -79.6442001731 0 -0 0 1000 
+0 -80.727402431 0 -0 0 1000 
+0 -81.4073298995 0 -0 0 1000 
+0 -70.660352485 0 -0 0 1000 
+0 -75.0485944289 0 -0 0 1000 
+0 -70.8622209395 0 -0 0 1000 
+0 -73.4985498465 0 -0 0 1000 
+0 -84.5301557223 0 -0 0 1000 
+0 -82.5698577582 0 -0 0 1000 
+0 -84.5947176968 0 -0 0 1000 
+0 -75.0562452894 0 -0 0 1000 
+0 -77.0029713739 0 -0 0 1000 
+0 -80.9498549372 0 -0 0 1000 
+0 -81.9823215222 0 -0 0 1000 
+0 -79.7373782442 0 -0 0 1000 
+0 -76.3530049392 0 -0 0 1000 
+0 -76.2366143815 0 -0 0 1000 
+0 -77.1447721919 0 -0 0 1000 
+0 -76.4774272186 0 -0 0 1000 
+0 -71.6391143177 0 -0 0 1000 
+0 -80.9158978272 0 -0 0 1000 
+0 -74.9629307713 0 -0 0 1000 
+0 -75.5435083059 0 -0 0 1000 
+0 -70.8058301757 0 -0 0 1000 
+0 -79.570714293 0 -0 0 1000 
+0 -71.3039167384 0 -0 0 1000 
+0 -70.777757003 0 -0 0 1000 
+0 -71.2890228676 0 -0 0 1000 
+0 -79.5544114598 0 -0 0 1000 
+0 -81.7230630867 0 -0 0 1000 
+0 -74.7432751054 0 -0 0 1000 
+0 -83.6852371468 0 -0 0 1000 
+0 -77.4684471131 0 -0 0 1000 
+0 -80.9342793843 0 -0 0 1000 
+0 -72.5611990159 0 -0 0 1000 
+0 -83.0719789915 0 -0 0 1000 
+0 -80.4474797068 0 -0 0 1000 
+0 -75.6615530537 0 -0 0 1000 
+0 -83.9719717151 0 -0 0 1000 
+0 -73.4051098758 0 -0 0 1000 
+0 -80.4159657147 0 -0 0 1000 
+0 -79.0755399916 0 -0 0 1000 
+0 -73.6809582871 0 -0 0 1000 
+0 -71.0230842881 0 -0 0 1000 
+0 -84.0890825764 0 -0 0 1000 
+0 -83.5611611358 0 -0 0 1000 
+0 -82.0505170933 0 -0 0 1000 
+0 -82.6257828114 0 -0 0 1000 
+0 -71.7467050053 0 -0 0 1000 
+0 -74.3761207573 0 -0 0 1000 
+0 -80.1980332506 0 -0 0 1000 
+0 -77.4034971864 0 -0 0 1000 
+0 -70.8656695401 0 -0 0 1000 
+0 -82.0582091917 0 -0 0 1000 
+0 -84.1508708043 0 -0 0 1000 
+0 -72.0201920469 0 -0 0 1000 
+0 -76.9091127885 0 -0 0 1000 
+0 -82.5736864644 0 -0 0 1000 
+0 -76.8214627145 0 -0 0 1000 
+0 -70.4211020063 0 -0 0 1000 
+0 -72.7518331466 0 -0 0 1000 
+0 -77.9131278945 0 -0 0 1000 
+0 -81.7037163021 0 -0 0 1000 
+0 -73.4702490513 0 -0 0 1000 
+0 -75.8800992006 0 -0 0 1000 
+0 -84.5186373246 0 -0 0 1000 
+0 -84.6885739362 0 -0 0 1000 
+0 -79.0264353208 0 -0 0 1000 
+0 -71.1089308262 0 -0 0 1000 
+0 -78.8417121977 0 -0 0 1000 
+0 -76.6630673165 0 -0 0 1000 
+0 -77.550156882 0 -0 0 1000 
+0 -81.7785565282 0 -0 0 1000 
+0 -83.8993163371 0 -0 0 1000 
+0 -72.3327965019 0 -0 0 1000 
+0 -82.7777966218 0 -0 0 1000 
+0 -79.3465730954 0 -0 0 1000 
+0 -78.7225450521 0 -0 0 1000 
+0 -70.3098346965 0 -0 0 1000 
+0 -73.4981154131 0 -0 0 1000 
+0 -70.808496526 0 -0 0 1000 
+0 -76.5239421493 0 -0 0 1000 
+0 -80.0821145191 0 -0 0 1000 
+0 -75.3798218534 0 -0 0 1000 
+0 -83.2352166893 0 -0 0 1000 
+0 -72.5829636409 0 -0 0 1000 
+0 -72.2500238766 0 -0 0 1000 
+0 -84.0038386743 0 -0 0 1000 
+0 -75.8927976669 0 -0 0 1000 
+0 -78.741817468 0 -0 0 1000 
+0 -79.932987445 0 -0 0 1000 
+0 -84.3913999396 0 -0 0 1000 
+0 -83.3426714591 0 -0 0 1000 
+0 -82.8841064641 0 -0 0 1000 
+0 -79.6431159437 0 -0 0 1000 
+0 -72.046533959 0 -0 0 1000 
+0 -83.7462500675 0 -0 0 1000 
+0 -75.345152133 0 -0 0 1000 
+0 -71.1525776843 0 -0 0 1000 
+0 -76.7716639968 0 -0 0 1000 
+0 -78.4081501842 0 -0 0 1000 
+0 -84.2749936637 0 -0 0 1000 
+0 -79.9823180979 0 -0 0 1000 
+0 -77.7064689222 0 -0 0 1000 
+0 -72.680531147 0 -0 0 1000 
+0 -82.0828790272 0 -0 0 1000 
+0 -76.4763809058 0 -0 0 1000 
+0 -70.3868904818 0 -0 0 1000 
+0 -80.4645607633 0 -0 0 1000 
+0 -84.1662570452 0 -0 0 1000 
+0 -77.9407521075 0 -0 0 1000 
+0 -84.3429794514 0 -0 0 1000 
+0 -76.1339403878 0 -0 0 1000 
+0 -79.7391300579 0 -0 0 1000 
+0 -84.7888628356 0 -0 0 1000 
+0 -70.3364910906 0 -0 0 1000 
+0 -82.1730605586 0 -0 0 1000 
+0 -71.1860503138 0 -0 0 1000 
+0 -72.8962821772 0 -0 0 1000 
+0 -80.7827476563 0 -0 0 1000 
+0 -84.7751668794 0 -0 0 1000 
+0 -75.5815785103 0 -0 0 1000 
+0 -83.6014640998 0 -0 0 1000 
+0 -70.9728837845 0 -0 0 1000 
+0 -84.1434629821 0 -0 0 1000 
+0 -77.8238341036 0 -0 0 1000 
+0 -73.7525664564 0 -0 0 1000 
+0 -84.1944058852 0 -0 0 1000 
+0 -73.0430586401 0 -0 0 1000 
+0 -78.8686431332 0 -0 0 1000 
+0 -78.4753425023 0 -0 0 1000 
+0 -74.787880884 0 -0 0 1000 
+0 -84.9799067231 0 -0 0 1000 
+0 -72.3421444439 0 -0 0 1000 
+0 -76.5850492282 0 -0 0 1000 
+0 -82.1389992392 0 -0 0 1000 
+0 -74.1533080231 0 -0 0 1000 
+0 -80.0195883805 0 -0 0 1000 
+0 -81.7754799338 0 -0 0 1000 
+0 -77.9173337299 0 -0 0 1000 
+0 -74.4132683307 0 -0 0 1000 
+0 -78.3421173672 0 -0 0 1000 
+0 -78.4579936348 0 -0 0 1000 
+0 -71.8805656173 0 -0 0 1000 
+0 -80.9281628256 0 -0 0 1000 
+0 -72.9978442959 0 -0 0 1000 
+0 -79.788288922 0 -0 0 1000 
+0 -78.87612498 0 -0 0 1000 
+0 -70.1601191772 0 -0 0 1000 
+0 -73.2054564264 0 -0 0 1000 
+0 -72.4822876027 0 -0 0 1000 
+0 -80.417068888 0 -0 0 1000 
+0 -83.2867180337 0 -0 0 1000 
+0 -72.4354085892 0 -0 0 1000 
+0 -75.2866116457 0 -0 0 1000 
+0 -82.2772011637 0 -0 0 1000 
+0 -72.0825981385 0 -0 0 1000 
+0 -79.0036939511 0 -0 0 1000 
+0 -74.8136384477 0 -0 0 1000 
+0 -79.8491473451 0 -0 0 1000 
+0 -71.8710384456 0 -0 0 1000 
+0 -71.0349825146 0 -0 0 1000 
+0 -77.0840120478 0 -0 0 1000 
+0 -77.7111896886 0 -0 0 1000 
+0 -72.8143916435 0 -0 0 1000 
+0 -71.3650109359 0 -0 0 1000 
+0 -78.8269044509 0 -0 0 1000 
+0 -84.6426161698 0 -0 0 1000 
+0 -81.0773077315 0 -0 0 1000 
+0 -78.8265312266 0 -0 0 1000 
+0 -73.9845194934 0 -0 0 1000 
+0 -75.6672460471 0 -0 0 1000 
+0 -77.2650830553 0 -0 0 1000 
+0 -73.2195445159 0 -0 0 1000 
+0 -75.1446945081 0 -0 0 1000 
+0 -80.0603891809 0 -0 0 1000 
+0 -83.711394798 0 -0 0 1000 
+0 -78.9262483479 0 -0 0 1000 
+0 -77.8044902332 0 -0 0 1000 
+0 -72.3611285405 0 -0 0 1000 
+0 -74.318453658 0 -0 0 1000 
+0 -71.3060260466 0 -0 0 1000 
+0 -78.5469997696 0 -0 0 1000 
+0 -79.5404617192 0 -0 0 1000 
+0 -73.5946736392 0 -0 0 1000 
+0 -79.5484435501 0 -0 0 1000 
+0 -83.8200107459 0 -0 0 1000 
+0 -73.603099395 0 -0 0 1000 
+0 -72.5998878393 0 -0 0 1000 
+0 -73.8157568683 0 -0 0 1000 
+0 -79.0435039984 0 -0 0 1000 
+0 -83.0788230751 0 -0 0 1000 
+0 -76.7086281687 0 -0 0 1000 
+0 -74.1546610065 0 -0 0 1000 
+0 -72.0762748411 0 -0 0 1000 
+0 -74.3861027112 0 -0 0 1000 
+0 -73.4038553676 0 -0 0 1000 
+0 -77.5743428977 0 -0 0 1000 
+0 -74.5513521882 0 -0 0 1000 
+0 -78.7396434288 0 -0 0 1000 
+0 -80.8857188391 0 -0 0 1000 
+0 -80.7893756425 0 -0 0 1000 
+0 -74.4846242243 0 -0 0 1000 
+0 -80.703771248 0 -0 0 1000 
+0 -77.744513977 0 -0 0 1000 
+0 -77.7172732522 0 -0 0 1000 
+0 -81.6885397944 0 -0 0 1000 
+0 -70.2598068371 0 -0 0 1000 
+0 -83.6291831676 0 -0 0 1000 
+0 -77.847903169 0 -0 0 1000 
+0 -70.5284500295 0 -0 0 1000 
+0 -78.2181656049 0 -0 0 1000 
+0 -71.0207957854 0 -0 0 1000 
+0 -76.9023421738 0 -0 0 1000 
+0 -84.1667177438 0 -0 0 1000 
+0 -70.3408383625 0 -0 0 1000 
+0 -72.3758876002 0 -0 0 1000 
+0 -71.749698948 0 -0 0 1000 
+0 -83.7009106444 0 -0 0 1000 
+0 -78.7887509309 0 -0 0 1000 
+0 -72.9719113847 0 -0 0 1000 
+0 -84.7200775824 0 -0 0 1000 
+0 -70.147091203 0 -0 0 1000 
+0 -71.6285000029 0 -0 0 1000 
+0 -76.4040434583 0 -0 0 1000 
+0 -72.2490098018 0 -0 0 1000 
+0 -81.5054289626 0 -0 0 1000 
+0 -80.5469678486 0 -0 0 1000 
+0 -77.4400257516 0 -0 0 1000 
+0 -71.1127536527 0 -0 0 1000 
+0 -75.7092228941 0 -0 0 1000 
+0 -75.5688066414 0 -0 0 1000 
+0 -84.631545024 0 -0 0 1000 
+0 -78.4048819387 0 -0 0 1000 
+0 -73.9641900088 0 -0 0 1000 
+0 -70.1548558453 0 -0 0 1000 
+0 -70.9539304433 0 -0 0 1000 
+0 -80.293228868 0 -0 0 1000 
+0 -76.2749345635 0 -0 0 1000 
+0 -83.2989398015 0 -0 0 1000 
+0 -78.7508831336 0 -0 0 1000 
+0 -77.5538172333 0 -0 0 1000 
+0 -84.1003676981 0 -0 0 1000 
+0 -72.1215389467 0 -0 0 1000 
+0 -81.300856853 0 -0 0 1000 
+0 -83.8667650691 0 -0 0 1000 
+0 -71.4281330185 0 -0 0 1000 
+0 -72.4825135518 0 -0 0 1000 
+0 -81.5030329608 0 -0 0 1000 
+0 -70.9809091583 0 -0 0 1000 
+0 -83.7865673012 0 -0 0 1000 
+0 -84.5679850481 0 -0 0 1000 
+0 -72.0631456136 0 -0 0 1000 
+0 -83.602147079 0 -0 0 1000 
+0 -81.076269961 0 -0 0 1000 
+0 -84.5308734684 0 -0 0 1000 
+0 -75.4054099842 0 -0 0 1000 
+0 -83.3690787309 0 -0 0 1000 
+0 -79.6849779998 0 -0 0 1000 
+0 -73.6283018453 0 -0 0 1000 
+0 -81.5623075486 0 -0 0 1000 
+0 -75.5728365448 0 -0 0 1000 
+0 -82.310277658 0 -0 0 1000 
+0 -72.9655861269 0 -0 0 1000 
+0 -72.9179334447 0 -0 0 1000 
+0 -78.521069896 0 -0 0 1000 
+0 -71.7439877306 0 -0 0 1000 
+0 -84.7549338645 0 -0 0 1000 
+0 -84.7750818849 0 -0 0 1000 
+0 -73.1945577031 0 -0 0 1000 
+0 -71.6372053045 0 -0 0 1000 
+0 -80.7720031563 0 -0 0 1000 
+0 -74.856431913 0 -0 0 1000 
+0 -81.2951528334 0 -0 0 1000 
+0 -75.8615203262 0 -0 0 1000 
+0 -73.5554766572 0 -0 0 1000 
+0 -84.5644177519 0 -0 0 1000 
+0 -72.0226268355 0 -0 0 1000 
+0 -76.4834137427 0 -0 0 1000 
+0 -82.4697604502 0 -0 0 1000 
+0 -74.8440708986 0 -0 0 1000 
+0 -80.1730227383 0 -0 0 1000 
+0 -77.8771127766 0 -0 0 1000 
+0 -76.4304257868 0 -0 0 1000 
+0 -74.0028753047 0 -0 0 1000 
+0 -79.0405012446 0 -0 0 1000 
+0 -82.9960690175 0 -0 0 1000 
+0 -80.2832996946 0 -0 0 1000 
+0 -78.7291777435 0 -0 0 1000 
+0 -81.3871706856 0 -0 0 1000 
+0 -78.012758245 0 -0 0 1000 
+0 -82.2040297961 0 -0 0 1000 
+0 -84.6567631217 0 -0 0 1000 
+0 -73.5704376436 0 -0 0 1000 
+0 -74.2068080583 0 -0 0 1000 
+0 -73.233975932 0 -0 0 1000 
+0 -74.1917843588 0 -0 0 1000 
+0 -79.0750422511 0 -0 0 1000 
+0 -78.2467982854 0 -0 0 1000 
+0 -80.1445179079 0 -0 0 1000 
+0 -71.446398841 0 -0 0 1000 
+0 -80.8678139138 0 -0 0 1000 
+0 -83.5638325918 0 -0 0 1000 
+0 -73.1950414454 0 -0 0 1000 
+0 -82.2114036724 0 -0 0 1000 
+0 -81.4985886285 0 -0 0 1000 
+0 -84.8756555229 0 -0 0 1000 
+0 -77.2553247724 0 -0 0 1000 
+0 -73.1012003082 0 -0 0 1000 
+0 -72.9225822478 0 -0 0 1000 
+0 -83.6873202001 0 -0 0 1000 
+0 -82.9517728084 0 -0 0 1000 
+0 -83.6750009689 0 -0 0 1000 
+0 -70.9703540386 0 -0 0 1000 
+0 -74.6949558665 0 -0 0 1000 
+0 -83.4855361402 0 -0 0 1000 
+0 -78.2878848264 0 -0 0 1000 
+0 -83.9844857591 0 -0 0 1000 
+0 -83.9579242549 0 -0 0 1000 
+0 -78.0912345081 0 -0 0 1000 
+0 -76.1668166175 0 -0 0 1000 
+0 -74.7610322925 0 -0 0 1000 
+0 -80.814597142 0 -0 0 1000 
+0 -77.5556308976 0 -0 0 1000 
+0 -71.2058744071 0 -0 0 1000 
+0 -70.8530846992 0 -0 0 1000 
+0 -83.209267266 0 -0 0 1000 
+0 -82.1096491134 0 -0 0 1000 
+0 -82.900641993 0 -0 0 1000 
+0 -80.9284644336 0 -0 0 1000 
+0 -73.1115788403 0 -0 0 1000 
+0 -73.4236964694 0 -0 0 1000 
+0 -76.8160752345 0 -0 0 1000 
+0 -80.0293024894 0 -0 0 1000 
+0 -80.3627150007 0 -0 0 1000 
+0 -77.4700705207 0 -0 0 1000 
+0 -77.8303457095 0 -0 0 1000 
+0 -71.704338444 0 -0 0 1000 
+0 -73.7199154913 0 -0 0 1000 
+0 -83.0276461501 0 -0 0 1000 
+0 -74.8975198709 0 -0 0 1000 
+0 -80.412115833 0 -0 0 1000 
+0 -71.3163515373 0 -0 0 1000 
+0 -74.4690333728 0 -0 0 1000 
+0 -73.205892599 0 -0 0 1000 
+0 -77.8023910643 0 -0 0 1000 
+0 -79.7587139866 0 -0 0 1000 
+0 -79.8305684939 0 -0 0 1000 
+0 -73.8109310378 0 -0 0 1000 
+0 -76.3421772386 0 -0 0 1000 
+0 -84.7799582333 0 -0 0 1000 
+0 -79.6780783098 0 -0 0 1000 
+0 -78.2297931784 0 -0 0 1000 
+0 -79.7707008375 0 -0 0 1000 
+0 -73.7075029841 0 -0 0 1000 
+0 -79.8691904504 0 -0 0 1000 
+0 -79.1890861264 0 -0 0 1000 
+0 -76.4435723476 0 -0 0 1000 
+0 -83.033932398 0 -0 0 1000 
+0 -81.4145292718 0 -0 0 1000 
+0 -80.0128666613 0 -0 0 1000 
+0 -82.300700552 0 -0 0 1000 
+0 -76.4521603435 0 -0 0 1000 
+0 -82.4595374989 0 -0 0 1000 
+0 -79.7709318979 0 -0 0 1000 
+0 -73.8955785207 0 -0 0 1000 
+0 -70.782464274 0 -0 0 1000 
+0 -76.1656256374 0 -0 0 1000 
+0 -75.7283958848 0 -0 0 1000 
+0 -84.2268263197 0 -0 0 1000 
+0 -84.0452923512 0 -0 0 1000 
+0 -81.4492255966 0 -0 0 1000 
+0 -77.24971915 0 -0 0 1000 
+0 -83.4782051998 0 -0 0 1000 
+0 -81.3699237424 0 -0 0 1000 
+0 -77.1410885439 0 -0 0 1000 
+0 -82.7201978323 0 -0 0 1000 
+0 -75.8032595864 0 -0 0 1000 
+0 -81.6516763075 0 -0 0 1000 
+0 -79.9224213157 0 -0 0 1000 
+0 -74.3149974381 0 -0 0 1000 
+0 -79.9784606276 0 -0 0 1000 
+0 -79.6342909818 0 -0 0 1000 
+0 -79.1614272958 0 -0 0 1000 
+0 -76.3328287455 0 -0 0 1000 
+0 -70.7280074391 0 -0 0 1000 
+0 -81.9823858604 0 -0 0 1000 
+0 -81.5613581106 0 -0 0 1000 
+0 -75.0341302499 0 -0 0 1000 
+0 -81.3187035657 0 -0 0 1000 
+0 -79.5825981207 0 -0 0 1000 
+0 -72.9027683343 0 -0 0 1000 
+0 -73.4010881346 0 -0 0 1000 
+0 -78.2996056303 0 -0 0 1000 
+0 -70.7604762841 0 -0 0 1000 
+0 -75.4473982166 0 -0 0 1000 
+0 -79.3410613478 0 -0 0 1000 
+0 -73.0741027169 0 -0 0 1000 
+0 -82.8907317373 0 -0 0 1000 
+0 -76.1137158 0 -0 0 1000 
+0 -72.6611813034 0 -0 0 1000 
+0 -81.0380178086 0 -0 0 1000 
+0 -83.4066147109 0 -0 0 1000 
+0 -77.9449812438 0 -0 0 1000 
+0 -83.6783833045 0 -0 0 1000 
+0 -78.8831406193 0 -0 0 1000 
+0 -80.9535788734 0 -0 0 1000 
+0 -79.7957292842 0 -0 0 1000 
+0 -81.8273453221 0 -0 0 1000 
+0 -70.0788435031 0 -0 0 1000 
+0 -80.1847981395 0 -0 0 1000 
+0 -75.4534020945 0 -0 0 1000 
+0 -82.7733295683 0 -0 0 1000 
+0 -73.6232628421 0 -0 0 1000 
+0 -78.8413820395 0 -0 0 1000 
+0 -78.4957309278 0 -0 0 1000 
+0 -84.7154386924 0 -0 0 1000 
+0 -79.6587364724 0 -0 0 1000 
+0 -81.5063098541 0 -0 0 1000 
+0 -80.2342123927 0 -0 0 1000 
+0 -78.1191317094 0 -0 0 1000 
+0 -73.1231873761 0 -0 0 1000 
+0 -79.0543015035 0 -0 0 1000 
+0 -80.7981305884 0 -0 0 1000 
+0 -75.5889402602 0 -0 0 1000 
+0 -73.0499740937 0 -0 0 1000 
+0 -80.9543227023 0 -0 0 1000 
+0 -73.2261411776 0 -0 0 1000 
+0 -76.9802538114 0 -0 0 1000 
+0 -80.6140531736 0 -0 0 1000 
+0 -71.4095659659 0 -0 0 1000 
+0 -78.8231843577 0 -0 0 1000 
+0 -71.8529982464 0 -0 0 1000 
+0 -80.3734075264 0 -0 0 1000 
+0 -80.8620654899 0 -0 0 1000 
+0 -72.744782176 0 -0 0 1000 
+0 -71.6433362799 0 -0 0 1000 
+0 -71.0835008546 0 -0 0 1000 
+0 -72.7442255371 0 -0 0 1000 
+0 -79.0395782764 0 -0 0 1000 
+0 -75.3286155764 0 -0 0 1000 
+0 -73.8215614512 0 -0 0 1000 
+0 -73.9542265671 0 -0 0 1000 
+0 -76.2308965301 0 -0 0 1000 
+0 -82.1952516602 0 -0 0 1000 
+0 -80.1899426616 0 -0 0 1000 
+0 -71.3714037464 0 -0 0 1000 
+0 -70.9813556541 0 -0 0 1000 
+0 -76.6017530031 0 -0 0 1000 
+0 -77.9574412431 0 -0 0 1000 
+0 -84.644276489 0 -0 0 1000 
+0 -78.7590314204 0 -0 0 1000 
+0 -77.3254953613 0 -0 0 1000 
+0 -79.4186928026 0 -0 0 1000 
+0 -76.3890781224 0 -0 0 1000 
+0 -75.5227829646 0 -0 0 1000 
+0 -71.36107683 0 -0 0 1000 
+0 -81.9196445057 0 -0 0 1000 
+0 -75.0696494483 0 -0 0 1000 
+0 -81.8472565864 0 -0 0 1000 
+0 -81.522204501 0 -0 0 1000 
+0 -73.71729339 0 -0 0 1000 
+0 -76.0078016999 0 -0 0 1000 
+0 -75.2094758505 0 -0 0 1000 
+0 -72.2132733525 0 -0 0 1000 
+0 -76.5606629497 0 -0 0 1000 
+0 -83.8422309908 0 -0 0 1000 
+0 -79.2191723073 0 -0 0 1000 
+0 -83.5594183963 0 -0 0 1000 
+0 -81.9342852413 0 -0 0 1000 
+0 -72.0374106171 0 -0 0 1000 
+0 -80.7700833322 0 -0 0 1000 
+0 -74.1962974513 0 -0 0 1000 
+0 -72.7727996672 0 -0 0 1000 
+0 -74.7933573342 0 -0 0 1000 
+0 -82.5609439726 0 -0 0 1000 
+0 -75.3577645379 0 -0 0 1000 
+0 -84.0038368721 0 -0 0 1000 
+0 -84.5526457845 0 -0 0 1000 
+0 -75.3400548801 0 -0 0 1000 
+0 -77.0986180793 0 -0 0 1000 
+0 -82.5149159109 0 -0 0 1000 
+0 -78.7005394271 0 -0 0 1000 
+0 -74.9889699295 0 -0 0 1000 
+0 -77.1415741989 0 -0 0 1000 
+0 -81.9680590749 0 -0 0 1000 
+0 -71.5437494136 0 -0 0 1000 
+0 -81.1174915697 0 -0 0 1000 
+0 -72.7364687006 0 -0 0 1000 
+0 -71.3432605539 0 -0 0 1000 
+0 -83.097382693 0 -0 0 1000 
+0 -72.8978908611 0 -0 0 1000 
+0 -84.3125021397 0 -0 0 1000 
+0 -79.6094965371 0 -0 0 1000 
+0 -83.050480011 0 -0 0 1000 
+0 -72.1408091043 0 -0 0 1000 
+0 -75.5413060502 0 -0 0 1000 
+0 -75.570924465 0 -0 0 1000 
+0 -83.7886812217 0 -0 0 1000 
+0 -83.094000508 0 -0 0 1000 
+0 -83.6130451862 0 -0 0 1000 
+0 -72.6782020172 0 -0 0 1000 
+0 -77.8766222529 0 -0 0 1000 
+0 -71.6289170496 0 -0 0 1000 
+0 -75.1661258959 0 -0 0 1000 
+0 -73.5330010991 0 -0 0 1000 
+0 -81.6194229784 0 -0 0 1000 
+0 -71.6357191119 0 -0 0 1000 
+0 -75.9629247678 0 -0 0 1000 
+0 -83.4409626586 0 -0 0 1000 
+0 -78.486950969 0 -0 0 1000 
+0 -77.856845189 0 -0 0 1000 
+0 -75.3319797962 0 -0 0 1000 
+0 -73.8183236639 0 -0 0 1000 
+0 -79.3794504158 0 -0 0 1000 
+0 -78.6006425192 0 -0 0 1000 
+0 -70.817118816 0 -0 0 1000 
+0 -79.5546620839 0 -0 0 1000 
+0 -76.0997412766 0 -0 0 1000 
+0 -83.8532244703 0 -0 0 1000 
+0 -73.8049821617 0 -0 0 1000 
+0 -83.7436882868 0 -0 0 1000 
+0 -76.4647786871 0 -0 0 1000 
+0 -79.077781448 0 -0 0 1000 
+0 -72.016398737 0 -0 0 1000 
+0 -83.0714259744 0 -0 0 1000 
+0 -78.3052997179 0 -0 0 1000 
+0 -83.3007565775 0 -0 0 1000 
+0 -74.2192922386 0 -0 0 1000 
+0 -73.7927616676 0 -0 0 1000 
+0 -78.0620814687 0 -0 0 1000 
+0 -70.0439569818 0 -0 0 1000 
+0 -82.8795474827 0 -0 0 1000 
+0 -70.7201129025 0 -0 0 1000 
+0 -75.7646240676 0 -0 0 1000 
+0 -72.8967827219 0 -0 0 1000 
+0 -71.4430009457 0 -0 0 1000 
+0 -78.2194107671 0 -0 0 1000 
+0 -81.174612216 0 -0 0 1000 
+0 -80.424919917 0 -0 0 1000 
+0 -73.7210050586 0 -0 0 1000 
+0 -76.4768762475 0 -0 0 1000 
+10 -72.672182289 10 -726.72182289 52812.4607864 1295.89425836 
+10 -70.0882888127 10 -700.882888127 49123.6822869 1278.09633923 
+10 -78.3215478099 10 -783.215478099 61342.6485135 1337.13285561 
+10 -78.5239811418 10 -785.239811418 61660.1561436 1338.66978543 
+10 -81.7658364852 10 -817.658364852 66856.5201613 1363.84114168 
+10 -72.5646131544 10 -725.646131544 52656.2308225 1295.14000082 
+10 -83.0685081193 10 -830.685081193 69003.7704117 1374.25172503 
+10 -81.8369370869 10 -818.369370869 66972.8427176 1364.40497932 
+10 -72.7029339282 10 -727.029339282 52857.1660177 1296.11009661 
+10 -79.5341607257 10 -795.341607257 63256.8272234 1346.40059594 
+10 -77.9272385559 10 -779.272385559 60726.5450895 1334.15091581 
+10 -75.0510895994 10 -750.510895994 56326.6605006 1312.8705301 
+10 -80.6613087711 10 -806.613087711 65062.4673267 1355.14700944 
+10 -82.5300978863 10 -825.300978863 68112.1705713 1369.92832838 
+10 -84.602360614 10 -846.02360614 71575.5942146 1386.72738092 
+10 -73.1303720184 10 -731.303720184 53480.5131155 1299.11997257 
+10 -73.1061000528 10 -731.061000528 53445.0186492 1298.94856823 
+10 -76.8672299556 10 -768.672299556 59085.7104105 1326.21174456 
+10 -71.8936292196 10 -718.936292196 51686.9392237 1290.46128881 
+10 -77.5287859103 10 -775.287859103 60107.1264473 1331.15343576 
+10 -75.6198351178 10 -756.198351178 57183.5946324 1317.01301438 
+10 -84.1650158928 10 -841.650158928 70837.4990024 1383.14624104 
+10 -75.241292757 10 -752.41292757 56612.5213574 1314.2522836 
+10 -73.6866339301 10 -736.866339301 54297.2001995 1303.06434251 
+10 -79.4568206474 10 -794.568206474 63133.8634739 1345.80511221 
+10 -74.3296264954 10 -743.296264954 55248.9337494 1307.66226212 
+10 -72.0199879673 10 -720.199879673 51868.786668 1291.33893635 
+10 -82.9714773754 10 -829.714773754 68842.6605786 1373.47043355 
+10 -83.1617205766 10 -831.617205766 69158.7176927 1375.00315832 
+10 -77.5710618255 10 -775.710618255 60172.6963274 1331.47071618 
+10 -70.8594359123 10 -708.594359123 50210.5965781 1283.33812391 
+10 -76.6456877993 10 -766.456877993 58745.6145823 1324.56665096 
+10 -77.3317211984 10 -773.317211984 59801.9510351 1329.67682488 
+10 -84.6371823523 10 -846.371823523 71634.5263654 1387.01333624 
+10 -74.0937411137 10 -740.937411137 54898.8247223 1305.97068833 
+10 -79.0027991103 10 -790.027991103 62414.4226727 1342.32141359 
+10 -81.3249083953 10 -813.249083953 66137.4072551 1360.35580918 
+10 -76.7447909177 10 -767.447909177 58897.62933 1325.30194892 
+10 -79.8347612915 10 -798.347612915 63735.8911047 1348.7207652 
+10 -71.7380576622 10 -717.380576622 51463.4891715 1289.38293144 
+10 -84.8355430058 10 -848.355430058 71970.6935708 1388.6445821 
+10 -71.9921056713 10 -719.921056713 51828.6327899 1291.14513753 
+10 -84.7977551473 10 -847.977551473 71906.5927803 1388.33352511 
+10 -72.3196519704 10 -723.196519704 52301.3206111 1293.42669006 
+10 -78.5090756352 10 -785.090756352 61636.7495709 1338.55647895 
+10 -78.4261891221 10 -784.261891221 61506.6714022 1337.92680973 
+10 -71.0014006785 10 -710.014006785 50411.9889831 1284.30959475 
+10 -71.4117449594 10 -714.117449594 50996.3731815 1287.12892967 
+10 -81.473374577 10 -814.73374577 66379.1076496 1361.5271946 
+10 -82.507871998 10 -825.07871998 68075.4894163 1369.75047908 
+10 -84.6445018796 10 -846.445018796 71646.9169844 1387.07345945 
+10 -80.7149191025 10 -807.149191025 65148.9816573 1355.56617851 
+10 -78.9632577272 10 -789.632577272 62351.9607089 1342.01898911 
+10 -84.8257842424 10 -848.257842424 71954.1367234 1388.56423756 
+10 -76.6065877065 10 -766.065877065 58685.6928003 1324.27681707 
+10 -83.2708925253 10 -832.708925253 69340.4154197 1375.88435397 
+10 -84.3366542693 10 -843.366542693 71126.7125333 1384.5493991 
+10 -80.4362557777 10 -804.362557777 64699.9124353 1353.39049823 
+10 -77.1105991521 10 -771.105991521 59460.445016 1328.02457529 
+10 -77.8039111735 10 -778.039111735 60534.485939 1333.2214519 
+10 -77.2743322884 10 -772.743322884 59713.2243061 1329.24753846 
+10 -81.7886781834 10 -817.886781834 66893.8787899 1364.0222244 
+10 -77.5575285244 10 -775.575285244 60151.7023081 1331.36912941 
+10 -76.9092325513 10 -769.092325513 59150.3005163 1326.52419444 
+10 -76.9509971576 10 -769.509971576 59214.5596355 1326.83504889 
+10 -71.493651749 10 -714.93651749 51113.4224041 1287.69369908 
+10 -76.5329148447 10 -765.329148447 58572.8705463 1323.73112402 
+10 -72.3583793846 10 -723.583793846 52357.3506717 1293.69715851 
+10 -82.4217003333 10 -824.217003333 67933.3668584 1369.06140921 
+10 -81.126732011 10 -811.26732011 65815.4664678 1358.79564934 
+10 -82.5843310041 10 -825.843310041 68201.717274 1370.36250362 
+10 -78.8707709147 10 -788.707709147 62205.9850468 1341.31223251 
+10 -79.4200319207 10 -794.200319207 63075.4147028 1345.52206553 
+10 -75.2723124517 10 -752.723124517 56659.2102183 1314.47797298 
+10 -74.8713672409 10 -748.713672409 56057.2163252 1311.56823982 
+10 -73.9419744477 10 -739.419744477 54674.1558522 1304.88528565 
+10 -71.5777608288 10 -715.777608288 51233.7584526 1288.27435206 
+10 -81.3042370732 10 -813.042370732 66103.7896605 1360.19288903 
+10 -74.942191951 10 -749.42191951 56163.3213443 1312.08105873 
+10 -74.6508243296 10 -746.508243296 55727.4557309 1309.97457257 
+10 -70.6918163473 10 -706.918163473 49973.3289848 1282.19369084 
+10 -75.1918546327 10 -751.918546327 56538.1500311 1313.8927865 
+10 -70.1437501206 10 -701.437501206 49201.4568098 1278.47134652 
+10 -83.3623187587 10 -833.623187587 69492.7618883 1376.62322975 
+10 -79.8542823499 10 -798.542823499 63767.0640962 1348.87174989 
+10 -74.3977569962 10 -743.977569962 55350.2624607 1308.15187305 
+10 -79.9293620926 10 -799.293620926 63887.0292453 1349.4528057 
+10 -81.3624408363 10 -813.624408363 66198.4677884 1360.65172873 
+10 -74.8730328799 10 -748.730328799 56059.7105264 1311.58029441 
+10 -81.6973638961 10 -816.973638961 66744.5926757 1363.2986224 
+10 -77.194356261 10 -771.94356261 59589.6863855 1328.64984286 
+10 -70.3073980672 10 -703.073980672 49431.3022298 1279.57966163 
+10 -84.6215334121 10 -846.215334121 71608.0391701 1386.8848125 
+10 -84.2674269338 10 -842.674269338 71009.9924204 1383.98310537 
+10 -73.806978934 10 -738.06978934 54474.7013936 1303.92176223 
+10 -73.93639821 10 -739.3639821 54665.9098026 1304.84544946 
+10 -73.5210484238 10 -735.210484238 54053.4456133 1301.88696596 
+10 -72.4426535045 10 -724.426535045 52479.3804678 1294.28623896 
+10 -79.4708683405 10 -794.708683405 63156.1891479 1345.91322865 
+10 -76.4177680032 10 -764.177680032 58396.7526659 1322.87932133 
+10 -71.860040861 10 -718.60040861 51638.6547254 1290.22826341 
+10 -81.1748480078 10 -811.748480078 65893.559491 1359.17408545 
+10 -74.6726778805 10 -746.726778805 55760.0882184 1310.13227162 
+10 -71.4973889307 10 -714.973889307 51118.7662391 1287.71948396 
+10 -84.7550554621 10 -847.550554621 71834.1942638 1387.98220745 
+10 -82.0107098038 10 -820.107098038 67257.5652253 1365.78514868 
+10 -73.6529315516 10 -736.529315516 54247.5432615 1302.82448342 
+10 -74.9611098854 10 -749.611098854 56191.6799525 1312.21812229 
+10 -82.2441035204 10 -822.441035204 67640.9256387 1367.64360231 
+10 -81.6618164432 10 -816.618164432 66686.5226481 1363.01715913 
+10 -83.4619623397 10 -834.619623397 69658.9915759 1377.42946729 
+10 -83.8646644204 10 -838.646644204 70332.8193835 1380.69793081 
+10 -72.8448943317 10 -728.448943317 53063.786302 1297.10770793 
+10 -78.3180833029 10 -783.180833029 61337.2217225 1337.10658779 
+10 -77.3010175424 10 -773.010175424 59754.4731309 1329.44711127 
+10 -83.2219592975 10 -832.219592975 69258.9450932 1375.48923564 
+10 -76.3016961057 10 -763.016961057 58219.4882861 1322.0220174 
+10 -84.3644784611 10 -843.644784611 71173.6522601 1384.77714169 
+10 -83.5296338286 10 -835.296338286 69771.9972754 1377.97757792 
+10 -75.9623253138 10 -759.623253138 57702.7486708 1319.52316203 
+10 -78.6597893243 10 -786.597893243 61873.6245654 1339.7031755 
+10 -78.2259610057 10 -782.259610057 61193.0097526 1336.40855851 
+10 -83.1756346179 10 -831.756346179 69181.8619409 1375.11540105 
+10 -80.6969699803 10 -806.969699803 65120.00964 1355.4258057 
+10 -71.0471562263 10 -710.471562263 50476.9840785 1284.62313134 
+10 -82.5791035571 10 -825.791035571 68193.083443 1370.32064133 
+10 -80.1981534245 10 -801.981534245 64317.438127 1351.53765228 
+10 -70.2926085936 10 -702.926085936 49410.5082289 1279.479389 
+10 -76.9891140923 10 -769.891140923 59273.2368871 1327.11890591 
+10 -71.0378821521 10 -710.378821521 50463.8070066 1284.55956449 
+10 -77.5146344459 10 -775.146344459 60085.1855328 1331.04726905 
+10 -75.1948646519 10 -751.948646519 56542.6767002 1313.91466734 
+10 -84.9410551116 10 -849.410551116 72149.8284347 1389.5138784 
+10 -72.8185203551 10 -728.185203551 53025.3690671 1296.92221525 
+10 -82.2506262085 10 -822.506262085 67651.6551168 1367.69561903 
+10 -79.5249364831 10 -795.249364831 63242.1552264 1346.32954201 
+10 -81.2834346503 10 -812.834346503 66069.9674855 1360.02897876 
+10 -80.5025360904 10 -805.025360904 64806.5831698 1353.90728183 
+10 -78.3503108236 10 -783.503108236 61387.7120616 1337.3509826 
+10 -74.9802634298 10 -749.802634298 56220.39904 1312.35692934 
+10 -73.8959105075 10 -738.959105075 54606.0558973 1304.55630186 
+10 -80.3023607865 10 -803.023607865 64484.6914789 1352.3478672 
+10 -70.5931706657 10 -705.931706657 49833.9574464 1281.52149457 
+10 -77.6841560502 10 -776.841560502 60348.2810124 1332.32036605 
+10 -74.8064610757 10 -748.064610757 55960.0661866 1311.09871566 
+10 -73.6598075621 10 -736.598075621 54257.6725009 1302.87341061 
+10 -83.8981813741 10 -838.981813741 70389.0483788 1380.97069655 
+10 -78.1718695904 10 -781.718695904 61108.4119525 1335.99909237 
+10 -73.3169080034 10 -733.169080034 53753.6899918 1300.43922296 
+10 -72.3096099119 10 -723.096099119 52286.7968562 1293.3565818 
+10 -80.2147553178 10 -802.147553178 64344.069707 1351.66665971 
+10 -74.3833125414 10 -743.833125414 55328.7718463 1308.0480311 
+10 -79.5371718239 10 -795.371718239 63261.6170174 1346.42379213 
+10 -73.3692112474 10 -733.692112474 53830.4115907 1300.80975514 
+10 -75.1557883543 10 -751.557883543 56483.9252316 1313.63067907 
+10 -70.7080314656 10 -707.080314656 49996.2571374 1282.30427782 
+10 -74.8435548623 10 -748.435548623 56015.5770442 1311.36699651 
+10 -83.5885602602 10 -835.885602602 69870.4740637 1378.45523025 
+10 -75.1321551741 10 -751.321551741 56448.407411 1313.45899826 
+10 -77.0394635248 10 -770.394635248 59350.7894019 1327.49408113 
+10 -80.4162573875 10 -804.162573875 64667.7445221 1353.23465826 
+10 -80.642083977 10 -806.42083977 65031.4570815 1354.99676441 
+10 -71.1125500695 10 -711.125500695 50569.9477739 1285.07160135 
+10 -76.3264883377 10 -763.264883377 58257.3282196 1322.20501901 
+10 -71.5411982377 10 -715.411982377 51181.4304528 1288.0218527 
+10 -74.5671211251 10 -745.671211251 55602.5555289 1309.37099736 
+10 -77.2235009035 10 -772.235009035 59634.6909179 1328.86757936 
+10 -76.0354549862 10 -760.354549862 57813.9041496 1320.060657 
+10 -77.6921628401 10 -776.921628401 60360.7216678 1332.38056763 
+10 -82.9623795827 10 -829.623795827 68827.5642603 1373.39722641 
+10 -79.3906396993 10 -793.906396993 63028.7367186 1345.29602367 
+10 -76.1701472557 10 -761.701472557 58018.9133296 1321.05202983 
+10 -81.780597476 10 -817.80597476 66880.6612354 1363.95815681 
+10 -72.9355348223 10 -729.355348223 53195.9223981 1297.74572829 
+10 -78.7259639391 10 -787.259639391 61977.7739814 1340.20737892 
+10 -72.3462445817 10 -723.462445817 52339.7910508 1293.61239411 
+10 -84.1893916179 10 -841.893916179 70878.5366099 1383.34533514 
+10 -70.62563792 10 -706.2563792 49879.8073161 1281.7426271 
+10 -84.7120636554 10 -847.120636554 71761.3372876 1387.62867052 
+10 -71.8270267605 10 -718.270267605 51591.2177325 1289.99933197 
+10 -74.9392480133 10 -749.392480133 56158.908928 1312.05973264 
+10 -82.2839034689 10 -822.839034689 67706.4077008 1367.96106264 
+10 -74.701441041 10 -747.01441041 55803.0529361 1310.33990442 
+10 -81.2352713157 10 -812.352713157 65991.6930574 1359.64964746 
+10 -82.2953657053 10 -822.953657053 67725.2721658 1368.0525194 
+10 -74.7516761566 10 -747.516761566 55878.1308821 1310.70273537 
+10 -72.3185569033 10 -723.185569033 52299.7367258 1293.4190444 
+10 -83.8400425665 10 -838.400425665 70291.5273755 1380.49762624 
+10 -76.3599121883 10 -763.599121883 58308.361894 1322.45183142 
+10 -82.8685314155 10 -828.685314155 68671.9349897 1372.64254209 
+10 -80.9586721557 10 -809.586721557 65543.0659722 1357.47566182 
+10 -79.2445349734 10 -792.445349734 62796.9632315 1344.17368241 
+10 -72.3420202041 10 -723.420202041 52333.6788721 1293.58288931 
+10 -73.0337769872 10 -730.337769872 53339.3258102 1298.4381848 
+10 -78.3586079904 10 -783.586079904 61400.7144619 1337.41392031 
+10 -77.9810993122 10 -779.810993122 60810.5184994 1334.55731767 
+10 -79.7098201078 10 -797.098201078 63536.5542162 1347.75531605 
+10 -79.2539400175 10 -792.539400175 62811.870083 1344.24586541 
+10 -84.7610457214 10 -847.610457214 71844.3487179 1388.03148216 
+10 -74.8514627013 10 -748.514627013 56027.4146852 1311.42420775 
+10 -79.8444430748 10 -798.444430748 63751.3508993 1348.79564373 
+10 -82.4756249944 10 -824.756249944 68022.2871822 1369.49252966 
+10 -79.2998718383 10 -792.998718383 62884.6967358 1344.59851572 
+10 -78.8739915529 10 -788.739915529 62211.0654349 1341.33682929 
+10 -81.9982615105 10 -819.982615105 67237.1489074 1365.68617916 
+10 -82.531512999 10 -825.31512999 68114.5063791 1369.93965365 
+10 -75.1464158836 10 -751.464158836 56469.8382014 1313.56258704 
+10 -80.8463041897 10 -808.463041897 65361.2490114 1356.59466901 
+10 -78.7512536565 10 -787.512536565 62017.5995247 1340.40018421 
+10 -72.3369689382 10 -723.369689382 52326.3707516 1293.54761152 
+10 -77.6254236688 10 -776.254236688 60257.0639976 1331.87896407 
+10 -74.8719062317 10 -748.719062317 56058.0234277 1311.57214058 
+10 -75.0307973893 10 -750.307973893 56296.2055687 1312.7233285 
+10 -76.0510822242 10 -760.510822242 57837.6710747 1320.17558482 
+10 -76.8385763948 10 -768.385763948 59041.6682238 1325.99869702 
+10 -83.6957109763 10 -836.957109763 70049.7203582 1379.32467405 
+10 -81.4600463792 10 -814.600463792 66357.391561 1361.42194621 
+10 -80.2599643206 10 -802.599643206 64416.6187275 1352.01810256 
+10 -76.4287527437 10 -764.287527437 58413.5424596 1322.96052411 
+10 -79.4478579282 10 -794.478579282 63119.6212939 1345.73614199 
+10 -82.0050779448 10 -820.050779448 67248.3280873 1365.74037095 
+10 -73.1183652514 10 -731.183652514 53462.9533703 1299.03517554 
+10 -81.5396062878 10 -815.396062878 66487.0739357 1362.05046811 
+10 -76.9013194487 10 -769.013194487 59138.1293295 1326.46531679 
+10 -78.8561088977 10 -788.561088977 62182.8591049 1341.2002683 
+10 -70.0803771344 10 -700.803771344 49112.592593 1278.04286868 
+10 -71.0350899146 10 -710.350899146 50459.8399918 1284.54042748 
+10 -72.740177246 10 -727.40177246 52911.3338578 1296.37162498 
+10 -74.2862612542 10 -742.862612542 55184.4861113 1307.35086524 
+10 -77.9090176111 10 -779.090176111 60698.1502513 1334.01349685 
+10 -82.8581227213 10 -828.581227213 68654.685009 1372.55889436 
+10 -76.6365711912 10 -766.365711912 58731.6404395 1324.4990594 
+10 -80.0437566891 10 -800.437566891 64070.029849 1350.33921007 
+10 -81.1413062642 10 -811.413062642 65839.1158226 1358.91025255 
+10 -71.4456082872 10 -714.456082872 51044.7494352 1287.3623451 
+10 -82.3102117624 10 -823.102117624 67749.7096037 1368.17099508 
+10 -71.1392848534 10 -711.392848534 50607.9784945 1285.25507126 
+10 -81.9291643092 10 -819.291643092 67123.879644 1365.13710714 
+10 -71.2505467123 10 -712.505467123 50766.404068 1286.01938366 
+10 -83.7506683786 10 -837.506683786 70141.7445387 1379.7710556 
+10 -71.7570089651 10 -717.570089651 51490.6833562 1289.51416454 
+10 -81.0218085758 10 -810.218085758 65645.3346489 1357.9712211 
+10 -75.2262316207 10 -752.262316207 56589.8592386 1314.14273829 
+10 -79.6156880271 10 -796.156880271 63386.5778003 1347.02896699 
+10 -84.3407502411 10 -843.407502411 71133.6215124 1384.58292 
+10 -72.7126266189 10 -727.126266189 52871.2606982 1296.17814684 
+10 -78.1308077791 10 -781.308077791 61044.2312421 1335.68845427 
+10 -76.5654759856 10 -765.654759856 58622.721129 1323.97223665 
+10 -76.6599635679 10 -766.599635679 58767.5001424 1324.67250982 
+10 -71.4687872878 10 -714.687872878 51077.8755639 1287.522181 
+10 -76.4442303942 10 -764.442303942 58437.2036056 1323.07496043 
+10 -83.1807221592 10 -831.807221592 69190.3253892 1375.15644641 
+10 -70.1449381289 10 -701.449381289 49203.1234511 1278.47938272 
+10 -74.0866617905 10 -740.866617905 54888.3345526 1305.92000732 
+10 -78.7384838346 10 -787.384838346 61997.4883657 1340.30282087 
+10 -73.759346642 10 -737.59346642 54404.4121705 1303.58222419 
+10 -77.8771113263 10 -778.771113263 60648.4446853 1333.77294559 
+10 -75.9777307843 10 -759.777307843 57726.1557513 1319.63634606 
+10 -82.393480782 10 -823.93480782 67886.8567538 1368.83591357 
+10 -80.9522556521 10 -809.522556521 65532.6769517 1357.42532085 
+10 -73.0364800699 10 -730.364800699 53343.27421 1298.45725103 
+10 -73.2608848662 10 -732.608848662 53671.5725138 1300.04264135 
+10 -76.4461929786 10 -764.461929786 58440.2042092 1323.0894728 
+10 -81.0312580258 10 -810.312580258 65660.6477724 1358.04542436 
+10 -74.129963163 10 -741.29963163 54952.5143855 1306.23008114 
+10 -76.9063655892 10 -769.063655892 59145.8906813 1326.50286201 
+10 -76.1432070978 10 -761.432070978 57977.8798714 1320.85359758 
+10 -82.8727320627 10 -828.727320627 68678.8971953 1372.67630296 
+10 -79.0664699152 10 -790.664699152 62515.0666486 1342.80871576 
+10 -84.1981433534 10 -841.981433534 70893.2734417 1383.41683137 
+10 -76.9341241531 10 -769.341241531 59188.5945921 1326.70944192 
+10 -79.16931675 10 -791.6931675 62677.8071466 1343.59670655 
+10 -75.7987460585 10 -757.987460585 57454.4990405 1318.32280869 
+10 -75.2250137854 10 -752.250137854 56588.0269902 1314.1338815 
+10 -74.3952235735 10 -743.952235735 55346.4929056 1308.13365863 
+10 -75.2701193181 10 -752.701193181 56655.9086216 1314.46201328 
+10 -81.3393063569 10 -813.393063569 66160.8275862 1360.46931134 
+10 -79.2114670702 10 -792.114670702 62744.5651541 1343.919959 
+10 -79.0629139352 10 -790.629139352 62509.4435993 1342.78148951 
+10 -74.6095967595 10 -746.095967595 55665.9192862 1309.67719724 
+10 -82.076556785 10 -820.76556785 67365.6117368 1366.30891949 
+10 -82.008421725 10 -820.08421725 67253.8123383 1365.76695626 
+10 -76.7411366573 10 -767.411366573 58892.0205546 1325.27481861 
+10 -76.2689214421 10 -762.689214421 58169.4837794 1321.78018854 
+10 -76.3943156294 10 -763.943156294 58360.9146049 1322.70599412 
+10 -71.4978170401 10 -714.978170401 51119.3784149 1287.72243781 
+10 -70.3356470564 10 -703.356470564 49471.0324684 1279.77125058 
+10 -81.5644443194 10 -815.644443194 66527.5857714 1362.24681778 
+10 -78.1382451408 10 -781.382451408 61055.8535368 1335.7447064 
+10 -82.5560534375 10 -825.560534375 68155.0195918 1370.1360846 
+10 -74.1736643228 10 -741.736643228 55017.3247907 1306.54320787 
+10 -71.0596125599 10 -710.596125599 50494.6853717 1284.70852372 
+10 -82.8092112559 10 -828.092112559 68573.6546883 1372.16597063 
+10 -75.3672088761 10 -753.672088761 56802.1617378 1315.16900647 
+10 -83.5555785476 10 -835.555785476 69815.3470643 1378.18784068 
+10 -82.3237957367 10 -823.237957367 67772.073445 1368.27941829 
+10 -83.9074312254 10 -839.074312254 70404.5701485 1381.04599294 
+10 -76.5913187081 10 -765.913187081 58662.3010145 1324.1636754 
+10 -76.6251741971 10 -766.251741971 58714.1732073 1324.41457249 
+10 -77.5289651062 10 -775.289651062 60107.4043044 1331.15478025 
+10 -77.3417055343 10 -773.417055343 59817.3941495 1329.75154436 
+10 -78.2548876552 10 -782.548876552 61238.2744194 1336.62765018 
+10 -77.658245724 10 -776.58245724 60308.0312894 1332.12559502 
+10 -84.3887180202 10 -843.887180202 71214.5572909 1384.97560695 
+10 -77.5724441092 10 -775.724441092 60174.8408508 1331.48109323 
+10 -71.3349323585 10 -713.349323585 50886.725746 1286.59989564 
+10 -81.3817376269 10 -813.817376269 66229.8721918 1360.80392655 
+10 -81.450033223 10 -814.50033223 66341.0791203 1361.3428873 
+10 -74.321095275 10 -743.21095275 55236.2520287 1307.60098632 
+10 -74.2145828481 10 -742.145828481 55078.0430732 1306.83656965 
+10 -84.7249585339 10 -847.249585339 71783.1859858 1387.7346903 
+10 -74.6832967469 10 -746.832967469 55775.9481298 1310.20891646 
+10 -77.4756020629 10 -774.756020629 60024.6891501 1330.75454523 
+10 -78.3735778263 10 -783.735778263 61424.1770129 1337.52749061 
+10 -81.4524421141 10 -814.524421141 66345.0032635 1361.36190579 
+10 -81.1580913957 10 -811.580913957 65866.35799 1359.0422671 
+10 -80.8034021115 10 -808.034021115 65291.8979279 1356.25863911 
+10 -82.4824734309 10 -824.824734309 68033.5842328 1369.54730281 
+10 -76.8692271102 10 -768.692271102 59088.7807652 1326.22659705 
+10 -72.2091594645 10 -722.091594645 52141.6271057 1292.65584566 
+10 -70.3801373264 10 -703.801373264 49533.6373008 1280.07315217 
+10 -80.1522747004 10 -801.522747004 64243.8713965 1351.18128831 
+10 -80.3613998641 10 -803.613998641 64579.5458812 1352.80737944 
+10 -74.397617439 10 -743.97617439 55350.054806 1308.15086967 
+10 -83.2116555186 10 -832.116555186 69241.7961415 1375.40606683 
+10 -71.8743448693 10 -718.743448693 51659.2145039 1290.3274863 
+10 -71.0285056747 10 -710.285056747 50450.4861838 1284.4953045 
+10 -71.1563370227 10 -711.563370227 50632.2429848 1285.37213067 
+10 -72.4052012073 10 -724.052012073 52425.1316187 1294.02435779 
+10 -82.6073264347 10 -826.073264347 68239.703807 1370.54668743 
+10 -72.3738355059 10 -723.738355059 52379.7206583 1293.80514441 
+10 -79.8154480057 10 -798.154480057 63705.0574035 1348.57142502 
+10 -75.7971644861 10 -757.971644861 57452.1014413 1318.31121608 
+10 -72.2325212252 10 -722.325212252 52175.3712255 1292.81872582 
+10 -71.6907022586 10 -716.907022586 51395.5679032 1289.05516395 
+10 -81.6648292878 10 -816.648292878 66691.4434261 1363.04100981 
+10 -76.111768113 10 -761.11768113 57930.0124528 1320.62212024 
+10 -81.9264510214 10 -819.264510214 67119.4337696 1365.11555609 
+10 -79.8678313497 10 -798.678313497 63788.7048451 1348.97656639 
+10 -72.3965238561 10 -723.965238561 52412.5666645 1293.96370236 
+10 -72.2781316065 10 -722.781316065 52241.2830852 1293.13688252 
+10 -82.8745072026 10 -828.745072026 68681.8394407 1372.6905704 
+10 -76.238224013 10 -762.38224013 58122.6680065 1321.55378403 
+10 -80.14315576 10 -801.4315576 64229.2541517 1351.11048182 
+10 -73.3208899321 10 -733.208899321 53759.5290043 1300.46742254 
+10 -80.6736739707 10 -806.736739707 65082.4167193 1355.2436651 
+10 -72.4197538675 10 -724.197538675 52446.2075022 1294.12609904 
+10 -75.9911811858 10 -759.911811858 57746.5961801 1319.7351856 
+10 -79.4387211511 10 -794.387211511 63105.1041813 1345.66584062 
+10 -70.0118765071 10 -700.118765071 49016.6285204 1277.58017348 
+10 -74.9018981999 10 -749.018981999 56102.9435394 1311.78924315 
+10 -80.2933356705 10 -802.933356705 64470.197531 1352.27765374 
+10 -83.2506349935 10 -832.506349935 69306.6822683 1375.72075259 
+10 -81.5487895056 10 -815.487895056 66502.0506982 1362.12305611 
+10 -80.1840803868 10 -801.840803868 64294.8674748 1351.42831728 
+10 -81.966734373 10 -819.66734373 67185.4554377 1365.4355936 
+10 -80.304700517 10 -803.04700517 64488.4492513 1352.36607113 
+10 -70.4057944613 10 -704.057944613 49569.7589373 1280.24734607 
+10 -72.2829292612 10 -722.829292612 52248.2186258 1293.17036081 
+10 -79.7661562045 10 -797.661562045 63626.3967564 1348.19044473 
+10 -74.4691786454 10 -744.691786454 55456.5856812 1308.66563374 
+10 -75.8646724407 10 -758.646724407 57554.4852454 1318.80625812 
+10 -77.3172903081 10 -773.172903081 59779.6338058 1329.56884645 
+10 -80.9311345703 10 -809.311345703 65498.4854284 1357.2596435 
+10 -84.7510322435 10 -847.510322435 71827.3746634 1387.94911526 
+10 -72.1046643757 10 -721.046643757 51990.8262473 1291.92796514 
+10 -70.023122681 10 -700.23122681 49032.3771 1277.65610483 
+10 -80.6762515516 10 -806.762515516 65086.5756441 1355.26381533 
+10 -71.978895305 10 -719.78895305 51809.6136933 1291.05334464 
+10 -83.4204497806 10 -834.204497806 69589.7144159 1377.09345963 
+10 -84.5206804614 10 -845.206804614 71437.4542566 1386.05710117 
+10 -84.4227776264 10 -844.227776264 71272.0538216 1385.2545747 
+10 -77.0423016076 10 -770.423016076 59355.16237 1327.51523645 
+10 -79.9697387403 10 -799.697387403 63951.591142 1349.76552102 
+10 -70.4819266653 10 -704.819266653 49677.0198645 1280.76461766 
+10 -75.0434295544 10 -750.434295544 56315.1631929 1312.81495858 
+10 -72.469934649 10 -724.69934649 52518.9142803 1294.47708774 
+10 -80.8245176308 10 -808.245176308 65326.0265025 1356.4240031 
+10 -78.2584095371 10 -782.584095371 61243.7866328 1336.65433078 
+10 -75.4380738865 10 -754.380738865 56909.0299171 1315.68563111 
+10 -77.8586226204 10 -778.586226204 60619.6511635 1333.63360016 
+10 -73.8361378652 10 -738.361378652 54517.7525485 1304.12972828 
+10 -84.2134129766 10 -842.134129766 70918.9892517 1383.54159301 
+10 -73.5948467833 10 -735.948467833 54162.0147305 1302.41136196 
+10 -81.4116474189 10 -814.116474189 66278.5633545 1361.03990492 
+10 -76.4786155825 10 -764.786155825 58489.7864142 1323.32927818 
+10 -72.844771832 10 -728.44771832 53063.6078326 1297.10684621 
+10 -75.6771814834 10 -756.771814834 57270.3579727 1317.43249449 
+10 -72.8176730599 10 -728.176730599 53024.1350986 1296.91625723 
+10 -70.5795701569 10 -705.795701569 49814.7572353 1281.42889364 
+10 -74.627138576 10 -746.27138576 55692.0981203 1309.80370596 
+10 -83.2620469301 10 -832.620469301 69325.6845899 1375.81291122 
+10 -70.1863591358 10 -701.863591358 49261.2500873 1278.75966065 
+10 -77.372647289 10 -773.72647289 59865.265485 1329.9831656 
+10 -70.3886458699 10 -703.886458699 49545.614674 1280.1309119 
+10 -83.4283437922 10 -834.283437922 69602.8854791 1377.15734145 
+10 -70.3677669865 10 -703.677669865 49516.2263066 1279.98918979 
+10 -78.063149785 10 -780.63149785 60938.5535435 1335.17698027 
+10 -81.4639000322 10 -814.639000322 66363.6700845 1361.45237541 
+10 -80.1375414775 10 -801.375414775 64220.2555406 1351.06689233 
+10 -74.9123728261 10 -749.123728261 56118.6360244 1311.86508692 
+10 -75.5596625188 10 -755.596625188 57092.6259996 1316.57321437 
+10 -77.5332587639 10 -775.332587639 60114.0621455 1331.18699604 
+10 -79.0825607864 10 -790.825607864 62540.5142053 1342.93193083 
+10 -74.1973810016 10 -741.973810016 55052.513475 1306.71322212 
+10 -73.924059052 10 -739.24059052 54647.6650672 1304.75731057 
+10 -80.6207129766 10 -806.207129766 64996.9936086 1354.8297898 
+10 -75.6175256593 10 -756.175256593 57180.1018684 1316.99612793 
+10 -70.9517146752 10 -709.517146752 50341.4581535 1283.9693621 
+10 -80.6813925307 10 -806.813925307 65094.871007 1355.3040069 
+10 -72.0358525031 10 -720.358525031 51891.6404585 1291.44923917 
+10 -70.372863092 10 -703.72863092 49523.3985977 1280.02377722 
+10 -73.983308322 10 -739.83308322 54735.2991026 1305.18066843 
+10 -70.4264043441 10 -704.264043441 49598.7842884 1280.38732036 
+10 -71.4189191895 10 -714.189191895 51006.6201819 1287.17837111 
+10 -78.9504867935 10 -789.504867935 62331.7936493 1341.92134655 
+10 -73.3530193362 10 -733.530193362 53806.6544574 1300.69501745 
+10 -74.1969571786 10 -741.969571786 55051.8845456 1306.71018343 
+10 -76.4945336578 10 -764.945336578 58514.1367952 1323.44705056 
+10 -81.5662466033 10 -815.662466033 66530.5258496 1362.2610676 
+10 -73.3826225533 10 -733.826225533 53850.092928 1300.904809 
+10 -78.1544661017 10 -781.544661017 61081.2057164 1335.86741206 
+10 -73.6251442187 10 -736.251442187 54206.6186122 1302.62680701 
+10 -79.4358761297 10 -794.358761297 63100.584165 1345.64395179 
+10 -73.6410844373 10 -736.410844373 54230.0931711 1302.74019475 
+10 -71.0308387169 10 -710.308387169 50453.8004883 1284.51129276 
+10 -70.9485333091 10 -709.485333091 50336.9437871 1283.94758561 
+10 -80.0013645827 10 -800.013645827 64002.1833509 1350.01057561 
+10 -75.6628908615 10 -756.628908615 57248.7305353 1317.32792996 
+10 -76.1496448121 10 -761.496448121 57987.6840501 1320.90100905 
+10 -75.4068987443 10 -754.068987443 56862.0037823 1315.45829423 
+10 -71.0726794168 10 -710.726794168 50513.2575948 1284.79811812 
+10 -77.4320066385 10 -774.320066385 59957.1565206 1330.42778094 
+10 -75.2009438407 10 -752.009438407 56551.8195453 1313.95886177 
+10 -75.653299323 10 -756.53299323 57234.2169846 1317.25776009 
+10 -79.5613632308 10 -795.613632308 63300.1051914 1346.61018515 
+10 -75.2605840514 10 -752.605840514 56641.5551176 1314.39262958 
+10 -79.2047565888 10 -792.047565888 62733.9346628 1343.86848417 
+10 -74.9329372137 10 -749.329372137 56149.4507947 1312.01401967 
+10 -71.5446354572 10 -715.446354572 51186.348627 1288.04558427 
+10 -75.3264444052 10 -753.264444052 56740.7322674 1314.87205024 
+10 -77.6135520545 10 -776.135520545 60238.6346251 1331.78978511 
+10 -80.0632884004 10 -800.632884004 64101.3014948 1350.49068537 
+10 -73.8987857773 10 -738.987857773 54610.3053936 1304.57683052 
+10 -82.8593888738 10 -828.593888738 68656.7832454 1372.56906901 
+10 -79.420933464 10 -794.20933464 63076.8467229 1345.52900025 
+10 -82.5130575855 10 -825.130575855 68084.0467211 1369.79196921 
+10 -76.0470159796 10 -760.470159796 57831.4863941 1320.14567798 
+10 -76.4134354776 10 -764.134354776 58390.131215 1322.84729721 
+10 -76.6191750295 10 -766.191750295 58704.979822 1324.37010535 
+10 -73.9430206456 10 -739.430206456 54675.703022 1304.89275995 
+10 -72.4882592015 10 -724.882592015 52545.4772207 1294.6053213 
+10 -72.2881356974 10 -722.881356974 52255.745626 1293.20669421 
+10 -78.8052350843 10 -788.052350843 62102.6507669 1340.81194506 
+10 -77.0128463325 10 -770.128463325 59309.7850024 1327.29571343 
+10 -84.6092942209 10 -846.092942209 71587.3266855 1386.78430987 
+10 -84.5033298252 10 -845.033298252 71408.1275155 1385.91480512 
+10 -80.1118281696 10 -801.118281696 64179.0501267 1350.86729359 
+10 -76.5709047135 10 -765.709047135 58631.0344865 1324.01244625 
+10 -74.8727167585 10 -748.727167585 56059.2371479 1311.57800655 
+10 -79.6523124918 10 -796.523124918 63444.9088529 1347.31146614 
+10 -77.641180061 10 -776.41180061 60281.5284126 1331.99734705 
+10 -79.7759431668 10 -797.759431668 63642.0110815 1348.26606962 
+10 -74.2486936732 10 -742.486936732 55128.6851217 1307.08125219 
+10 -76.9007816918 10 -769.007816918 59137.3022482 1326.46131582 
+10 -81.9239421683 10 -819.239421683 67115.3230039 1365.09562948 
+10 -80.2005369003 10 -802.005369003 64321.261191 1351.55617173 
+10 -77.7901985457 10 -777.901985457 60513.1498978 1333.11819985 
+10 -83.6336438817 10 -836.336438817 69945.8638892 1378.82090848 
+10 -74.5997567896 10 -745.997567896 55651.2371307 1309.60624646 
+10 -76.4397202618 10 -764.397202618 58430.3083371 1323.04161162 
+10 -74.5015225143 10 -745.015225143 55504.7685695 1308.89846222 
+10 -84.1273771458 10 -841.273771458 70774.1558543 1382.83893498 
+10 -80.0201189039 10 -800.201189039 64032.194294 1350.15594174 
+10 -74.3006228625 10 -743.006228625 55205.8255776 1307.45397217 
+10 -71.2208114101 10 -712.208114101 50724.0397791 1285.81499604 
+10 -75.8189718441 10 -758.189718441 57485.1649149 1318.47108161 
+10 -74.0750751161 10 -740.750751161 54871.1675345 1305.83706889 
+10 -71.8398410602 10 -718.398410602 51609.6276356 1290.08817791 
+10 -71.6223633003 10 -716.223633003 51297.6292473 1288.58255541 
+10 -81.5083563645 10 -815.083563645 66436.1215725 1361.80351877 
+10 -79.5251625802 10 -795.251625802 63242.514834 1346.33128353 
+10 -77.6073659574 10 -776.073659574 60229.0325085 1331.74332105 
+10 -72.777218556 10 -727.77218556 52965.2354075 1296.6318724 
+10 -71.2526824343 10 -712.526824343 50769.4475408 1286.0340671 
+10 -84.0266717882 10 -840.266717882 70604.8157181 1382.01741064 
+10 -80.6649840671 10 -806.649840671 65068.3965454 1355.17573671 
+10 -83.0156015635 10 -830.156015635 68915.9010295 1373.82560476 
+10 -74.9490226945 10 -749.490226945 56173.5600286 1312.13054447 
+10 -74.9352935829 10 -749.352935829 56152.9822436 1312.03108782 
+10 -80.6921115112 10 -806.921115112 65112.1686014 1355.38781513 
+10 -80.2770682784 10 -802.770682784 64444.0769137 1352.1511175 
+10 -82.1461807367 10 -821.461807367 67479.9500962 1366.8632053 
+10 -78.689584195 10 -786.89584195 61920.5066079 1339.93013699 
+10 -76.6450873416 10 -766.450873416 58744.6941361 1324.56219884 
+10 -84.2694410208 10 -842.694410208 71013.3868996 1383.99957424 
+10 -78.5438133394 10 -785.438133394 61691.306139 1338.82057736 
+10 -82.9561790869 10 -829.561790869 68817.276487 1373.34733766 
+10 -82.5722316344 10 -825.722316344 68181.7343709 1370.26561395 
+10 -79.782060307 10 -797.82060307 63651.7714683 1348.31334226 
+10 -81.823424051 10 -818.23424051 66950.7272342 1364.29778016 
+10 -74.8736584581 10 -748.736584581 56060.647309 1311.58482193 
+10 -80.8347897131 10 -808.347897131 65342.6322796 1356.50446397 
+10 -71.4994671606 10 -714.994671606 51121.7380425 1287.73382342 
+10 -70.8846393436 10 -708.846393436 50246.3209487 1283.51044491 
+10 -70.2873910073 10 -702.873910073 49403.1733461 1279.44401898 
+10 -75.8746805163 10 -758.746805163 57569.6714345 1318.87968704 
+10 -75.8658873117 10 -758.658873117 57556.3285759 1318.81517105 
+10 -81.5332811359 10 -815.332811359 66476.7593278 1362.00047635 
+10 -78.2151595022 10 -782.151595022 61176.1117595 1336.32676892 
+10 -79.9883150583 10 -799.883150583 63981.3054586 1349.90944853 
+10 -76.5769850369 10 -765.769850369 58640.3463735 1324.05748561 
+10 -70.0649853485 10 -700.649853485 49091.0217189 1277.93886226 
+10 -79.3301284552 10 -793.301284552 62932.6928072 1344.83093192 
+10 -81.1993454418 10 -811.993454418 65933.3370017 1359.36684865 
+10 -82.3820781779 10 -823.820781779 67868.0680492 1368.7448207 
+10 -74.7174931449 10 -747.174931449 55827.0378185 1310.45581581 
+10 -76.6666022939 10 -766.666022939 58777.6790729 1324.72174479 
+10 -84.1128662912 10 -841.128662912 70749.7427573 1382.72049721 
+10 -72.2167711649 10 -722.167711649 52152.6203749 1292.70890908 
+10 -79.4123924134 10 -794.123924134 63063.2806883 1345.46330534 
+10 -79.2335184169 10 -792.335184169 62779.5044072 1344.08914243 
+10 -72.6232640887 10 -726.232640887 52741.384869 1295.55110832 
+10 -80.5428087292 10 -805.428087292 64871.4403799 1354.22149972 
+10 -76.6872697016 10 -766.872697016 58809.3733428 1324.87504929 
+10 -82.7148250016 10 -827.148250016 68417.4227505 1371.4084075 
+10 -78.0346660285 10 -780.346660285 60894.0910217 1334.9617886 
+10 -77.8295434715 10 -778.295434715 60574.3783698 1333.41450598 
+10 -71.924330004 10 -719.24330004 51731.0924652 1290.67437983 
+10 -74.9145349407 10 -749.145349407 56121.8754539 1311.88074353 
+10 -72.7369739732 10 -727.369739732 52906.6738277 1296.34912565 
+10 -71.6910346297 10 -716.910346297 51396.0444627 1289.05746366 
+10 -77.4320613743 10 -774.320613743 59957.2412867 1330.42819109 
+10 -83.3026763895 10 -833.026763895 69393.3589365 1376.14112559 
+10 -70.215101204 10 -702.15101204 49301.6043708 1278.95424655 
+10 -70.5063673196 10 -705.063673196 49711.4783261 1280.9307998 
+10 -81.2310960644 10 -812.310960644 65984.9096783 1359.61677438 
+10 -72.6875536772 10 -726.875536772 52834.8045957 1296.00213456 
+10 -72.2107052255 10 -722.107052255 52143.8594916 1292.66662115 
+10 -74.7508402685 10 -747.508402685 55876.8812085 1310.69669598 
+10 -81.4608076219 10 -814.608076219 66358.6317841 1361.42795702 
+10 -82.1962913238 10 -821.962913238 67562.3030739 1367.26244254 
+10 -78.1139992233 10 -781.139992233 61017.9687466 1335.56134393 
+10 -83.4953796862 10 -834.953796862 69714.7842894 1377.70007653 
+10 -75.6642669025 10 -756.642669025 57250.812859 1317.33799757 
+10 -77.9217851798 10 -779.217851798 60718.0460561 1334.10978399 
+10 -70.6508231908 10 -706.508231908 49915.3881754 1281.91423508 
+10 -82.9746864855 10 -829.746864855 68847.9859737 1373.49625825 
+10 -76.1589670962 10 -761.589670962 58001.8826916 1320.96967168 
+10 -73.5877798306 10 -735.877798306 54151.6134039 1302.36112206 
+10 -78.1128835561 10 -781.128835561 61016.2257745 1335.55290798 
+10 -77.0556276352 10 -770.556276352 59375.6975025 1327.6145806 
+10 -79.6703514273 10 -796.703514273 63473.6489655 1347.45065697 
+10 -77.7083069387 10 -777.083069387 60385.8096728 1332.50197163 
+10 -72.4258726606 10 -724.258726606 52455.0703065 1294.16888337 
+10 -76.2712790624 10 -762.712790624 58173.0800981 1321.79758072 
+10 -84.1338949978 10 -841.338949978 70785.122875 1382.89214063 
+10 -73.0522567065 10 -730.522567065 53366.3220991 1298.56854632 
+10 -74.3831269803 10 -743.831269803 55328.4957936 1308.04669722 
+10 -78.6284812924 10 -786.284812924 61824.3807035 1339.46478319 
+10 -78.3766870939 10 -783.766870939 61429.0507981 1337.55108222 
+10 -79.8631406787 10 -798.631406787 63781.2123907 1348.94027678 
+10 -73.2167708547 10 -732.167708547 53606.9553439 1299.73058401 
+10 -79.0940689661 10 -790.940689661 62558.7174562 1343.02007004 
+10 -80.4166399952 10 -804.166399952 64668.3598812 1353.23763941 
+10 -82.5884902475 10 -825.884902475 68208.5872136 1370.39581351 
+10 -70.1122410034 10 -701.122410034 49157.2633852 1278.25825667 
+10 -80.853995589 10 -808.53995589 65373.686027 1356.65493124 
+10 -76.5902477214 10 -765.902477214 58660.6604602 1324.15574037 
+10 -78.7187980188 10 -787.187980188 61966.4916152 1340.15275857 
+10 -70.2771415853 10 -702.771415853 49388.766294 1279.37454607 
+10 -79.5979343936 10 -795.979343936 63358.3115973 1346.89207439 
+10 -82.1899910294 10 -821.899910294 67551.9462541 1367.21223351 
+10 -70.3640502219 10 -703.640502219 49510.9956363 1279.96396563 
+10 -71.1861102989 10 -711.861102989 50674.6229949 1285.5765874 
+10 -82.0777591027 10 -820.777591027 67367.5853933 1366.31848719 
+10 -72.8899161618 10 -728.899161618 53129.3987807 1297.42451486 
+10 -78.0639441505 10 -780.639441505 60939.7937633 1335.18298278 
+10 -71.7774783468 10 -717.774783468 51520.0639782 1289.6559503 
+10 -73.5303837278 10 -735.303837278 54067.1733116 1301.95327063 
+10 -76.9206121389 10 -769.206121389 59167.8057182 1326.60887556 
+10 -72.9586867782 10 -729.586867782 53229.6997639 1297.90882713 
+10 -71.7658013079 10 -717.658013079 51503.3023736 1289.57506154 
+10 -79.6431823918 10 -796.431823918 63430.3650149 1347.24102948 
+10 -82.7589076116 10 -827.589076116 68490.3678906 1371.76211255 
+10 -77.2793057561 10 -772.793057561 59720.9109815 1329.28472847 
+10 -73.1507693885 10 -731.507693885 53510.3506213 1299.26406076 
+10 -81.1136575801 10 -811.136575801 65794.2544603 1358.69285791 
+10 -74.3873612522 10 -743.873612522 55334.7951407 1308.07713539 
+10 -78.3537735381 10 -783.537735381 61393.1382766 1337.377248 
+10 -73.1946444687 10 -731.946444687 53574.5597889 1299.57413783 
+10 -76.4448422739 10 -764.448422739 58438.1391028 1323.07948495 
+10 -81.896412169 10 -818.96412169 67070.2232615 1364.87701327 
+10 -73.1876759499 10 -731.876759499 53564.3591095 1299.52487656 
+10 -71.0574131395 10 -710.574131395 50491.5596207 1284.69344482 
+10 -71.9953971554 10 -719.953971554 51833.3721156 1291.16801129 
+10 -79.1183967081 10 -791.183967081 62597.2069766 1343.20643571 
+10 -71.6509996913 10 -716.509996913 51338.6575676 1288.78053792 
+10 -77.3246098505 10 -773.246098505 59790.9528854 1329.62361196 
+10 -80.93041257 10 -809.3041257 65497.3167876 1357.2539808 
+10 -71.9461580533 10 -719.461580533 51762.4965864 1290.82594342 
+10 -77.3868455881 10 -773.868455881 59887.2387008 1330.08948211 
+10 -83.4436976662 10 -834.436976662 69628.5068021 1377.28160959 
+10 -82.1980852376 10 -821.980852376 67565.2521673 1367.27673953 
+10 -72.1764330748 10 -721.764330748 52094.374914 1292.4277663 
+10 -77.5200974662 10 -775.200974662 60093.6551118 1331.08825119 
+10 -77.6605662786 10 -776.605662786 60311.6355471 1332.14303617 
+10 -74.9818758917 10 -749.818758917 56222.8171224 1312.36861664 
+10 -75.8844797149 10 -758.844797149 57584.542616 1318.95159315 
+10 -76.8665168556 10 -768.665168556 59084.614135 1326.20644146 
+10 -77.1808131587 10 -771.808131587 59568.7791984 1328.5486927 
+10 -82.8812551584 10 -828.812551584 68693.0245664 1372.74480904 
+10 -70.0645156541 10 -700.645156541 49090.3635384 1277.93568878 
+10 -73.6732429194 10 -736.732429194 54277.4672226 1302.96902538 
+10 -76.6868343507 10 -766.868343507 58808.7056274 1324.87181955 
+10 -82.8811251151 10 -828.811251151 68692.8090034 1372.74376374 
+10 -84.2216078758 10 -842.216078758 70932.7923319 1383.60855969 
+10 -74.5237316005 10 -745.237316005 55537.8657166 1309.05839568 
+10 -77.9403117505 10 -779.403117505 60746.9219576 1334.24953185 
+10 -78.6455021719 10 -786.455021719 61851.1501187 1339.59437505 
+10 -83.7639408669 10 -837.639408669 70163.9778955 1379.87890426 
+10 -83.2428695423 10 -832.428695423 69293.7532964 1375.6580491 
+10 -70.3625140593 10 -703.625140593 49508.8338474 1279.95354072 
+10 -77.8707272466 10 -778.707272466 60638.5016192 1333.72482628 
+10 -75.9872813568 10 -759.872813568 57740.66928 1319.70652606 
+10 -70.7860734497 10 -707.860734497 50106.6819442 1282.83689136 
+10 -80.2871242917 10 -802.871242917 64460.2232703 1352.22933528 
+10 -83.0536207217 10 -830.536207217 68979.0391499 1374.13179057 
+10 -82.5614575304 10 -825.614575304 68163.9426954 1370.17934909 
+10 -80.7999857526 10 -807.999857526 65286.3769762 1356.23188844 
+10 -76.0503880428 10 -760.503880428 57836.6152147 1320.17047906 
+10 -70.6575364483 10 -706.575364483 49924.8745694 1281.95998873 
+10 -80.1954133537 10 -801.954133537 64313.0432297 1351.51636281 
+10 -77.9278793002 10 -779.278793002 60727.5437222 1334.15574879 
+10 -74.4526890083 10 -744.526890083 55432.0290056 1308.54697278 
+10 -71.0217301502 10 -710.217301502 50440.8615352 1284.44887514 
+10 -80.3746418484 10 -803.746418484 64600.8305227 1352.91049215 
+10 -71.8916888948 10 -718.916888948 51684.1493215 1290.44782438 
+10 -83.0787718064 10 -830.787718064 69020.8232487 1374.33442329 
+10 -71.5750070514 10 -715.750070514 51229.816344 1288.25532996 
+10 -79.1124276446 10 -791.124276446 62587.7620783 1343.16070348 
+10 -79.821922346 10 -798.21922346 63715.3928701 1348.62148376 
+10 -84.888442289 10 -848.88442289 72060.4763426 1389.08027114 
+10 -76.7420404595 10 -767.420404595 58893.4077389 1325.28152858 
+10 -71.7423467511 10 -717.423467511 51469.6431736 1289.41262918 
+10 -84.3994199417 10 -843.994199417 71232.620865 1385.06324934 
+10 -70.7265025598 10 -707.265025598 50022.3816434 1282.43028258 
+10 -75.0194714531 10 -750.194714531 56279.210971 1312.64118699 
+10 -74.1900130169 10 -741.900130169 55041.5803145 1306.66039832 
+10 -71.8075053601 10 -718.075053601 51563.1782604 1289.86401496 
+10 -74.4938671597 10 -744.938671597 55493.362444 1308.84334543 
+10 -81.8389488006 10 -818.389488006 66976.1354079 1364.42093984 
+10 -70.5113840292 10 -705.113840292 49718.5527772 1280.96491788 
+10 -76.7236046467 10 -767.236046467 58865.1150998 1325.14467434 
+10 -81.6683286371 10 -816.683286371 66697.1590238 1363.06871296 
+10 -71.2063118495 10 -712.063118495 50703.3884721 1285.7153644 
+10 -83.9654270184 10 -839.654270184 70501.9293438 1381.51828996 
+10 -83.0756295149 10 -830.756295149 69015.602193 1374.30910359 
+10 -72.3634903112 10 -723.634903112 52364.7473002 1293.73286392 
+10 -81.5314464237 10 -815.314464237 66473.7675593 1361.98597619 
+10 -71.5211055249 10 -715.211055249 51152.685355 1287.88315039 
+10 -82.7856784625 10 -827.856784625 68534.6855849 1371.97700831 
+10 -74.8212817737 10 -748.212817737 55982.2420626 1311.20588987 
+10 -81.2538688232 10 -812.538688232 66021.9119873 1359.79609273 
+10 -80.5811129487 10 -805.811129487 64933.1576406 1354.52050997 
+10 -72.4728805873 10 -724.728805873 52523.1842062 1294.49770088 
+10 -72.0036638653 10 -720.036638653 51845.2761003 1291.22546454 
+10 -71.6773548915 10 -716.773548915 51376.4320424 1288.96282149 
+10 -74.2643074495 10 -742.643074495 55151.8736096 1307.19329119 
+10 -77.1050941033 10 -771.050941033 59451.9553667 1327.98350331 
+10 -80.0921848273 10 -800.921848273 64147.580704 1350.71485731 
+10 -82.0960938656 10 -820.960938656 67397.6862799 1366.46440793 
+10 -72.8302768193 10 -728.302768193 53042.4922158 1297.00489187 
+10 -82.9079009562 10 -829.079009562 68737.2004097 1372.95902681 
+10 -76.2326633702 10 -762.326633702 58114.1896451 1321.51278238 
+10 -81.7086994156 10 -817.086994156 66763.1156019 1363.38840316 
+10 -72.5858897144 10 -725.858897144 52687.1138564 1295.28909685 
+10 -84.7567621891 10 -847.567621891 71837.0873678 1387.99624629 
+10 -83.7422678438 10 -837.422678438 70127.6742362 1379.70280422 
+10 -82.7493669768 10 -827.493669768 68474.5773507 1371.68554501 
+10 -78.7962038225 10 -787.962038225 62088.4173684 1340.74303589 
+10 -74.6077923633 10 -746.077923633 55663.2268132 1309.66418598 
+10 -74.396578834 10 -743.96578834 55348.509422 1308.1434024 
+10 -77.632566239 10 -776.32566239 60268.1534085 1331.93262548 
+10 -70.9699599713 10 -709.699599713 50367.3521833 1284.09427092 
+10 -80.8434769748 10 -808.434769748 65356.6776938 1356.57251923 
+10 -76.956935682 10 -769.56935682 59223.6994956 1326.87926356 
+10 -78.014564547 10 -780.14564547 60862.7228146 1334.80997294 
+10 -70.2204766644 10 -702.204766644 49309.1534297 1278.99064798 
+10 -78.31652097 10 -783.1652097 61334.7745684 1337.0947426 
+10 -82.1086709148 10 -821.086709148 67418.338394 1366.56452424 
+10 -75.4680800526 10 -754.680800526 56954.3110682 1315.90453533 
+10 -75.8615798721 10 -758.615798721 57549.7930069 1318.78357007 
+10 -77.2282307284 10 -772.282307284 59641.9962144 1328.90292339 
+10 -81.7370507206 10 -817.370507206 66809.4546051 1363.61301035 
+10 -74.7823767884 10 -747.823767884 55924.0387812 1310.92459971 
+10 -78.7088909261 10 -787.088909261 61950.8951082 1340.07725281 
+10 -81.1533728072 10 -811.533728072 65858.6991798 1359.0051527 
+10 -78.451309699 10 -784.51309699 61546.0799349 1338.11757225 
+10 -83.7176764936 10 -837.176764936 70086.4935748 1379.50304875 
+10 -79.7711088706 10 -797.711088706 63634.2981045 1348.2287133 
+10 -75.6629218845 10 -756.629218845 57248.777481 1317.32815693 
+10 -82.4126644872 10 -824.126644872 67918.4726789 1368.98919727 
+10 -74.7280380466 10 -747.280380466 55842.7967029 1310.531974 
+10 -80.7637454336 10 -807.637454336 65227.8257646 1355.94819246 
+10 -75.2567342746 10 -752.567342746 56635.7605367 1314.36461912 
+10 -75.4673088114 10 -754.673088114 56953.1469923 1315.89890776 
+10 -83.7296338372 10 -837.296338372 70106.5158252 1379.60017067 
+10 -81.6171087011 10 -816.171087011 66613.5243272 1362.66334446 
+10 -81.1228136641 10 -811.228136641 65809.1089679 1358.76484142 
+10 -82.9209523583 10 -829.209523583 68758.8434001 1373.06397891 
+10 -80.3310473852 10 -803.310473852 64530.77174 1352.57109685 
+10 -79.417318425 10 -794.17318425 63071.1046582 1345.50119368 
+10 -77.5269489116 10 -775.269489116 60104.2780755 1331.13965315 
+10 -74.8114129149 10 -748.114129149 55967.4750232 1311.13452189 
+10 -74.0988670559 10 -740.988670559 54906.4209897 1306.00738818 
+10 -78.8780294801 10 -788.780294801 62217.4353466 1341.36766936 
+10 -77.1102014112 10 -771.102014112 59459.8316168 1328.02160773 
+10 -79.487175794 10 -794.87175794 63182.111157 1346.03876184 
+10 -73.8361208971 10 -738.361208971 54517.7274913 1304.12960723 
+10 -79.9337231211 10 -799.337231211 63894.0009201 1349.48657382 
+10 -82.7517282225 10 -827.517282225 68478.4852381 1371.70449414 
+10 -76.6328919682 10 -766.328919682 58726.0013141 1324.47178358 
+10 -74.5742764817 10 -745.742764817 55613.2271277 1309.42256652 
+10 -70.6434061924 10 -706.434061924 49904.9083846 1281.86369038 
+10 -70.9260984611 10 -709.260984611 50305.1144292 1283.79404753 
+10 -70.5008168828 10 -705.008168828 49703.6518115 1280.89305484 
+10 -70.9835312618 10 -709.835312618 50386.6171039 1284.1872027 
+10 -70.6449691135 10 -706.449691135 49907.1166105 1281.87434077 
+10 -77.1485709011 10 -771.485709011 59519.0199209 1328.30795688 
+10 -76.1166409229 10 -761.166409229 57937.4302539 1320.65799104 
+10 -71.2934823713 10 -712.934823713 50827.6062863 1286.31466084 
+10 -80.5820521327 10 -805.820521327 64934.6712592 1354.52784326 
+10 -76.425351918 10 -764.25351918 58408.3441579 1322.93538281 
+10 -75.1886002841 10 -751.886002841 56533.2561269 1313.86913056 
+10 -83.0801541272 10 -830.801541272 69023.120098 1374.34556196 
+10 -77.4919387994 10 -774.919387994 60050.005789 1330.87704424 
+10 -84.8908713642 10 -848.908713642 72064.6004097 1389.10028421 
+10 -73.6228788551 10 -736.228788551 54203.2829091 1302.61069483 
+10 -83.549565735 10 -835.49565735 69805.2993451 1378.13910529 
+10 -75.1777436878 10 -751.777436878 56516.9314599 1313.79022138 
+10 -84.56845128 10 -845.6845128 71518.229519 1386.44903478 
+10 -70.1519379683 10 -701.519379683 49212.9440071 1278.52673554 
+10 -77.25695496 10 -772.5695496 59686.370897 1329.11761574 
+10 -72.2521209045 10 -722.521209045 52203.689752 1292.95541853 
+10 -76.4978750633 10 -764.978750633 58519.248892 1323.47177569 
+10 -70.0344868367 10 -700.344868367 49048.2934647 1277.73284561 
+10 -77.7094748529 10 -777.094748529 60387.6248191 1332.51075538 
+10 -75.3221486566 10 -753.221486566 56734.2607825 1314.84076675 
+10 -78.1623944152 10 -781.623944152 61093.5990072 1335.92739643 
+10 -77.9584024687 10 -779.584024687 60775.1251547 1334.38602516 
+10 -70.5643140684 10 -705.643140684 49793.2241995 1281.32504248 
+10 -74.7533259466 10 -747.533259466 55880.5974008 1310.71465552 
+10 -80.0633646089 10 -800.633646089 64101.423525 1350.49127647 
+10 -74.7462191673 10 -747.462191673 55869.972798 1310.6633092 
+10 -71.3500459649 10 -713.500459649 50908.2905919 1286.70394147 
+10 -73.5002581183 10 -735.002581183 54022.8794345 1301.73933264 
+10 -81.5433269517 10 -815.433269517 66493.1417035 1362.07987678 
+10 -79.7551546694 10 -797.551546694 63608.8469634 1348.10544615 
+10 -73.8935015657 10 -738.935015657 54602.4957363 1304.53910329 
+10 -83.596241307 10 -835.96241307 69883.3156066 1378.51751771 
+10 -84.1739373024 10 -841.739373024 70852.5172098 1383.21910172 
+10 -79.7114678968 10 -797.114678968 63539.1811426 1347.76803874 
+10 -75.1551256841 10 -751.551256841 56482.9291659 1313.62586441 
+10 -79.3553396697 10 -793.553396697 62972.699341 1345.02466179 
+10 -83.5952727093 10 -835.952727093 69881.6961933 1378.50966279 
+10 -74.3068224677 10 -743.068224677 55215.0386525 1307.49848765 
+10 -81.5807781039 10 -815.807781039 66554.2335603 1362.37597328 
+10 -78.0385663873 10 -780.385663873 60900.1784378 1334.99125059 
+10 -80.0249612337 10 -800.249612337 64039.9442045 1350.19348071 
+10 -79.0999558837 10 -790.999558837 62568.030208 1343.06516207 
+10 -76.6260717433 10 -766.260717433 58715.548708 1324.4212256 
+10 -83.3784376684 10 -833.784376684 69519.6386802 1376.75358398 
+10 -78.4221243624 10 -784.221243624 61500.2958951 1337.89594838 
+10 -83.9511469613 10 -839.511469613 70477.9507612 1381.40196707 
+10 -76.9500112714 10 -769.500112714 59213.0423467 1326.82770892 
+10 -80.7296011427 10 -807.296011427 65172.6850065 1355.68102475 
+10 -84.680773666 10 -846.80773666 71708.3342867 1387.37147802 
+10 -75.4136789455 10 -754.136789455 56872.2297209 1315.50772887 
+10 -83.19794775 10 -831.9794775 69218.9850981 1375.29543855 
+10 -81.8317039263 10 -818.317039263 66964.2776749 1364.36346239 
+10 -82.1941650859 10 -821.941650859 67558.8077417 1367.24549744 
+10 -73.7127831227 10 -737.127831227 54335.7439569 1303.250524 
+10 -82.9803616081 10 -829.803616081 68857.4041262 1373.54193023 
+10 -71.9265440964 10 -719.265440964 51734.2774565 1290.68975126 
+10 -77.64541199 10 -776.4541199 60288.100031 1332.02914716 
+10 -74.3586129701 10 -743.586129701 55292.0332284 1307.8705129 
+10 -77.9250166855 10 -779.250166855 60723.0822544 1334.1341571 
+10 -75.7853501166 10 -757.853501166 57434.192923 1318.22462709 
+10 -82.1757434983 10 -821.757434983 67528.528195 1367.0987051 
+10 -78.2189622369 10 -782.189622369 61182.0605342 1336.35556211 
+10 -75.7475062565 10 -757.475062565 57376.8470408 1317.94735864 
+10 -75.6723887497 10 -756.723887497 57263.1041909 1317.39742377 
+10 -78.9111440941 10 -789.111440941 62269.6866223 1341.62064709 
+10 -77.3761471706 10 -773.761471706 59870.6815096 1330.00937076 
+10 -78.5016769471 10 -785.016769471 61625.132835 1338.50024494 
+10 -73.3247709635 10 -733.247709635 53765.2203684 1300.4949091 
+10 -79.7073257793 10 -797.073257793 63532.5778289 1347.7360577 
+10 -77.1202936903 10 -771.202936903 59475.3969888 1328.09691152 
+10 -71.2800323288 10 -712.800323288 50808.430088 1286.22214236 
+10 -77.1701901169 10 -771.701901169 59552.3824267 1328.4693646 
+10 -78.4342915578 10 -784.342915578 61519.3809217 1337.98833172 
+10 -77.5008999764 10 -775.008999764 60063.8949715 1330.94424986 
+10 -70.018773794 10 -700.18773794 49026.2868361 1277.62674073 
+10 -76.5673951011 10 -765.673951011 58625.6599256 1323.98645085 
+10 -72.9630004012 10 -729.630004012 53235.9942755 1297.93922128 
+10 -83.4358040102 10 -834.358040102 69615.3339082 1377.21771854 
+10 -78.9970461325 10 -789.970461325 62405.3329766 1342.27740335 
+10 -83.2496059261 10 -832.496059261 69304.9688685 1375.71244286 
+10 -84.5513156405 10 -845.513156405 71489.2497654 1386.30841992 
+10 -81.1305193687 10 -811.305193687 65821.6117304 1358.82542881 
+10 -83.5202581226 10 -835.202581226 69756.3351686 1377.90161131 
+10 -79.1180782986 10 -791.180782986 62596.7031367 1343.20399611 
+10 -82.6336124761 10 -826.336124761 68283.1391086 1370.75729242 
+10 -75.6133813689 10 -756.133813689 57173.8344204 1316.96582676 
+10 -76.9487084593 10 -769.487084593 59211.0373356 1326.81800956 
+10 -84.3889998398 10 -843.889998398 71215.0329396 1384.97791474 
+10 -77.1928625972 10 -771.928625972 59587.3803594 1328.63868615 
+10 -80.3682647785 10 -803.682647785 64590.5798351 1352.86083298 
+10 -76.1214535551 10 -761.214535551 57944.7569135 1320.69342118 
+10 -84.9873615612 10 -849.873615612 72228.5162513 1389.89574087 
+10 -74.2960562834 10 -742.960562834 55199.0397927 1307.42118489 
+10 -83.1251140776 10 -831.251140776 69097.8459041 1374.707951 
+10 -70.6683202055 10 -706.683202055 49940.1148067 1282.03349398 
+10 -77.2300268601 10 -772.300268601 59644.7704882 1328.91634573 
+10 -80.8794414177 10 -808.794414177 65414.8404404 1356.85434185 
+10 -77.8306129787 10 -778.306129787 60576.0431664 1333.42256259 
+10 -84.1777318924 10 -841.777318924 70858.9054654 1383.25009435 
+10 -71.7986744282 10 -717.986744282 51550.4964965 1289.80281388 
+10 -75.1208561043 10 -751.208561043 56431.4302184 1313.37693707 
+10 -77.1015819068 10 -771.015819068 59446.5393253 1327.95730115 
+10 -83.562746653 10 -835.62746653 69827.3262819 1378.24594475 
+10 -70.9015038985 10 -709.015038985 50270.2325507 1283.62578678 
+10 -82.3896336481 10 -823.896336481 67880.5173267 1368.80517822 
+10 -73.1998257154 10 -731.998257154 53582.1448476 1299.61076781 
+10 -83.7511860406 10 -837.511860406 70142.6116321 1379.77526165 
+10 -79.3185716054 10 -793.185716054 62914.3580153 1344.74214717 
+10 -74.7430170531 10 -747.430170531 55865.1859821 1310.64017565 
+10 -81.8499793858 10 -818.499793858 66994.1912546 1364.50846143 
+10 -72.4173828048 10 -724.173828048 52442.773323 1294.10952091 
+10 -73.7555013 10 -737.555013 54398.7397201 1303.55482328 
+10 -73.6802115135 10 -736.802115135 54287.7356868 1303.01862556 
+10 -78.3453621338 10 -783.453621338 61379.9576788 1337.31344786 
+10 -77.4129285876 10 -774.129285876 59927.615125 1330.28484348 
+10 -83.9583488765 10 -839.583488765 70490.0434607 1381.46063008 
+10 -80.5752291574 10 -805.752291574 64923.6755377 1354.4745704 
+10 -80.0980205421 10 -800.980205421 64156.9289477 1350.7601396 
+10 -71.7725262288 10 -717.725262288 51512.9552126 1289.62164451 
+10 -79.3109739258 10 -793.109739258 62902.3058505 1344.68378577 
+10 -77.1072671274 10 -771.072671274 59455.3064386 1327.99971541 
+10 -75.5382143695 10 -755.382143695 57060.2183013 1316.41653791 
+10 -83.2399332625 10 -832.399332625 69288.8648954 1375.63434116 
+10 -75.9158920545 10 -759.158920545 57632.2266642 1319.18216031 
+10 -71.5778595005 10 -715.778595005 51233.8997067 1288.27503366 
+10 -74.458894857 10 -744.58894857 55441.2702333 1308.59162745 
+10 -70.6399379282 10 -706.399379282 49900.0083049 1281.84005704 
+10 -71.2988832109 10 -712.988832109 50835.3074712 1286.35181655 
+10 -77.2484321312 10 -772.484321312 59673.2026672 1329.0539053 
+10 -76.1386899841 10 -761.386899841 57971.001125 1320.82033313 
+10 -80.7178755806 10 -807.178755806 65153.7543824 1355.58930302 
+10 -73.0533705456 10 -730.533705456 53367.9494808 1298.57640477 
+10 -81.5167688045 10 -815.167688045 66449.8359633 1361.86998762 
+10 -74.9221145255 10 -749.221145255 56133.2324497 1311.93563362 
+10 -79.2715358183 10 -792.715358183 62839.76391 1344.3809356 
+10 -77.707644424 10 -777.07644424 60384.7800192 1332.49698899 
+10 -71.6584936737 10 -716.584936737 51349.3971559 1288.83236236 
+10 -70.1508602429 10 -701.508602429 49211.4319282 1278.51944458 
+10 -84.1452180319 10 -841.452180319 70804.1771764 1382.98458137 
+10 -84.4393949101 10 -844.393949101 71300.1141279 1385.39072191 
+10 -83.0378403929 10 -830.378403929 68952.8293712 1374.00468676 
+10 -72.1409134205 10 -721.409134205 52043.1138914 1292.1803411 
+10 -72.4665794531 10 -724.665794531 52514.0513763 1294.45361202 
+10 -82.6388661714 10 -826.388661714 68291.8220209 1370.79939356 
+10 -76.7041892012 10 -767.041892012 58835.3264102 1325.00058475 
+10 -75.2058385378 10 -752.058385378 56559.1815017 1313.99444787 
+10 -82.0488242395 10 -820.488242395 67320.0955908 1366.08827189 
+10 -76.7235156164 10 -767.235156164 58864.9784854 1325.14401352 
+10 -77.4662110341 10 -774.662110341 60010.1385198 1330.68413984 
+10 -73.9089284742 10 -739.089284742 54625.297082 1304.64925329 
+10 -74.2093687044 10 -742.093687044 55070.3040351 1306.799178 
+10 -82.600731999 10 -826.00731999 68228.8092677 1370.49386334 
+10 -84.2186890897 10 -842.186890897 70927.8759198 1383.58470733 
+10 -76.8612485771 10 -768.612485771 59076.5153282 1326.1672645 
+10 -71.0676755722 10 -710.676755722 50506.1451124 1284.76380667 
+10 -83.1564480003 10 -831.564480003 69149.9484403 1374.9606302 
+10 -77.0985447312 10 -770.985447312 59441.8559967 1327.9346438 
+10 -72.4972145021 10 -724.972145021 52558.4611057 1294.6680019 
+10 -71.2663931648 10 -712.663931648 50788.9879471 1286.12834144 
+10 -70.5900067571 10 -705.900067571 49829.4905396 1281.49995101 
+10 -75.092252717 10 -750.92252717 56388.4641812 1313.16925773 
+10 -80.5856872724 10 -805.856872724 64940.5299317 1354.55622784 
+10 -84.7388027619 10 -847.388027619 71806.6469352 1387.84853399 
+10 -83.1211662496 10 -831.211662496 69091.2827869 1374.67612237 
+10 -76.8982920844 10 -768.982920844 59133.4732549 1326.44279325 
+10 -78.4572138083 10 -784.572138083 61555.3439855 1338.16241648 
+10 -80.7400331006 10 -807.400331006 65189.5294509 1355.76263898 
+10 -76.9435332073 10 -769.435332073 59203.0730243 1326.77948182 
+10 -77.0727701322 10 -770.727701322 59402.1189584 1327.74240226 
+10 -74.4346825677 10 -744.346825677 55405.2196895 1308.41742781 
+10 -81.6283341356 10 -816.283341356 66631.8493376 1362.75216315 
+10 -74.4980170497 10 -744.980170497 55499.5454434 1308.87322295 
+10 -75.9267294156 10 -759.267294156 57648.6823975 1319.26172963 
+10 -82.0861222203 10 -820.861222203 67381.3146116 1366.3850425 
+10 -73.4753268505 10 -734.753268505 53986.2365579 1301.56235108 
+10 -75.4762171631 10 -754.762171631 56966.5935725 1315.96391357 
+10 -70.9883780421 10 -709.883780421 50393.4981705 1284.22039634 
+10 -80.2185917659 10 -802.185917659 64350.224649 1351.6964753 
+10 -83.2906011371 10 -832.906011371 69373.2423779 1376.0435616 
+10 -72.0512613382 10 -720.512613382 51913.8426042 1291.55639769 
+10 -70.5466734078 10 -705.466734078 49768.3312891 1281.20498809 
+10 -81.9981635194 10 -819.981635194 67236.9882055 1365.68540015 
+10 -76.6469836228 10 -766.469836228 58747.6009847 1324.57625902 
+10 -76.8648822659 10 -768.648822659 59082.1012576 1326.19428572 
+10 -82.3240654001 10 -823.240654001 67772.51744 1368.28157085 
+10 -74.9130812238 10 -749.130812238 56119.6973845 1311.87021662 
+10 -75.6095308738 10 -756.095308738 57168.0115896 1316.93767523 
+10 -82.2949604261 10 -822.949604261 67724.6051153 1368.04928547 
+10 -76.4211185721 10 -764.211185721 58401.8736382 1322.90408855 
+10 -71.148604539 10 -711.48604539 50621.2392785 1285.31904526 
+10 -79.8157347102 10 -798.157347102 63705.5150734 1348.57364169 
+10 -83.5860083148 10 -835.860083148 69866.20786 1378.43453722 
+10 -78.5851604407 10 -785.851604407 61756.2744148 1339.13508196 
+10 -73.1692735961 10 -731.692735961 53537.4259858 1299.39481153 
+10 -72.1790944877 10 -721.790944877 52098.2168107 1292.44631043 
+10 -78.9728805606 10 -789.728805606 62367.1586404 1342.09257306 
+10 -74.5956464215 10 -745.956464215 55645.1046504 1309.57661165 
+10 -84.2169135208 10 -842.169135208 70924.8852298 1383.57019777 
+10 -79.2362802017 10 -792.362802017 62783.8810021 1344.11033496 
+10 -81.9702498763 10 -819.702498763 67191.2186478 1365.46353077 
+10 -72.1628175697 10 -721.628175697 52074.722396 1292.33290759 
+10 -81.0433441217 10 -810.433441217 65680.2362642 1358.14034529 
+10 -70.5133692125 10 -705.133692125 49721.3523771 1280.97841958 
+10 -83.3700978123 10 -833.700978123 69505.7320924 1376.68613601 
+10 -83.5013067887 10 -835.013067887 69724.6823542 1377.74808507 
+10 -81.4712846282 10 -814.712846282 66375.7021897 1361.51068979 
+10 -75.2235023338 10 -752.235023338 56585.7530336 1314.12288958 
+10 -82.0977647168 10 -820.977647168 67400.4297149 1366.4777074 
+10 -73.4800990805 10 -734.800990805 53993.2496087 1301.59622327 
+10 -75.4842927612 10 -754.842927612 56978.7845366 1316.02284949 
+10 -81.0418110397 10 -810.418110397 65677.7513659 1358.12830407 
+10 -70.1632429845 10 -701.632429845 49228.806661 1278.60322256 
+10 -73.5437732921 10 -735.437732921 54086.8659003 1302.04838618 
+10 -73.1088218301 10 -731.088218301 53448.9982939 1298.96778601 
+10 -81.939280687 10 -819.39280687 67140.457195 1365.2174658 
+10 -75.3257644107 10 -753.257644107 56739.7078405 1314.8670981 
+10 -70.0419732279 10 -700.419732279 49058.7801366 1277.78340738 
+10 -73.6938143027 10 -736.938143027 54307.7826648 1303.11545975 
+10 -70.0416239802 10 -700.416239802 49058.2908979 1277.78104849 
+10 -72.4118340547 10 -724.118340547 52434.7371117 1294.07072704 
+10 -84.054926512 10 -840.54926512 70652.3067093 1382.24780192 
+10 -74.5939956809 10 -745.939956809 55642.6419164 1309.56471066 
+10 -78.0491584943 10 -780.491584943 60916.7114167 1335.07126746 
+10 -82.2133322898 10 -822.133322898 67590.3200619 1367.39826724 
+10 -73.6385267585 10 -736.385267585 54226.3262317 1302.72199947 
+10 -76.2036338685 10 -762.036338685 58069.9381477 1321.29878227 
+10 -75.8866509717 10 -758.866509717 57587.837957 1318.96752704 
+10 -73.5949014711 10 -735.949014711 54162.0952253 1302.41175076 
+10 -78.7746200063 10 -787.746200063 62054.4075714 1340.57838286 
+10 -77.7025568334 10 -777.025568334 60376.8733845 1332.45872771 
+10 -70.3162733926 10 -703.162733926 49443.7830382 1279.63984684 
+10 -70.4884367129 10 -704.884367129 49686.1971023 1280.80887633 
+10 -80.3579165525 10 -803.579165525 64573.9475266 1352.7802585 
+10 -82.4033705666 10 -824.033705666 67903.1548073 1368.9149314 
+10 -73.2510005402 10 -732.510005402 53657.0908014 1299.97270387 
+10 -80.3051194365 10 -803.051194365 64489.1220772 1352.36933053 
+10 -70.7032358538 10 -707.032358538 49989.4756019 1282.27156905 
+10 -78.8189104371 10 -788.189104371 62124.206425 1340.91630452 
+10 -70.3493800082 10 -703.493800082 49490.3526754 1279.86441838 
+10 -83.4882004467 10 -834.882004467 69702.7961382 1377.64193058 
+10 -81.2540615995 10 -812.540615995 66022.2252641 1359.79761092 
+10 -77.2959373436 10 -772.959373436 59746.6192982 1329.40911216 
+10 -72.1956623931 10 -721.956623931 52122.1366838 1292.56176782 
+10 -76.3269141308 10 -763.269141308 58257.9782074 1322.2081625 
+10 -80.1197379766 10 -801.197379766 64191.7241344 1350.92868618 
+10 -75.5320258821 10 -755.320258821 57050.8693385 1316.37134022 
+10 -72.4024558338 10 -724.024558338 52421.1561077 1294.00516658 
+10 -79.1958697611 10 -791.958697611 62719.8578722 1343.80032192 
+10 -70.4838030912 10 -704.838030912 49679.6649819 1280.77737414 
+10 -73.4576804084 10 -734.576804084 53960.3081098 1301.43712045 
+10 -73.387654177 10 -733.87654177 53857.477856 1300.94047574 
+10 -82.3455276274 10 -823.455276274 67807.8592024 1368.45291411 
+10 -70.7952830582 10 -707.952830582 50119.7210329 1282.8997844 
+10 -79.7282766658 10 -797.282766658 63565.9810011 1347.89783584 
+10 -77.3352959116 10 -773.352959116 59807.4799373 1329.70357571 
+10 -83.5965596558 10 -835.965596558 69883.8478628 1378.5200994 
+10 -72.4792369764 10 -724.792369764 52532.3979268 1294.54218039 
+10 -77.5369069082 10 -775.369069082 60119.7193289 1331.21436992 
+10 -82.0537807011 10 -820.537807011 67328.2292735 1366.12770119 
+10 -80.4607740796 10 -804.607740796 64739.3616548 1353.58161475 
+10 -83.9490504316 10 -839.490504316 70474.4306836 1381.38489081 
+10 -75.189175471 10 -751.89175471 56534.1210801 1313.87331153 
+10 -74.5876659055 10 -745.876659055 55633.1990523 1309.51907878 
+10 -79.5787344449 10 -795.787344449 63327.7497586 1346.74406518 
+10 -70.253149887 10 -702.53149887 49355.0506904 1279.21196598 
+10 -76.1371448506 10 -761.371448506 57968.64826 1320.80895509 
+10 -71.6548759867 10 -716.548759867 51344.2125267 1288.80734364 
+10 -74.012232559 10 -740.12232559 54778.1056836 1305.38747028 
+10 -72.2908038785 10 -722.908038785 52259.6032541 1293.2253153 
+10 -70.1677898525 10 -701.677898525 49235.1873279 1278.63398918 
+10 -75.2939972027 10 -752.939972027 56691.8601477 1314.63580144 
+30 -84.0195157432 30 -2520.5854723 211778.370772 2145.87721705 
+30 -83.2489659045 30 -2497.46897714 207911.709725 2127.1218242 
+30 -81.6004245787 30 -2448.01273736 199758.878743 2087.59407528 
+30 -83.6814375665 30 -2510.443127 210077.489796 2137.6263708 
+30 -75.9618787453 30 -2278.85636236 173106.210675 1958.55964432 
+30 -82.5737998419 30 -2477.21399526 204552.97261 2110.83451317 
+30 -75.5396942495 30 -2266.19082748 171187.362219 1949.28204041 
+30 -80.4712717516 30 -2414.13815255 194268.76732 2060.99038278 
+30 -76.009292705 30 -2280.27878115 173322.377325 1959.6049171 
+30 -75.2413382024 30 -2257.24014607 169837.769234 1942.75784252 
+30 -79.0310664192 30 -2370.93199258 187377.283781 2027.61311909 
+30 -82.4178515208 30 -2472.53554562 203781.067479 2107.09194876 
+30 -78.2256654756 30 -2346.76996427 183577.642173 2009.21896176 
+30 -79.4420081144 30 -2383.26024343 189330.979597 2037.0733919 
+30 -71.902634345 30 -2157.07903035 155099.664773 1871.5713481 
+30 -78.5496584016 30 -2356.48975205 185101.46505 2016.59508145 
+30 -83.3947421831 30 -2501.84226549 208640.490714 2130.65639693 
+30 -75.6694961574 30 -2270.08488472 171776.179461 1952.12877519 
+30 -76.881904433 30 -2306.45713299 177324.816877 1978.96265606 
+30 -77.9999457985 30 -2339.99837395 182519.746337 2004.09877234 
+30 -74.897319976 30 -2246.91959928 168288.256188 1935.26829096 
+30 -80.9972126316 30 -2429.91637895 196816.453622 2073.33435864 
+30 -79.4336501136 30 -2383.00950341 189291.143111 2036.88047797 
+30 -76.3836265767 30 -2291.5087973 175033.75227 1967.88104142 
+30 -82.9492492865 30 -2488.4774786 206417.338716 2119.87475661 
+30 -81.4426850905 30 -2443.28055272 198987.328643 2083.85462939 
+30 -79.5625715149 30 -2386.87714545 189906.083582 2039.85848927 
+30 -72.5993984346 30 -2177.98195304 158120.179592 1886.15134913 
+30 -84.2656334114 30 -2527.96900234 213020.909227 2151.90532107 
+30 -77.4344115589 30 -2323.03234677 179882.642804 1991.33740535 
+30 -72.4032242055 30 -2172.09672616 157266.80626 1882.03161315 
+30 -77.2806771749 30 -2318.42031525 179169.091938 1987.88495181 
+30 -76.5158516263 30 -2295.47554879 175640.266503 1970.8144438 
+30 -75.6955123561 30 -2270.86537068 171894.317726 1952.69995436 
+30 -81.8234163975 30 -2454.70249192 200852.144129 2092.89315835 
+30 -83.1085663384 30 -2493.25699015 207211.013965 2123.72364507 
+30 -77.8907761982 30 -2336.72328595 182009.190503 2001.62787037 
+30 -78.2980374236 30 -2348.94112271 183917.479932 2010.86387159 
+30 -80.9930926309 30 -2429.79277893 196796.431617 2073.23733861 
+30 -83.5154946479 30 -2505.46483944 209245.135388 2133.58905596 
+30 -71.4102133557 30 -2142.30640067 152982.557145 1861.35512571 
+30 -80.1907400642 30 -2405.72220193 192916.643761 2054.44016376 
+30 -81.1188184285 30 -2433.56455285 197407.881097 2076.20029166 
+30 -74.2705893885 30 -2228.11768165 165483.613443 1921.71512518 
+30 -79.775680343 30 -2393.27041029 190924.775226 2044.79211587 
+30 -71.3968696067 30 -2141.9060882 152925.389689 1861.07929624 
+30 -71.4676750201 30 -2144.0302506 153228.857184 1862.54352965 
+30 -79.2592382787 30 -2377.77714836 188460.805576 2032.85959917 
+30 -73.2197679173 30 -2196.59303752 160834.032416 1899.25533614 
+30 -79.0680412804 30 -2372.04123841 187552.654558 2028.46224183 
+30 -80.7601113039 30 -2422.80333912 195665.867334 2067.75925319 
+30 -78.8021636325 30 -2364.06490897 186293.429795 2022.36552625 
+30 -79.8452878761 30 -2395.35863628 191258.099881 2046.4065335 
+30 -77.1821130718 30 -2315.46339215 178712.357347 1985.67520193 
+30 -76.8086520469 30 -2304.25956141 176987.070878 1977.32886535 
+30 -82.8468547391 30 -2485.40564217 205908.040205 2117.40505997 
+30 -77.8900512294 30 -2336.70153688 182005.802415 2001.61147365 
+30 -78.4194631125 30 -2352.58389337 184488.365845 2013.62723189 
+30 -83.4310222506 30 -2502.93066752 208822.064213 2131.53705438 
+30 -75.6901664546 30 -2270.70499364 171870.038938 1952.58256985 
+30 -78.5294722678 30 -2355.88416804 185006.34044 2016.134598 
+30 -76.4409687708 30 -2293.22906312 175296.651199 1969.15252942 
+30 -83.6380379155 30 -2509.14113746 209859.64159 2136.56967952 
+30 -84.8297080662 30 -2544.89124199 215882.381118 2165.78962454 
+30 -72.6503798491 30 -2179.51139547 158342.330767 1887.22386895 
+30 -73.7358166534 30 -2212.0744996 163109.119726 1910.24373614 
+30 -76.5574784649 30 -2296.72435395 175831.425267 1971.73901749 
+30 -74.5083556331 30 -2235.25066899 166544.851775 1926.84299215 
+30 -83.2346975219 30 -2497.04092566 207840.446147 2126.77620759 
+30 -71.4871227269 30 -2144.61368181 153312.261473 1862.94596532 
+30 -72.6271661242 30 -2178.81498373 158241.157777 1886.73541429 
+30 -75.3164872665 30 -2259.494618 170177.197625 1944.39862268 
+30 -71.8984114684 30 -2156.95234405 155081.44715 1871.48342715 
+30 -70.6129403151 30 -2118.38820945 149585.620198 1844.96839576 
+30 -78.0988279265 30 -2342.9648378 182982.807705 2006.33991758 
+30 -72.2966532757 30 -2168.89959827 156804.182246 1879.79842127 
+30 -72.8849874585 30 -2186.54962375 159366.641905 1892.16946893 
+30 -81.6399323612 30 -2449.19797084 199952.356678 2088.53183412 
+30 -73.6173270317 30 -2208.51981095 162585.325179 1907.71363062 
+30 -75.6922658128 30 -2270.76797438 171879.573116 1952.62866622 
+30 -74.6367579073 30 -2239.10273722 167119.368927 1929.61927621 
+30 -73.2327596481 30 -2196.98278944 160891.11257 1899.53099312 
+30 -83.5589670197 30 -2506.76901059 209463.029082 2134.64592014 
+30 -80.2730646796 30 -2408.19194039 193312.947392 2056.35993845 
+30 -83.5145355064 30 -2505.43606519 209240.329226 2133.5657445 
+30 -77.6756901884 30 -2330.27070565 181005.385388 1996.7701593 
+30 -83.3623660625 30 -2500.87098188 208478.522266 2129.87083679 
+30 -70.9237513649 30 -2127.71254095 150905.35523 1851.33396263 
+30 -74.4347035838 30 -2233.04110751 166215.752928 1925.25273695 
+30 -80.0412933046 30 -2401.23879914 192198.259016 2050.9603251 
+30 -72.403562705 30 -2172.10688115 157268.276771 1882.03871183 
+30 -70.4070712296 30 -2112.21213689 148714.670374 1840.76804845 
+30 -76.1022931423 30 -2283.06879427 173746.770646 1961.65713337 
+30 -82.1071965722 30 -2463.21589717 202247.751869 2099.65836191 
+30 -83.1443717034 30 -2494.3311511 207389.596378 2124.58970311 
+30 -79.308178107 30 -2379.24534321 188693.61344 2033.98693362 
+30 -71.1742152512 30 -2135.22645754 151973.067499 1856.48467606 
+30 -81.7342313672 30 -2452.02694102 200414.537316 2090.77201305 
+30 -74.6135022993 30 -2238.40506898 167015.241761 1929.11608208 
+30 -71.6733755071 30 -2150.20126521 154112.182697 1866.80588186 
+30 -77.4531329208 30 -2323.59398762 179969.633977 1991.7583202 
+30 -77.6019747912 30 -2328.05924374 180661.994745 1995.10849263 
+30 -75.5106527522 30 -2265.31958257 171055.760372 1948.6458123 
+30 -81.703958156 30 -2451.11874468 200266.103351 2090.05254814 
+30 -71.0318116063 30 -2130.95434819 151365.547802 1853.55388031 
+30 -83.1304388254 30 -2493.91316476 207320.095779 2124.25264978 
+30 -70.804899232 30 -2124.14697696 150400.012658 1848.89638886 
+30 -72.626165846 30 -2178.78497538 158236.798965 1886.71437044 
+30 -70.9506898578 30 -2128.52069573 151020.011739 1851.8870413 
+30 -74.5848132309 30 -2237.54439693 166886.830941 1928.49554478 
+30 -84.0335245967 30 -2521.0057379 211848.997684 2146.21984497 
+30 -81.9931225585 30 -2459.79367675 201686.164407 2096.93598011 
+30 -77.2464941843 30 -2317.39482553 179010.625913 1987.11825893 
+30 -72.7647135453 30 -2182.94140636 158841.10612 1889.63199544 
+30 -72.2024284607 30 -2166.07285382 156395.720269 1877.82678 
+30 -80.7866066352 30 -2423.59819906 195794.274349 2068.38141677 
+30 -81.4337427388 30 -2443.01228216 198943.633694 2083.64286141 
+30 -81.0869210776 30 -2432.60763233 197252.663095 2075.44812467 
+30 -82.3039946083 30 -2469.11983825 203218.425855 2104.36413332 
+30 -84.7687464579 30 -2543.06239374 215572.211281 2164.28449656 
+30 -84.2288237696 30 -2526.86471309 212834.842608 2151.00259521 
+30 -77.0633546418 30 -2311.90063925 178162.818859 1983.01657832 
+30 -74.7654605386 30 -2242.96381616 167696.222686 1932.40701803 
+30 -70.2200497283 30 -2106.60149185 147925.661516 1836.96327028 
+30 -82.2810047356 30 -2468.43014207 203104.912209 2103.81380749 
+30 -73.2018354551 30 -2196.05506365 160755.26142 1898.87493051 
+30 -78.3362570542 30 -2350.08771163 184097.075078 2011.7331826 
+30 -70.0149670716 30 -2100.44901215 147062.868421 1832.8031168 
+30 -76.4773593624 30 -2294.32078087 175463.594852 1969.95995474 
+30 -74.7795737234 30 -2243.3872117 167759.539388 1932.71301665 
+30 -74.9354086415 30 -2248.06225925 168459.464048 1936.09576376 
+30 -76.594501385 30 -2297.83504155 176001.529272 1972.56177032 
+30 -83.0284505305 30 -2490.85351591 206811.707925 2121.78720173 
+30 -78.0873195043 30 -2342.61958513 182928.884021 2006.07893048 
+30 -73.181978238 30 -2195.45934714 160668.058165 1898.45380715 
+30 -82.8528671861 30 -2485.58601558 205937.928029 2117.54998976 
+30 -76.5860595562 30 -2297.58178669 175962.735551 1972.37413309 
+30 -81.9605080424 30 -2458.81524127 201525.746357 2096.15835075 
+30 -82.7978981737 30 -2483.93694521 205664.758259 2116.22536767 
+30 -78.9581682292 30 -2368.74504688 187031.769903 2025.94022335 
+30 -77.4888149562 30 -2324.66444869 180135.4933 1992.56085528 
+30 -78.3128424722 30 -2349.38527416 183987.038882 2011.20056256 
+30 -77.8316728965 30 -2334.95018689 181733.079176 2000.29164121 
+30 -84.2624109359 30 -2527.87232808 213004.616902 2151.82627631 
+30 -83.3498789903 30 -2500.49636971 208416.069831 2129.56793991 
+30 -78.093571147 30 -2342.80713441 182958.175635 2006.22069981 
+30 -76.9348138831 30 -2308.04441649 177568.967617 1980.14372767 
+30 -74.4514447751 30 -2233.54334325 166290.528873 1925.61406078 
+30 -70.3946559755 30 -2111.83967926 148662.227697 1840.5151465 
+30 -81.493834435 30 -2444.81503305 199237.351527 2085.06638181 
+30 -70.415043189 30 -2112.45129567 148748.349219 1840.9304637 
+30 -71.0587826961 30 -2131.76348088 151480.517948 1854.10850272 
+30 -71.6056753573 30 -2148.17026072 153821.182301 1865.40165499 
+30 -75.237103193 30 -2257.11309579 169818.650906 1942.66542714 
+30 -83.8789747313 30 -2516.36924194 211070.472059 2142.44312925 
+30 -71.1774941294 30 -2135.32482388 151987.070116 1856.55222998 
+30 -70.0443826328 30 -2101.33147899 147186.466152 1833.39904379 
+30 -77.5767598473 30 -2327.30279542 180544.610052 1994.54048037 
+30 -71.3029719303 30 -2139.08915791 152523.414183 1859.13984197 
+30 -80.3008939832 30 -2409.0268195 193447.007235 2057.00936569 
+30 -84.9816752563 30 -2549.45025769 216656.553881 2169.54651296 
+30 -73.8787596358 30 -2216.36278907 163742.13376 1913.30159907 
+30 -73.8781320741 30 -2216.34396222 163739.351963 1913.28816076 
+30 -70.4956125465 30 -2114.8683764 149088.941649 1842.57299884 
+30 -70.2949064283 30 -2108.84719285 148241.216093 1838.48490064 
+30 -82.8431556671 30 -2485.29467001 205889.653226 2117.31589938 
+30 -71.9609320304 30 -2158.82796091 155351.272161 1872.78566178 
+30 -74.7404873165 30 -2242.2146195 167584.213329 1931.86570116 
+30 -81.171129995 30 -2435.13389985 197662.57034 2077.4345042 
+30 -76.9848035865 30 -2309.5441076 177799.799498 1981.2603948 
+30 -78.6251820221 30 -2358.75546066 185457.57744 2018.31900068 
+30 -73.072857571 30 -2192.18572713 160189.275408 1896.14173386 
+30 -77.5150823705 30 -2325.45247111 180257.639847 1993.15188746 
+30 -79.6861313723 30 -2390.58394117 190496.385992 2042.71733143 
+30 -84.3068944149 30 -2529.20683245 213229.573376 2152.91769607 
+30 -71.8821800604 30 -2156.46540181 155011.434307 1871.14553649 
+30 -71.6944252561 30 -2150.83275768 154202.718384 1867.24277298 
+30 -82.2044436768 30 -2466.1333103 202727.116806 2101.98225127 
+30 -80.717928163 30 -2421.53784489 195461.517808 2066.76914292 
+30 -83.1319585667 30 -2493.958757 207327.676054 2124.28941135 
+30 -76.7908637835 30 -2303.72591351 176905.102818 1976.93236625 
+30 -84.4794297451 30 -2534.38289235 214103.221502 2157.1565352 
+30 -70.8863870161 30 -2126.59161048 150746.395926 1850.56718937 
+30 -74.7179553248 30 -2241.53865974 167483.185438 1931.37746069 
+30 -84.3687913588 30 -2531.06374077 213542.788661 2154.43734978 
+30 -76.4755858415 30 -2294.26757524 175455.456894 1969.92059509 
+30 -83.8744261396 30 -2516.23278419 211047.580807 2142.33208443 
+30 -77.4673174947 30 -2324.01952484 180035.558395 1992.07730385 
+30 -76.7561027505 30 -2302.68308252 176744.979283 1976.15781935 
+30 -72.4069988645 30 -2172.20996594 157283.204537 1882.11077354 
+30 -72.3931777339 30 -2171.79533202 157223.165472 1881.82094406 
+30 -72.2240210693 30 -2166.72063208 156489.276583 1878.27836711 
+30 -76.8658936535 30 -2305.9768096 177250.968215 1978.60542083 
+30 -82.3418439896 30 -2470.25531969 203405.378148 2105.27050775 
+30 -77.3488868903 30 -2320.46660671 179485.509095 1989.41588031 
+30 -84.9659468623 30 -2548.97840587 216576.363786 2169.15735878 
+30 -78.9121858924 30 -2367.36557677 186813.99247 2024.88582293 
+30 -82.9501273078 30 -2488.50381923 206421.708611 2119.89594758 
+30 -82.9361245792 30 -2488.08373738 206352.022806 2119.5580206 
+30 -82.2636226135 30 -2467.90867841 203019.108165 2103.39782386 
+30 -73.8049654051 30 -2214.14896215 163415.187553 1911.72221371 
+30 -71.1353810969 30 -2134.06143291 151807.273314 1855.68483075 
+30 -72.568310671 30 -2177.04932013 157984.791409 1885.49772404 
+30 -78.5664808308 30 -2356.99442492 185180.757304 2016.9789259 
+30 -80.1952029912 30 -2405.85608974 192938.117484 2054.54418518 
+30 -77.839546126 30 -2335.18638378 181769.848233 2000.46958157 
+30 -74.9810565258 30 -2249.43169577 168664.765132 1937.08803326 
+30 -78.6263078227 30 -2358.78923468 185462.888455 2018.34471141 
+30 -82.8027783305 30 -2484.08334992 205689.002978 2116.34293114 
+30 -84.8061288149 30 -2544.18386445 215762.384537 2165.20732607 
+30 -79.7414692905 30 -2392.24407871 190761.057738 2043.99918672 
+30 -84.8169345305 30 -2544.50803592 215817.371495 2165.47415658 
+30 -76.8511037799 30 -2305.5331134 177182.764566 1978.27549499 
+30 -84.6715027211 30 -2540.14508163 215077.901191 2161.88587892 
+30 -75.0811189091 30 -2252.43356727 169115.232499 1939.26532331 
+30 -82.5523082984 30 -2476.56924895 204446.508162 2110.31830959 
+30 -76.781628769 30 -2303.44886307 176862.555493 1976.72655589 
+30 -80.585160256 30 -2417.55480768 194819.041605 2063.65633783 
+30 -82.0795493026 30 -2462.38647908 202111.572412 2098.99820008 
+30 -81.4506756938 30 -2443.52027081 199026.377129 2084.04387888 
+30 -78.387306034 30 -2351.61918102 184337.092418 2012.89498256 
+30 -84.0596633124 30 -2521.78989937 211980.809886 2146.85930195 
+30 -78.3498375201 30 -2350.4951256 184160.911183 2012.04217777 
+30 -72.2401139666 30 -2167.203419 156559.021977 1878.61502441 
+30 -80.6226502753 30 -2418.67950826 195000.352122 2064.53477291 
+30 -70.8584671747 30 -2125.75401524 150627.67111 1849.99450517 
+30 -80.3117142132 30 -2409.3514264 193499.143196 2057.26193032 
+30 -75.6901117803 30 -2270.70335341 171869.790639 1952.58136936 
+30 -77.4834759122 30 -2324.50427737 180110.671183 1992.44074898 
+30 -81.1488022465 30 -2434.46406739 197553.843181 2076.90761422 
+30 -74.1282258606 30 -2223.84677582 164849.816077 1918.65291099 
+30 -71.5159825179 30 -2145.47947554 153436.072665 1863.54337644 
+30 -84.944146241 30 -2548.32438723 216465.239419 2168.61808741 
+30 -84.597119327 30 -2537.91357981 214700.177953 2160.05305027 
+30 -75.3790390694 30 -2261.37117208 170459.985931 1945.76565035 
+30 -70.3088848314 30 -2109.26654494 148300.178587 1838.76922931 
+30 -70.2647093053 30 -2107.94127916 148113.881213 1837.87087408 
+30 -78.5515879627 30 -2356.54763888 185110.559144 2016.63910475 
+30 -82.4505803314 30 -2473.51740994 203942.945909 2107.8767943 
+30 -76.0560392191 30 -2281.68117657 173535.633051 1960.63613584 
+30 -73.3832689584 30 -2201.49806875 161553.124891 1902.72817273 
+30 -76.4407603563 30 -2293.22281069 175295.695316 1969.14790631 
+30 -77.5467161141 30 -2326.40148342 180404.795402 1993.86393993 
+30 -70.8359053513 30 -2125.07716054 150531.764608 1849.53189403 
+30 -71.267100766 30 -2138.01302298 152369.989548 1858.39962216 
+30 -72.2863769938 30 -2168.59130981 156759.608967 1879.58326209 
+30 -70.7231784449 30 -2121.69535335 150053.03908 1847.22281157 
+30 -77.2947866737 30 -2318.84360021 179234.521408 1988.20151703 
+30 -77.264254356 30 -2317.92763068 179092.950036 1987.51655941 
+30 -70.0636211114 30 -2101.90863334 147267.330097 1833.78893465 
+30 -80.6871254994 30 -2420.61376498 195312.366641 2066.04648908 
+30 -80.6683455773 30 -2420.05036732 195221.459345 2065.60603754 
+30 -83.7586944046 30 -2512.76083214 210465.566651 2139.50881245 
+30 -75.0917789384 30 -2252.75336815 169163.257924 1939.49745542 
+30 -82.4959154599 30 -2474.8774638 204167.282027 2108.96447354 
+30 -70.4282581759 30 -2112.84774528 148804.186491 1841.19973882 
+30 -77.9475544473 30 -2338.42663342 182274.637329 2002.91252081 
+30 -78.7657078684 30 -2362.97123605 186121.10208 2021.5312295 
+30 -81.1553103651 30 -2434.65931095 197585.532014 2077.0611773 
+30 -71.2757515624 30 -2138.27254687 152406.982824 1858.57810045 
+30 -78.8180689474 30 -2364.54206842 186368.639778 2022.72964718 
+30 -72.5728569097 30 -2177.18570729 158004.586801 1885.59329132 
+30 -80.3289851526 30 -2409.86955458 193582.37567 2057.66513948 
+30 -83.7257123629 30 -2511.77137089 210299.84732 2138.70495233 
+30 -77.4715923453 30 -2324.14777036 180055.428615 1992.17344882 
+30 -83.3265494904 30 -2499.79648471 208299.415499 2129.00216538 
+30 -81.5035909027 30 -2445.10772708 199285.059901 2085.29760633 
+30 -82.1237225574 30 -2463.71167672 202329.1742 2100.05307908 
+30 -70.7183169679 30 -2121.54950904 150032.410643 1847.12331549 
+30 -81.9941795233 30 -2459.8253857 201691.364271 2096.96118671 
+30 -77.5350307496 30 -2326.05092249 180350.4298 1993.60087594 
+30 -71.7006809315 30 -2151.02042795 154229.629381 1867.37263621 
+30 -72.3224975093 30 -2169.67492528 156916.30938 1880.33967377 
+30 -75.0348641194 30 -2251.04592358 168906.925002 1938.25847692 
+30 -80.2634973346 30 -2407.90492004 193266.870131 2056.13672766 
+30 -74.4231452394 30 -2232.69435718 166164.13642 1925.00332317 
+30 -81.7159361126 30 -2451.47808338 200324.826443 2090.33718013 
+30 -76.1765420513 30 -2285.29626154 174085.966767 1963.2974273 
+30 -74.011762359 30 -2220.35287077 164332.229024 1916.15232335 
+30 -84.5603452518 30 -2536.81035755 214513.559673 2159.14753943 
+30 -78.2970617028 30 -2348.91185109 183912.896139 2010.84168442 
+30 -75.4647325589 30 -2263.94197677 170847.775806 1947.64032961 
+30 -70.1608970549 30 -2104.82691165 147676.544266 1835.76204854 
+30 -79.3197594008 30 -2379.59278202 188748.726942 2034.25381516 
+30 -81.302157957 30 -2439.06473871 198301.226654 2080.5295148 
+30 -75.8770259334 30 -2276.310778 172719.691935 1956.69069023 
+30 -79.4708575528 30 -2384.12572658 189468.516005 2037.73943686 
+30 -75.7516317676 30 -2272.54895303 172149.291464 1953.93273349 
+30 -71.4602889527 30 -2143.80866858 153197.186916 1862.39071787 
+30 -79.0073420692 30 -2370.22026208 187264.803025 2027.06850857 
+30 -78.4241364865 30 -2352.72409459 184510.355509 2013.73367518 
+30 -79.6788707705 30 -2390.36612312 190461.673418 2042.54921401 
+30 -83.3384979384 30 -2500.15493815 208359.157159 2129.29191234 
+30 -73.2361673948 30 -2197.08502184 160906.08644 1899.60330665 
+30 -73.1160320607 30 -2193.48096182 160378.624329 1897.0560976 
+30 -73.353080141 30 -2200.59240423 161420.230985 1902.08634482 
+30 -81.1412956141 30 -2434.23886842 197517.295618 2076.73050638 
+30 -74.3870908566 30 -2231.6127257 166003.178583 1924.22557477 
+30 -74.2952135248 30 -2228.85640574 165593.362581 1922.24540276 
+30 -70.191315704 30 -2105.73947112 147804.624008 1836.37963326 
+30 -84.2688176249 30 -2528.06452875 213037.008717 2151.98343037 
+30 -71.361357487 30 -2140.84072461 152773.300272 1860.34548324 
+30 -77.2264878524 30 -2316.79463557 178917.91278 1986.66969801 
+30 -74.5234521574 30 -2235.70356472 166612.347643 1927.1691491 
+30 -75.7599494561 30 -2272.79848368 172187.098248 1954.11552915 
+30 -72.3918201035 30 -2171.7546031 157217.268537 1881.79247761 
+30 -70.4604417493 30 -2113.81325248 148940.215545 1841.85574641 
+30 -73.1293215422 30 -2193.87964627 160436.930077 1897.33765923 
+30 -76.7769483944 30 -2303.30845183 176840.994143 1976.62225942 
+30 -70.8821974288 30 -2126.46592286 150728.57737 1850.48123878 
+30 -83.1615161954 30 -2494.84548586 207475.133278 2125.00452924 
+30 -70.2112134713 30 -2106.33640414 147888.434914 1836.78376446 
+30 -76.0315194981 30 -2280.94558494 173423.758716 1960.09515396 
+30 -73.8291669474 30 -2214.87500842 163522.376765 1912.24000861 
+30 -81.8797628971 30 -2456.39288691 201128.867162 2094.23451364 
+30 -81.7146954991 30 -2451.44086497 200318.743815 2090.30769745 
+30 -70.8419334065 30 -2125.25800219 150557.385863 1849.65547926 
+30 -73.3613846845 30 -2200.84154053 161456.782885 1902.26287591 
+30 -72.0178535902 30 -2160.53560771 155597.137072 1873.97229517 
+30 -79.8534343363 30 -2395.60303009 191297.129259 2046.59557054 
+30 -82.7577411361 30 -2482.73223408 205465.311538 2115.25825184 
+30 -79.2845083798 30 -2378.53525139 188580.998071 2033.44160907 
+30 -72.4128094049 30 -2172.38428215 157308.448977 1882.23263783 
+30 -74.7268140028 30 -2241.80442008 167522.90193 1931.56939915 
+30 -83.1322025655 30 -2493.96607697 207328.893102 2124.29531359 
+30 -83.7738067841 30 -2513.21420352 210541.521093 2139.87725038 
+30 -78.5434587927 30 -2356.30376378 185072.247574 2016.45364377 
+30 -72.8483195222 30 -2185.44958567 159206.329716 1891.39540894 
+30 -82.9800839136 30 -2489.40251741 206570.829789 2120.61908601 
+30 -75.6006925964 30 -2268.02077789 171463.941632 1950.61918871 
+30 -71.7150141393 30 -2151.45042418 154291.29759 1867.67022735 
+30 -79.6741734761 30 -2390.22520428 190439.217573 2042.44045776 
+30 -71.0755029852 30 -2132.26508956 151551.813738 1854.45244145 
+30 -84.8768714488 30 -2546.30614346 216122.499208 2166.95484245 
+30 -70.9396994535 30 -2128.1909836 150973.228756 1851.66136919 
+30 -70.1724916898 30 -2105.17475069 147725.357698 1835.99741973 
+30 -78.7446421033 30 -2362.3392631 186021.559799 2021.04931742 
+30 -78.1257308975 30 -2343.77192693 183108.894848 2006.95017607 
+30 -72.1085097462 30 -2163.25529238 155989.115334 1875.86419436 
+30 -72.5808026054 30 -2177.42407816 158039.187205 1885.76033407 
+30 -74.7431652751 30 -2242.29495825 167596.22266 1931.92373935 
+30 -70.1867031473 30 -2105.60109442 147785.198961 1836.28596744 
+30 -80.8685072074 30 -2426.05521622 196191.463739 2070.30593829 
+30 -70.6323165505 30 -2118.96949652 149667.724239 1845.36438378 
+30 -72.1079510772 30 -2163.23853232 155986.698256 1875.85252797 
+30 -72.6818497939 30 -2180.45549382 158479.538684 1887.88630607 
+30 -82.5202553634 30 -2475.6076609 204287.776357 2109.54869026 
+30 -70.1976252093 30 -2105.92875628 147831.197551 1836.50776885 
+30 -82.895293786 30 -2486.85881358 206148.891956 2118.57298944 
+30 -84.4476877759 30 -2533.43063328 213942.359121 2156.37602977 
+30 -72.3218803676 30 -2169.65641103 156913.631397 1880.32674671 
+30 -71.8879722062 30 -2156.63916619 155036.416438 1871.26610303 
+30 -73.2991652566 30 -2198.9749577 161183.02882 1900.94077016 
+30 -76.8977795399 30 -2306.9333862 177398.054945 1979.31694007 
+30 -79.1237737547 30 -2373.71321264 187817.147196 2029.74290566 
+30 -70.2389018802 30 -2107.16705641 148005.10012 1837.34632419 
+30 -74.1477267593 30 -2224.43180278 164936.561507 1919.07201247 
+30 -70.9369487101 30 -2128.1084613 150961.520769 1851.60489231 
+30 -70.0081836846 30 -2100.24551054 147034.373485 1832.66572966 
+30 -76.5696291214 30 -2297.08887364 175887.243114 1972.00899373 
+30 -71.146416246 30 -2134.39248738 151854.37634 1855.91206951 
+30 -72.0158818779 30 -2160.47645634 155588.61728 1873.93117499 
+30 -70.0210772317 30 -2100.63231695 147088.537701 1832.92688058 
+30 -77.0651676368 30 -2311.9550291 178171.201887 1983.05713371 
+30 -75.2421201429 30 -2257.26360429 169841.299308 1942.77490643 
+30 -78.6806890456 30 -2360.42067137 185719.524861 2019.58710752 
+30 -72.5630149463 30 -2176.89044839 157961.734143 1885.3864095 
+30 -73.5170212477 30 -2205.51063743 162142.572394 1905.57509604 
+30 -70.9738025657 30 -2129.21407697 151118.419519 1852.36174567 
+30 -73.5366963383 30 -2206.10089015 162229.371251 1905.994334 
+30 -74.1578060479 30 -2224.73418144 164981.405935 1919.28867514 
+30 -79.0866218844 30 -2372.59865653 187640.812833 2028.88909775 
+30 -70.8272666419 30 -2124.81799926 150495.050999 1849.35480501 
+30 -84.6759364038 30 -2540.27809211 215100.426176 2161.99517858 
+30 -78.2019785074 30 -2346.05935522 183466.483274 2008.68093249 
+30 -83.4168528801 30 -2502.5055864 208751.140333 2131.193062 
+30 -75.180345213 30 -2255.41035639 169562.52919 1941.42738704 
+30 -72.095711004 30 -2162.87133012 155933.746355 1875.59694852 
+30 -77.6772982575 30 -2330.31894773 181012.879938 1996.80642599 
+30 -80.0447160452 30 -2401.34148136 192214.697003 2051.03994798 
+30 -72.9927693936 30 -2189.78308181 159838.331513 1894.44708052 
+30 -76.5090782418 30 -2295.27234725 175609.171602 1970.66404933 
+30 -75.3985261483 30 -2261.95578445 170548.13236 1946.19176719 
+30 -81.8868998862 30 -2456.60699658 201163.931189 2094.40448103 
+30 -80.6233760918 30 -2418.70128276 195003.863173 2064.5517838 
+30 -84.7806402101 30 -2543.4192063 215632.708633 2164.57806301 
+30 -74.0882553457 30 -2222.64766037 164672.087405 1917.79424552 
+30 -79.2447232828 30 -2377.34169848 188391.785045 2032.52538276 
+30 -84.0354474599 30 -2521.0634238 211858.692894 2146.26687887 
+30 -79.341677169 30 -2380.25031507 188853.052079 2034.75900252 
+30 -78.7920959757 30 -2363.76287927 186245.831647 2022.13508625 
+30 -71.3613280157 30 -2140.83984047 152773.174085 1860.34487441 
+30 -74.7462091654 30 -2242.38627496 167609.873538 1931.98971082 
+30 -71.6922182122 30 -2150.76654637 154193.224566 1867.19695917 
+30 -72.9458632504 30 -2188.37589751 159632.96896 1893.45544736 
+30 -70.7583638066 30 -2122.7509142 150202.381458 1847.94313443 
+30 -72.5843581494 30 -2177.53074448 158054.671439 1885.83508858 
+30 -83.094407334 30 -2492.83222002 207140.415905 2123.38127403 
+30 -80.8101003917 30 -2424.30301175 195908.16976 2068.9332735 
+30 -70.9686650562 30 -2129.05995169 151096.542596 1852.25621419 
+30 -79.1135769969 30 -2373.40730991 187768.741958 2029.50852704 
+30 -77.9274944183 30 -2337.82483255 182180.831589 2002.45853713 
+30 -75.2276737063 30 -2256.83021119 169776.086738 1942.45967841 
+30 -73.5930983055 30 -2207.79294916 162478.323546 1907.196794 
+30 -81.2620789903 30 -2437.86236971 198105.764455 2079.58226303 
+30 -70.8015545101 30 -2124.0466353 150385.803632 1848.82785228 
+30 -72.4218844679 30 -2172.65653404 157347.880496 1882.42298913 
+30 -70.9620276656 30 -2128.86082997 151068.281113 1852.11988481 
+30 -79.6481981573 30 -2389.44594472 190315.064091 2041.83917184 
+30 -77.3218423429 30 -2319.65527029 179360.019099 1988.80871374 
+30 -72.2232461557 30 -2166.69738467 156485.918558 1878.26215817 
+30 -78.833491121 30 -2365.00473363 186441.57967 2023.08278001 
+30 -73.51789999 30 -2205.5369997 162146.448568 1905.59381785 
+30 -72.5313740678 30 -2175.94122203 157824.006725 1884.72150307 
+30 -72.0335963753 30 -2161.00789126 155665.170203 1874.30065373 
+30 -80.1606177745 30 -2404.81853324 192771.73926 2053.73823297 
+30 -82.397973791 30 -2471.93921373 203682.782546 2106.61543239 
+30 -71.2243710046 30 -2136.73113014 152187.33075 1857.5183755 
+30 -83.5504957824 30 -2506.51487347 209420.560365 2134.43992999 
+30 -70.8000838359 30 -2124.00251508 150379.556135 1848.7977178 
+30 -73.1328346269 30 -2193.98503881 160452.345017 1897.41209912 
+30 -75.9717025857 30 -2279.15107757 173150.987813 1958.77616213 
+30 -79.7799818341 30 -2393.39945502 190945.365043 2044.89183884 
+30 -71.2921675123 30 -2138.76502537 152477.194458 1858.91684666 
+30 -72.105694444 30 -2163.17083332 155976.935137 1875.80540485 
+30 -73.3011540489 30 -2199.03462147 161191.775547 1900.9830122 
+30 -78.8618885387 30 -2365.85665616 186575.923917 2023.73320318 
+30 -77.3425090118 30 -2320.27527035 179455.911007 1989.27267328 
+30 -72.166865836 30 -2165.00597508 156241.695738 1877.08332931 
+30 -74.7655704166 30 -2242.9671125 167696.715592 1932.40940015 
+30 -75.3724348562 30 -2261.17304569 170430.118085 1945.62126428 
+30 -70.0879256758 30 -2102.63777028 147369.519766 1834.28165457 
+30 -83.2017710678 30 -2496.05313204 207676.041265 2125.97887802 
+30 -79.8616684442 30 -2395.85005333 191336.582601 2046.78666167 
+30 -76.910069346 30 -2307.30208038 177454.763004 1979.59126301 
+30 -84.4861128771 30 -2534.58338631 214137.098072 2157.3209057 
+30 -71.7956010589 30 -2153.86803177 154638.249942 1869.34454892 
+30 -73.948164083 30 -2218.44492249 164049.929137 1914.78852262 
+30 -76.2222073715 30 -2286.66622115 174294.746898 1964.30707896 
+30 -84.4749428203 30 -2534.24828461 214080.478935 2157.04618756 
+30 -74.0953869315 30 -2222.86160794 164703.790936 1917.94741448 
+30 -79.4860611562 30 -2384.58183469 189541.017544 2038.09054185 
+30 -74.9052049637 30 -2247.15614891 168323.69192 1935.43955588 
+30 -77.7851448251 30 -2333.55434475 181515.862664 1999.2404547 
+30 -70.5665182451 30 -2116.99554735 149389.004917 1844.0201359 
+30 -73.3843389429 30 -2201.53016829 161557.836063 1902.75092611 
+30 -78.7735006353 30 -2363.20501906 186157.93207 2021.70953487 
+30 -70.2348261146 30 -2107.04478344 147987.92398 1837.26350032 
+30 -75.8005999788 30 -2274.01799936 172371.928714 1955.00919359 
+30 -75.7943387745 30 -2273.83016323 172343.453708 1954.87151446 
+30 -70.5152683334 30 -2115.45805 149172.092044 1842.97400897 
+30 -81.9006106467 30 -2457.0183194 201231.300729 2094.73104566 
+30 -76.0942424992 30 -2282.82727498 173710.012246 1961.47937936 
+30 -74.9349841284 30 -2248.04952385 168457.55539 1936.08653885 
+30 -79.853231632 30 -2395.59694896 191296.158062 2046.59086659 
+30 -74.053799166 30 -2221.61397498 164518.955128 1917.05442626 
+30 -75.0013079877 30 -2250.03923963 168755.885996 1937.52844899 
+30 -73.043301622 30 -2191.29904866 160059.717355 1895.51611056 
+30 -78.4356865166 30 -2353.0705955 184564.70758 2013.99677301 
+30 -76.1171754837 30 -2283.51526451 173814.732108 1961.98577893 
+30 -74.1098008859 30 -2223.29402658 164767.877621 1918.25703744 
+30 -82.1908933196 30 -2465.72679959 202660.28834 2101.65827171 
+30 -71.3725879995 30 -2141.17763998 152821.389532 1860.57750666 
+30 -83.9758160836 30 -2519.27448251 211558.130607 2144.80879097 
+30 -84.6326216951 30 -2538.97865085 214880.41965 2160.92763198 
+30 -80.863020445 30 -2425.89061335 196164.842264 2070.17694599 
+30 -78.1862196591 30 -2345.58658977 183392.548337 2008.32307694 
+30 -81.7410415516 30 -2452.23124655 200447.936218 2090.93389993 
+30 -78.0805607144 30 -2342.41682143 182897.218844 2005.92567368 
+30 -78.0043964829 30 -2340.13189449 182540.57612 2004.19958324 
+30 -75.9000553116 30 -2277.00165935 172824.551889 1957.19771796 
+30 -80.8886431075 30 -2426.65929322 196289.177513 2070.77940524 
+30 -71.9360738678 30 -2158.08221603 155243.961705 1872.26775313 
+30 -71.8518803402 30 -2155.55641021 154880.781253 1870.51499601 
+30 -79.6806337235 30 -2390.4190117 190470.101717 2042.59003329 
+30 -77.5795147438 30 -2327.38544232 180557.433237 1994.60253013 
+30 -78.325564436 30 -2349.76693308 184046.821327 2011.48993331 
+30 -74.7218592619 30 -2241.65577786 167500.687546 1931.46204329 
+30 -72.4664208707 30 -2173.99262612 157541.464614 1883.35750742 
+30 -82.8222351992 30 -2484.66705598 205785.679302 2116.81172011 
+30 -79.7322251085 30 -2391.96675325 190716.831622 2043.78498928 
+30 -73.9376931411 30 -2218.13079423 164003.474011 1914.5641002 
+30 -73.15867505 30 -2194.7602515 160565.752052 1897.95975397 
+30 -71.9930132904 30 -2159.79039871 155489.818879 1873.45433443 
+30 -81.6652321047 30 -2449.95696314 200076.304042 2089.13259613 
+30 -84.9742582726 30 -2549.22774818 216618.737069 2169.36299164 
+30 -71.4593284715 30 -2143.77985414 153193.068768 1862.37084749 
+30 -81.5193990468 30 -2445.5819714 199362.372628 2085.67231386 
+30 -81.3466100026 30 -2440.39830008 198518.128767 2081.58068633 
+30 -73.3821060453 30 -2201.46318136 161548.004629 1902.70344361 
+30 -70.2700501121 30 -2108.10150336 148136.398283 1837.97945383 
+30 -79.3315607071 30 -2379.94682121 188804.895727 2034.5258081 
+30 -71.1649101569 30 -2134.94730471 151933.333129 1856.29298303 
+30 -82.118392119 30 -2463.55176357 202302.909726 2099.92575454 
+30 -74.6182789124 30 -2238.54836737 167036.626435 1929.21942299 
+30 -72.9506480024 30 -2188.51944007 159653.911319 1893.55657059 
+30 -78.2236000197 30 -2346.70800059 183567.948001 2009.17203999 
+30 -79.0565108301 30 -2371.6953249 187497.957139 2028.19740257 
+30 -78.4565591488 30 -2353.69677446 184662.950204 2014.47233166 
+30 -74.920344336 30 -2247.61033008 168391.739863 1935.76844106 
+30 -75.4585030858 30 -2263.75509257 170819.570638 1947.50397588 
+30 -78.9378895041 30 -2368.13668512 186935.711981 2025.47514278 
+30 -75.9505413423 30 -2278.51624027 173054.541906 1958.30980352 
+30 -70.1883185331 30 -2105.64955599 147792.001755 1836.31876987 
+30 -81.7676424001 30 -2453.029272 200578.42031 2091.56636975 
+30 -79.1498845629 30 -2374.49653689 187941.12679 2030.34322053 
+30 -76.2912276695 30 -2288.73683008 174610.54258 1965.83429215 
+30 -81.1427098354 30 -2434.28129506 197524.180783 2076.76387154 
+30 -73.4714323939 30 -2204.14297182 161941.54134 1904.60413241 
+30 -81.0110273765 30 -2430.3308213 196883.596698 2073.65971296 
+30 -76.8542608428 30 -2305.62782528 177197.322291 1978.34591582 
+30 -78.3294318265 30 -2349.88295479 184064.996708 2011.57790967 
+30 -82.3624670659 30 -2470.87401198 203507.279435 2105.76454688 
+30 -77.7824692792 30 -2333.47407838 181503.375815 1999.18002712 
+30 -78.1022251362 30 -2343.06675409 182998.727137 2006.41696683 
+30 -82.5840010463 30 -2477.52003139 204603.516864 2111.07958354 
+30 -78.1014250201 30 -2343.0427506 182994.977705 2006.39881976 
+30 -82.2314736157 30 -2466.94420847 202860.45759 2102.62868274 
+30 -83.8571179592 30 -2515.71353878 210960.486973 2141.90959639 
+30 -71.9624482573 30 -2158.87344772 155357.818775 1872.81725768 
+30 -83.8362364108 30 -2515.08709232 210855.436066 2141.40000302 
+30 -71.0939246587 30 -2132.81773976 151630.383701 1854.83147501 
+30 -72.0345554429 30 -2161.03666329 155669.315336 1874.3206601 
+30 -70.6459437196 30 -2119.37831159 149725.480921 1845.64294682 
+30 -71.5611412528 30 -2146.83423758 153629.908122 1864.47868467 
+30 -84.3284203182 30 -2529.85260955 213338.474201 2153.44605577 
+30 -80.1572162051 30 -2404.71648615 192755.379293 2053.65898431 
+30 -76.0099764814 30 -2280.29929444 173325.495741 1959.61999634 
+30 -70.8642456355 30 -2125.92736907 150652.239285 1850.1130122 
+30 -75.2505642977 30 -2257.51692893 169879.422814 1942.95919085 
+30 -81.683949124 30 -2450.51847372 200168.026335 2089.57716983 
+30 -77.5188106538 30 -2325.56431961 180274.980155 1993.23579279 
+30 -70.6384099498 30 -2119.1522985 149693.548807 1845.48893657 
+30 -74.8741753134 30 -2246.2252594 168184.263866 1934.76568784 
+30 -72.5874438794 30 -2177.62331638 158068.110269 1885.89996843 
+30 -75.6476629883 30 -2269.42988965 171677.067468 1951.6495901 
+30 -84.9306641053 30 -2547.91992316 216396.531161 2168.28465773 
+30 -72.4735127347 30 -2174.20538204 157572.301443 1883.50637266 
+30 -82.5750825357 30 -2477.25247607 204559.327673 2110.86532646 
+30 -75.9073948536 30 -2277.22184561 172857.977804 1957.35934288 
+30 -82.0878467012 30 -2462.63540104 202152.437281 2099.19630138 
+30 -79.1901310983 30 -2375.70393295 188132.305901 2031.26893118 
+30 -78.7153768449 30 -2361.46130535 185883.316555 2020.38005014 
+30 -80.3989020041 30 -2411.96706012 193919.503304 2059.29834002 
+30 -76.5069410225 30 -2295.20823067 175599.360739 1970.61659793 
+30 -75.62809695 30 -2268.8429085 171588.271449 1951.22028453 
+30 -71.0501945667 30 -2131.505837 151443.904439 1853.93187627 
+30 -79.4468563847 30 -2383.40569154 189354.089682 2037.18530612 
+30 -76.7318883806 30 -2301.95665142 176633.480833 1975.61848788 
+30 -75.7661319418 30 -2272.98395825 172215.202483 1954.25141346 
+30 -84.5378592323 30 -2536.13577697 214399.489307 2158.59405211 
+30 -81.4356697004 30 -2443.07009101 198953.048987 2083.68849266 
+30 -82.0468815165 30 -2461.40644549 201950.722997 2098.21845385 
+30 -77.1345126232 30 -2314.0353787 178491.991129 1984.60907118 
+30 -74.5843667481 30 -2237.53100244 166884.832897 1928.48588942 
+30 -74.3157976599 30 -2229.4739298 165685.133455 1922.68881903 
+30 -75.6197853465 30 -2268.5935604 171550.558076 1951.03795137 
+30 -82.2936114745 30 -2468.80834423 203167.154685 2104.11556482 
+30 -76.6327193447 30 -2298.98158034 176177.210225 1973.41151162 
+30 -74.5777007259 30 -2237.33102178 166855.003367 1928.34174129 
+30 -79.2470320677 30 -2377.41096203 188402.762746 2032.57853968 
+30 -78.960781993 30 -2368.82345979 187044.152788 2026.00017745 
+30 -79.1501779432 30 -2374.50533829 187942.520053 2030.34996681 
+30 -80.156460956 30 -2404.69382868 192751.74699 2053.64138923 
+30 -77.7698503653 30 -2333.09551096 181444.488775 1998.8950561 
+30 -70.1794746404 30 -2105.38423921 147754.759824 1836.13919314 
+30 -83.6896483505 30 -2510.68945051 210118.717231 2137.82634989 
+30 -79.4753891422 30 -2384.26167427 189490.124379 2037.84408004 
+30 -72.7758969938 30 -2183.27690981 158889.935498 1889.86775474 
+30 -77.2412467288 30 -2317.23740186 178986.305887 1987.00059439 
+30 -71.017140112 30 -2130.51420336 151303.02569 1853.25227337 
+30 -83.0457310218 30 -2491.37193065 206897.803228 2122.20471788 
+30 -81.6032711393 30 -2448.09813418 199772.815819 2087.66162574 
+30 -84.4555494499 30 -2533.6664835 213982.194986 2156.56931284 
+30 -81.058089665 30 -2431.74268995 197112.417004 2074.76851777 
+30 -82.9862099052 30 -2489.58629716 206601.331033 2120.76699774 
+30 -70.3366405393 30 -2110.09921618 148417.290071 1839.33396995 
+30 -72.6273157846 30 -2178.81947354 158241.809942 1886.73856287 
+30 -77.2902669572 30 -2318.70800872 179213.560989 1988.10010473 
+30 -84.9256647027 30 -2547.76994108 216371.055756 2168.16103025 
+30 -76.1670511397 30 -2285.01153419 174042.590379 1963.08766354 
+30 -78.3275355355 30 -2349.82606607 184056.084692 2011.53477181 
+30 -83.3220572338 30 -2499.66171701 208276.95665 2128.89324033 
+30 -71.8101210971 30 -2154.30363291 154700.804759 1869.64643297 
+30 -75.4953119217 30 -2264.85935765 170986.263665 1948.30983438 
+30 -70.8219147671 30 -2124.65744301 150472.308339 1849.24510562 
+30 -81.5673225701 30 -2447.0196771 199596.843338 2086.80872476 
+30 -77.598558567 30 -2327.95675701 180646.08875 1995.03152483 
+30 -73.6391512521 30 -2209.17453756 162681.737914 1908.17932613 
+30 -72.2177280763 30 -2166.53184229 156462.007455 1878.14674122 
+30 -78.9401212431 30 -2368.20363729 186946.282256 2025.52632035 
+30 -76.0363211778 30 -2281.08963533 173445.664147 1960.20107985 
+30 -84.1802635013 30 -2525.40790504 212589.502894 2149.81231685 
+30 -76.8750599161 30 -2306.25179748 177293.245113 1978.80993063 
+30 -78.3257425085 30 -2349.77227526 184047.658185 2011.49398405 
+30 -70.1191045826 30 -2103.57313748 147500.664824 1834.91399568 
+30 -76.4106625579 30 -2292.31987674 175157.680576 1968.48040596 
+30 -71.0473972163 30 -2131.42191649 151431.979536 1853.87434977 
+30 -77.6733700951 30 -2330.20110285 180994.572658 1996.71783572 
+30 -81.3718995845 30 -2441.15698753 198641.58126 2082.17898161 
+30 -76.1383150509 30 -2284.14945153 173911.290564 1962.45271653 
+30 -76.7252063524 30 -2301.75619057 176602.718694 1975.46968871 
+30 -82.0379150508 30 -2461.13745152 201906.585176 2098.00448959 
+30 -71.1749729568 30 -2135.2491887 151976.303262 1856.50028659 
+30 -70.2478483853 30 -2107.43545156 148042.806083 1837.52814413 
+30 -70.6775546672 30 -2120.32664001 149859.502012 1846.28934406 
+30 -75.8649777985 30 -2275.94933395 172664.845691 1956.42549511 
+30 -83.4723330727 30 -2504.16999218 209028.911658 2132.54030849 
+30 -80.91934992 30 -2427.5804976 196438.235745 2071.50166628 
+30 -75.1594968168 30 -2254.7849045 169468.498852 1940.97287165 
+30 -79.5574556826 30 -2386.72367048 189881.662641 2039.74022144 
+30 -82.837200311 30 -2485.11600933 205860.052661 2117.17236307 
+30 -79.6511515791 30 -2389.53454737 190329.178436 2041.9075285 
+30 -79.8809407471 30 -2396.42822241 191428.940839 2047.23399863 
+30 -71.6320762377 30 -2148.96228713 153934.630384 1865.94909474 
+30 -72.9744442536 30 -2189.23332761 159758.085424 1894.05959393 
+30 -75.1534116929 30 -2254.60235079 169441.058672 1940.84023459 
+30 -75.8357636815 30 -2275.07291045 172531.891595 1955.78263521 
+30 -77.0193031858 30 -2310.57909557 177959.191897 1982.03148209 
+30 -83.8830504286 30 -2516.49151286 211090.984476 2142.54263456 
+30 -72.5487707468 30 -2176.46312241 157899.724106 1885.08704247 
+30 -72.9534166702 30 -2188.60250011 159666.030116 1893.61508808 
+30 -76.6839520951 30 -2300.51856285 176412.855268 1974.55131227 
+30 -79.5443528451 30 -2386.33058535 189819.122086 2039.4373458 
+30 -83.9830027597 30 -2519.49008279 211594.342576 2144.98446081 
+30 -76.2601135806 30 -2287.80340742 174468.1477 1965.14565331 
+30 -80.3529110103 30 -2410.58733031 193697.709235 2058.22386292 
+30 -74.7465538738 30 -2242.39661621 167611.41948 1931.997182 
+30 -78.889167055 30 -2366.67501165 186705.020359 2024.3582265 
+30 -80.0895484637 30 -2402.68645391 192430.073194 2052.08320462 
+30 -78.7901585155 30 -2363.70475546 186236.672367 2022.09074295 
+30 -82.4961142175 30 -2474.88342652 204168.265829 2108.96924348 
+30 -74.5181690279 30 -2235.54507084 166588.725458 1927.05500052 
+30 -78.6461505669 30 -2359.38451701 185556.50997 2018.79793692 
+30 -81.5205029239 30 -2445.61508772 199367.771909 2085.69848235 
+30 -72.0357218423 30 -2161.07165527 155674.35664 1874.34499182 
+30 -71.5298709596 30 -2145.89612879 153495.673185 1863.83096271 
+30 -77.9450204513 30 -2338.35061354 182262.786395 2002.85516664 
+30 -78.8879519114 30 -2366.63855734 186699.268703 2024.33037958 
+30 -84.3111538749 30 -2529.33461625 213251.120032 2153.02223475 
+30 -73.093087815 30 -2192.79263445 160277.98459 1896.57010709 
+30 -71.3953702668 30 -2141.861108 152918.966866 1861.04830663 
+30 -75.7613072468 30 -2272.8392174 172193.270272 1954.14537093 
+30 -78.4704686697 30 -2354.11406009 184728.433597 2014.78931648 
+30 -83.0592160682 30 -2491.77648205 206965.001216 2122.53059403 
+30 -76.3876178063 30 -2291.62853419 175052.044624 1967.96950976 
+30 -74.4405346245 30 -2233.21603873 166241.795855 1925.37857831 
+30 -81.6942705793 30 -2450.82811738 200218.615364 2089.82237389 
+30 -80.9202587762 30 -2427.60776329 196442.648412 2071.52304798 
+30 -80.532984066 30 -2415.98952198 194566.845677 2062.43449034 
+30 -78.4478792884 30 -2353.43637865 184622.092945 2014.27455526 
+30 -79.0415664807 30 -2371.24699442 187427.076951 2027.8542099 
+30 -83.8331351435 30 -2514.99405431 210839.83644 2141.32433084 
+30 -79.2988692375 30 -2378.96607713 188649.319871 2033.77244742 
+30 -70.9359044662 30 -2128.07713399 150957.076273 1851.58345302 
+30 -81.6388948826 30 -2449.16684648 199947.274729 2088.50720249 
+30 -74.4620305333 30 -2233.860916 166337.819734 1925.84257577 
+30 -80.8094089216 30 -2424.28226765 195904.817108 2068.91702885 
+30 -73.6420669206 30 -2209.26200762 162694.62061 1908.24155286 
+30 -71.1684945313 30 -2135.05483594 151948.638416 1856.36682118 
+30 -74.5609110707 30 -2236.82733212 166779.883791 1927.97873565 
+30 -82.4300424359 30 -2472.90127308 203841.35688 2107.38425257 
+30 -81.3506824769 30 -2440.52047431 198538.006184 2081.67701906 
+30 -77.3424538994 30 -2320.27361698 179455.655255 1989.27143585 
+30 -77.4690784826 30 -2324.07235448 180043.743628 1992.11690928 
+30 -82.3348849591 30 -2470.04654877 203370.998437 2105.10382846 
+30 -80.0758695291 30 -2402.27608587 192364.346425 2051.76482998 
+30 -70.6428348533 30 -2119.2850456 149712.303483 1845.57939128 
+30 -81.2317834233 30 -2436.9535027 197958.079144 2078.86655815 
+30 -84.7390364707 30 -2542.17109412 215421.12906 2163.55136795 
+30 -83.9941105531 30 -2519.82331659 211650.318228 2145.25600823 
+30 -70.7121072105 30 -2121.36321631 150006.063184 1846.99623551 
+30 -76.1715820741 30 -2285.14746222 174063.29747 1963.1878008 
+30 -75.5531595742 30 -2266.59478723 171248.397649 1949.57711857 
+30 -74.0763859014 30 -2222.29157704 164619.328446 1917.5393528 
+30 -81.183904875 30 -2435.51714625 197724.792323 2077.73603296 
+30 -71.0385690742 30 -2131.15707223 151394.348883 1853.69281761 
+30 -71.3388168874 30 -2140.16450662 152676.803847 1859.87990657 
+30 -82.3944809067 30 -2471.8344272 203665.514517 2106.5317119 
+30 -84.6317828542 30 -2538.95348563 214876.160072 2160.90696322 
+30 -77.5512326641 30 -2326.53697992 180425.810632 1993.96562866 
+30 -80.0799033244 30 -2402.39709973 192383.727493 2051.85870997 
+30 -72.9042419192 30 -2187.12725757 159450.854694 1892.57609203 
+30 -83.5046067554 30 -2505.13820266 209190.580481 2133.32444734 
+30 -80.2249631129 30 -2406.74889339 193081.341194 2055.23798363 
+30 -76.1733908215 30 -2285.20172465 174071.564077 1963.22777727 
+30 -71.7935796304 30 -2153.80738891 154629.542285 1869.3025267 
+30 -84.1233564215 30 -2523.70069264 212302.172868 2148.41834703 
+30 -82.9708358578 30 -2489.12507573 206524.788088 2120.39581355 
+30 -81.4324994539 30 -2442.97498362 198937.559019 2083.61342051 
+30 -81.0813342379 30 -2432.44002714 197225.482854 2075.31641359 
+30 -84.88801223 30 -2546.6403669 216179.238611 2167.23018388 
+30 -83.4599441401 30 -2503.7983242 208966.868276 2132.23938328 
+30 -75.8039210065 30 -2274.11763019 172387.033199 1955.08222524 
+30 -80.3742969579 30 -2411.22890874 193800.828345 2058.723419 
+30 -76.0279803364 30 -2280.83941009 173407.613821 1960.01708385 
+30 -70.693155071 30 -2120.79465213 149925.665217 1846.60845978 
+30 -73.9600754613 30 -2218.80226384 164102.782867 1915.04385774 
+30 -71.5464214464 30 -2146.39264339 153566.712654 1864.17374718 
+30 -82.4089908294 30 -2472.26972488 203737.253085 2106.87952231 
+30 -84.4257158248 30 -2532.77147475 213831.044776 2155.83593701 
+30 -72.2354291129 30 -2167.06287339 156538.716574 1878.51701103 
+30 -79.5623771193 30 -2386.87131358 189905.155586 2039.85399509 
+30 -76.8579844633 30 -2305.7395339 177214.493273 1978.42897802 
+30 -80.9817758511 30 -2429.45327553 196741.4406 2072.97087111 
+30 -78.3461216811 30 -2350.38365043 184143.443474 2011.95762611 
+30 -77.8960395151 30 -2336.88118545 182033.789164 2001.74691618 
+30 -77.1002283956 30 -2313.00685187 178333.35656 1983.8416115 
+30 -73.7948744214 30 -2213.84623264 163370.504726 1911.50636781 
+30 -72.5436404231 30 -2176.30921269 157877.392975 1884.97923456 
+30 -81.6153510042 30 -2448.46053013 199831.965586 2087.94831468 
+30 -78.0254332465 30 -2340.76299739 182639.046999 2004.67616006 
+30 -71.5441533111 30 -2146.32459933 153556.97619 1864.12676597 
+30 -82.9007684106 30 -2487.02305232 206176.122092 2118.70503415 
+30 -83.543413649 30 -2506.30240947 209385.058924 2134.26773438 
+30 -72.5582718808 30 -2176.74815642 157941.08455 1885.28671884 
+30 -78.6679997558 30 -2360.03999268 185659.625568 2019.29712802 
+30 -76.1718734044 30 -2285.15620213 174064.628938 1963.19423964 
+30 -79.2400151582 30 -2377.20045475 188369.400068 2032.41698897 
+30 -81.7403386497 30 -2452.21015949 200444.488877 2090.9171904 
+30 -84.0506378428 30 -2521.51913528 211935.291654 2146.63847989 
+30 -84.4857696801 30 -2534.5730904 214135.358353 2157.31246451 
+30 -73.3594839809 30 -2200.78451943 161448.416698 1902.22247051 
+30 -79.7127754787 30 -2391.38326436 190623.797235 2043.33440457 
+30 -71.8446250043 30 -2155.33875013 154849.50426 1870.36405255 
+30 -77.1594793086 30 -2314.78437926 178607.557415 1985.16817759 
+30 -76.1643909509 30 -2284.93172853 174030.433468 1963.02887413 
+30 -74.4896922256 30 -2234.69076677 166461.427436 1926.43986801 
+30 -74.3431570877 30 -2230.29471263 165807.150173 1923.27838305 
+30 -72.3224683227 30 -2169.67404968 156916.182729 1880.3390624 
+30 -83.2478578455 30 -2497.43573536 207906.175076 2127.09498199 
+30 -79.7409121987 30 -2392.22736596 190758.392349 2043.98627759 
+30 -75.008548398 30 -2250.25645194 168788.469983 1937.68593862 
+30 -78.2361884863 30 -2347.08565459 183627.035666 2009.45803696 
+30 -74.4309180648 30 -2232.92754194 166198.846919 1925.17104605 
+30 -78.1578937077 30 -2344.73681123 183259.690465 2007.68003204 
+30 -84.7333649563 30 -2542.00094869 215392.294104 2163.4114468 
+30 -76.1214935653 30 -2283.64480696 173834.453478 1962.08114722 
+30 -83.1494466927 30 -2494.48340078 207414.914559 2124.71248778 
+30 -74.3989540586 30 -2231.96862176 166056.13095 1924.48143921 
+30 -82.0227078015 30 -2460.68123404 201831.737853 2097.64165841 
+30 -76.6708216693 30 -2300.12465008 176352.446863 1974.25911806 
+30 -83.6747067693 30 -2510.24120308 210043.696588 2137.46245286 
+30 -76.52981758 30 -2295.8945274 175704.389365 1971.12458364 
+30 -71.4824512999 30 -2144.473539 153292.225315 1862.8492881 
+30 -73.942668924 30 -2218.28006772 164025.548628 1914.67074145 
+30 -74.17274101 30 -2225.1822303 165047.865268 1919.60977058 
+30 -72.364313129 30 -2170.92939387 157097.814439 1881.21583735 
+30 -72.0493469257 30 -2161.48040777 155733.251772 1874.62924867 
+30 -82.998176034 30 -2489.94528102 206660.916749 2121.05595172 
+30 -84.8039937545 30 -2544.11981263 215751.520701 2165.15460819 
+30 -82.1296731418 30 -2463.89019425 202358.496311 2100.1952267 
+30 -74.1534386506 30 -2224.60315952 164961.973911 1919.19479057 
+30 -79.9445847492 30 -2398.33754248 191734.098922 2048.71205605 
+30 -70.902121933 30 -2127.06365799 150813.326838 1850.89004274 
+30 -81.533874732 30 -2446.01624196 199433.181864 2086.01550327 
+30 -82.1379597454 30 -2464.13879236 202399.332934 2100.39319486 
+30 -83.2644974245 30 -2497.93492273 207989.29594 2127.49810663 
+30 -75.3095166123 30 -2259.28549837 170145.698771 1944.2463564 
+30 -70.0919776472 30 -2102.75932942 147386.559915 1834.36381634 
+30 -81.0316752574 30 -2430.95025772 196983.97185 2074.14610281 
+30 -82.7155163296 30 -2481.46548989 205255.69925 2114.241859 
+30 -75.4493035414 30 -2263.47910624 170777.922146 1947.30263308 
+30 -75.6082431522 30 -2268.24729457 171498.192977 1950.78478252 
+30 -70.2565075086 30 -2107.69522526 148079.305419 1837.70414646 
+30 -83.2298016726 30 -2496.89405018 207815.996594 2126.65763171 
+30 -80.8953423664 30 -2426.86027099 196321.692497 2070.93695571 
+30 -77.0353761636 30 -2311.06128491 178033.47542 1982.39084498 
+30 -81.2203664605 30 -2436.61099382 197902.43784 2078.59691435 
+30 -81.1908450238 30 -2435.72535071 197758.59947 2077.89986358 
+30 -80.4819451446 30 -2414.45835434 194320.304828 2061.24006528 
+30 -78.7065592861 30 -2361.19677858 185841.67424 2020.17845173 
+30 -82.480660533 30 -2474.41981599 204091.780859 2108.59840889 
+30 -79.0444095196 30 -2371.33228559 187440.560289 2027.91949431 
+30 -73.2457557627 30 -2197.37267288 160948.222117 1899.80679376 
+30 -73.7157058523 30 -2211.47117557 163020.158679 1909.81401401 
+30 -79.3353692573 30 -2380.06107772 188823.024456 2034.61359534 
+30 -77.2568664553 30 -2317.70599366 179058.702435 1987.35086233 
+30 -74.2886681772 30 -2228.66004532 165564.186586 1922.1044318 
+30 -79.2028387152 30 -2376.08516146 188192.689816 2031.56132005 
+30 -72.2013248002 30 -2166.03974401 156390.939087 1877.80370184 
+30 -78.2774112013 30 -2348.32233604 183820.593131 2010.39490725 
+30 -71.5211333462 30 -2145.63400039 153458.175454 1863.65002726 
+30 -75.5716164392 30 -2267.14849318 171332.076337 1949.98166936 
+30 -72.9471077241 30 -2188.41323172 159638.415759 1893.481748 
+30 -77.0168463643 30 -2310.50539093 177947.838717 1981.97655881 
+30 -81.9211576359 30 -2457.63472908 201332.282052 2095.22054203 
+30 -78.4523177513 30 -2353.56953254 184642.984816 2014.37568577 
+30 -74.7624711707 30 -2242.87413512 167682.812867 1932.34221096 
+30 -82.8163783251 30 -2484.49134975 205756.575566 2116.67059409 
+30 -80.6102996631 30 -2418.30898989 194940.612353 2064.24533702 
+30 -70.1442227075 30 -2104.32668122 147606.359377 1835.42362985 
+30 -76.0473497755 30 -2281.42049326 173495.982236 1960.44439885 
+30 -71.3524112761 30 -2140.57233828 152734.997847 1860.16068078 
+30 -72.5917233019 30 -2177.75169906 158086.748758 1885.98995131 
+30 -71.5850840667 30 -2147.552522 153732.727825 1864.97482608 
+30 -82.8992928522 30 -2486.97878557 206168.782662 2118.66944367 
+30 -81.0804922284 30 -2432.41476685 197221.3866 2075.29656383 
+30 -77.257682236 30 -2317.73046708 179062.483934 1987.36915799 
+30 -74.7516789016 30 -2242.55036705 167634.404958 1932.10826562 
+30 -78.8547185488 30 -2365.64155646 186541.999122 2023.5689567 
+30 -75.8518377056 30 -2275.55513117 172605.0385 1956.13631422 
+30 -84.7986413051 30 -2543.95923915 215724.287016 2165.0224541 
+30 -81.0843075818 30 -2432.52922745 197239.948081 2075.38650972 
+30 -71.710974571 30 -2151.32923713 154273.916218 1867.58635016 
+30 -71.1933595696 30 -2135.80078709 152054.833404 1856.87914734 
+30 -75.9306522783 30 -2277.91956835 172963.918662 1957.8716041 
+30 -81.7302290014 30 -2451.90687004 200394.909979 2090.67687814 
+30 -70.2151945202 30 -2106.45583561 147905.206245 1836.86463534 
+30 -70.3965301825 30 -2111.89590548 148670.143852 1840.55332162 
+30 -82.1017919001 30 -2463.053757 202221.126996 2099.52929106 
+30 -79.4376763467 30 -2383.1302904 189310.332701 2036.97340624 
+30 -76.6728647045 30 -2300.18594113 176361.84546 1974.30457877 
+30 -84.2471374665 30 -2527.41412399 212927.405139 2151.45167259 
+30 -79.6957584208 30 -2390.87275262 190542.417308 2042.94026772 
+30 -82.0152008804 30 -2460.45602641 201794.795264 2097.46257566 
+30 -73.702497266 30 -2211.07491798 162961.743097 1909.53184254 
+30 -79.6979549412 30 -2390.93864824 190552.920654 2042.99113707 
+30 -79.0775546343 30 -2372.32663903 187597.789408 2028.68078106 
+30 -79.7531812163 30 -2392.59543649 190817.097424 2044.27060121 
+30 -74.3695994482 30 -2231.08798345 165925.119663 1923.84839873 
+30 -82.5561920593 30 -2476.68576178 204465.74542 2110.41158305 
+30 -77.4321310392 30 -2322.96393117 179872.047518 1991.28613931 
+30 -70.8285764311 30 -2124.85729293 150500.617178 1849.38165356 
+30 -72.2781185995 30 -2168.34355798 156723.792848 1879.41037529 
+30 -72.8595226851 30 -2185.78568055 159255.301377 1891.63186487 
+30 -83.7446174038 30 -2512.33852211 210394.828323 2139.16567856 
+30 -72.8641821796 30 -2185.92546539 159275.671341 1891.73022007 
+30 -73.2137359011 30 -2196.41207703 160807.533738 1899.12736676 
+30 -71.8463659372 30 -2155.39097812 154857.008952 1870.4002703 
+30 -77.426155083 30 -2322.78465249 179844.284728 1991.15180733 
+30 -71.7641837978 30 -2152.92551393 154502.942285 1868.69157358 
+30 -79.0319116235 30 -2370.9573487 187381.291646 2027.63252451 
+30 -82.6013903952 30 -2478.04171185 204689.690856 2111.49741149 
+30 -79.6713012026 30 -2390.13903608 190425.487059 2042.3739594 
+30 -81.1137282667 30 -2433.411848 197383.1074 2076.0802408 
+30 -70.4037087671 30 -2112.11126301 148700.466245 1840.69954965 
+30 -78.6550314313 30 -2359.65094294 185598.419084 2019.00082185 
+30 -83.763579619 30 -2512.90738857 210490.118118 2139.62790587 
+30 -77.6172219242 30 -2328.51665773 180732.994177 1995.45205444 
+30 -73.0915230518 30 -2192.74569155 160271.122261 1896.53696902 
+30 -73.1308787161 30 -2193.92636148 160443.762654 1897.37065423 
+30 -83.0501976845 30 -2491.50593054 206920.060063 2122.31265205 
+30 -72.7043920215 30 -2181.13176065 158577.858577 1888.36099887 
+30 -71.7704331824 30 -2153.11299547 154529.852376 1868.82143699 
+30 -84.8274583368 30 -2544.8237501 215870.930636 2165.73405943 
+30 -75.9635526133 30 -2278.9065784 173113.839769 1958.59653438 
+30 -72.8917416806 30 -2186.75225042 159396.180157 1892.31209453 
+30 -70.2625889667 30 -2107.877669 148104.942249 1837.82776952 
+30 -84.7671780163 30 -2543.01534049 215564.234066 2164.24578682 
+30 -82.2573619697 30 -2467.72085909 202988.207946 2103.24801825 
+30 -71.2274185862 30 -2136.82255759 152200.354754 1857.58120983 
+30 -72.9636339907 30 -2188.90901972 159710.756554 1893.83105728 
+30 -79.8866261934 30 -2396.5987858 191456.191337 2047.36598704 
+30 -83.9836397918 30 -2519.50919375 211597.55258 2145.00003306 
+30 -74.0378719038 30 -2221.13615711 164448.194281 1916.71256748 
+30 -77.3414969897 30 -2320.24490969 179451.214698 1989.24995075 
+30 -78.3362427789 30 -2350.08728337 184097.007982 2011.73285782 
+30 -74.8009984397 30 -2244.02995319 167855.681027 1933.17765631 
+30 -72.7437785118 30 -2182.31335535 158749.719365 1889.19076294 
+30 -83.6369896017 30 -2509.10968805 209854.380889 2136.54416224 
+30 -74.2264628115 30 -2226.79388434 165287.033445 1920.76532012 
+30 -75.065706728 30 -2251.97120184 169045.809797 1938.92976894 
+30 -74.1199927392 30 -2223.59978218 164813.19971 1918.47600399 
+30 -82.3286506578 30 -2469.85951973 203340.201574 2104.95451988 
+30 -73.0402505455 30 -2191.20751637 160046.345993 1895.45154205 
+30 -79.1085225779 30 -2373.25567734 187744.750334 2029.39235974 
+30 -77.579752466 30 -2327.39257398 180558.539781 1994.60788455 
+30 -70.9054363793 30 -2127.16309138 150827.427244 1850.95805894 
+30 -81.5325922977 30 -2445.97776893 199426.908204 2085.98509679 
+30 -70.8896136221 30 -2126.68840866 150760.119585 1850.63338771 
+30 -73.7977227435 30 -2213.9316823 163383.116464 1911.56729026 
+30 -74.9625546074 30 -2248.87663822 168581.537798 1936.68577303 
+30 -72.9757281952 30 -2189.27184586 159763.707169 1894.0867397 
+30 -71.301077224 30 -2139.03231672 152515.308399 1859.10073408 
+30 -75.8209650773 30 -2274.62895232 172464.562358 1955.45708798 
+30 -79.3684873195 30 -2381.05461958 188980.703381 2035.37715142 
+30 -82.570027393 30 -2477.10082179 204534.28271 2110.74389301 
+30 -83.154992545 30 -2494.64977635 207442.583555 2124.84667336 
+30 -75.2135002622 30 -2256.40500787 169712.118651 1942.15046806 
+30 -78.0936719833 30 -2342.8101595 182958.648115 2006.22298659 
+30 -79.7254249051 30 -2391.76274715 190684.301289 2043.62743777 
+30 -84.9610269246 30 -2548.83080774 216551.282883 2169.03564422 
+30 -84.3413242112 30 -2530.23972634 213403.769091 2153.7628523 
+30 -72.4201765908 30 -2172.60529772 157340.459323 1882.38716417 
+30 -79.4938425007 30 -2384.81527502 189578.129866 2038.27026745 
+30 -78.0209472378 30 -2340.62841713 182618.046237 2004.57452075 
+30 -74.6237036649 30 -2238.71110995 167060.91446 1929.33679455 
+30 -75.4218883005 30 -2262.65664902 170653.837045 1946.702769 
+30 -71.4812376998 30 -2144.437131 153287.020293 1862.82417319 
+30 -74.9106493745 30 -2247.31948124 168348.161691 1935.55782143 
+30 -74.0871110422 30 -2222.61333127 164667.000678 1917.76967011 
+30 -83.3992493216 30 -2501.97747965 208663.043622 2130.76578112 
+30 -75.1367153445 30 -2254.10146033 169365.779783 1940.47636241 
+30 -79.7993358649 30 -2393.98007595 191038.020134 2045.34059877 
+30 -83.3846690785 30 -2501.54007235 208590.09112 2130.41195379 
+30 -70.0325487997 30 -2100.97646399 147136.736742 1833.15927211 
+30 -82.9689720615 30 -2489.06916185 206515.509748 2120.3508197 
+30 -74.1891882538 30 -2225.67564761 165121.069613 1919.96345687 
+30 -79.2515053451 30 -2377.54516035 188424.032984 2032.68153591 
+30 -75.3724738312 30 -2261.17421494 170430.294343 1945.62211634 
+30 -80.3063267573 30 -2409.18980272 193473.183517 2057.13617252 
+30 -76.9193674342 30 -2307.58102303 177497.672594 1979.7988374 
+30 -80.2106283257 30 -2406.31884977 193012.346892 2054.90376322 
+30 -70.9834191505 30 -2129.50257452 151159.373829 1852.55930478 
+30 -80.0404466331 30 -2401.21339899 192194.192917 2050.94062961 
+30 -81.7406270815 30 -2452.21881244 200445.90347 2090.92404704 
+30 -84.9211194902 30 -2547.63358471 216347.896064 2168.0486407 
+30 -74.9894613149 30 -2249.68383945 168702.579249 1937.27080026 
+30 -73.9859596663 30 -2219.57878999 164217.666832 1915.59886441 
+30 -83.4595629108 30 -2503.78688732 208964.959238 2132.23012401 
+30 -75.4575038346 30 -2263.72511504 170815.046549 1947.48210487 
+30 -81.9185521679 30 -2457.55656504 201319.475679 2095.15846427 
+30 -78.1744276102 30 -2345.2328283 183337.233965 2008.05534912 
+30 -71.8059890169 30 -2154.17967051 154683.001761 1869.56051704 
+30 -71.7536536934 30 -2152.6096108 154457.604551 1868.47278248 
+30 -78.899135806 30 -2366.97407418 186752.208928 2024.58669278 
+30 -71.4732399009 30 -2144.19719703 153252.720658 1862.65867336 
+30 -77.4777023603 30 -2324.33107081 180083.830891 1992.31087769 
+30 -70.55466135 30 -2116.6398405 149338.807146 1843.77803972 
+30 -76.3149260211 30 -2289.44778063 174719.038008 1966.35899553 
+30 -70.2851049809 30 -2108.55314943 148199.879465 1838.28556859 
+30 -79.6516628523 30 -2389.54988557 190331.621854 2041.91936213 
+30 -80.2545741315 30 -2407.63722395 193223.900071 2055.92856976 
+30 -70.6760050473 30 -2120.28015142 149852.930683 1846.25764963 
+30 -73.9148130123 30 -2217.44439037 163901.987479 1914.07382764 
+30 -72.960199774 30 -2188.80599322 159695.722532 1893.75846283 
+30 -77.6061353394 30 -2328.18406018 180681.36727 1995.20223484 
+30 -73.5038522251 30 -2205.11556675 162084.488758 1905.29455462 
+30 -76.1752993331 30 -2285.25897999 174080.286854 1963.26995977 
+30 -82.059200754 30 -2461.77602262 202011.372852 2098.51246369 
+30 -83.2607545961 30 -2497.82263788 207970.597677 2127.40742244 
+30 -82.0686407224 30 -2462.05922167 202057.853701 2098.73778796 
+30 -74.3988528582 30 -2231.96558575 166055.679199 1924.47925635 
+30 -80.4594175373 30 -2413.78252612 194211.536113 2060.71311741 
+30 -70.6135060488 30 -2118.40518146 149588.017095 1844.97995594 
+30 -73.0515345189 30 -2191.54603557 160095.800867 1895.69035345 
+30 -78.6913145127 30 -2360.73943538 185769.689392 2019.82996108 
+30 -74.9522286212 30 -2248.56685864 168535.097258 1936.46131483 
+30 -78.3103114235 30 -2349.30934271 183975.146258 2011.14299772 
+30 -84.6532843041 30 -2539.59852912 214985.356304 2161.43681829 
+30 -70.7526492657 30 -2122.57947797 150178.121343 1847.82611977 
+30 -77.3907528174 30 -2321.72258452 179679.858649 1990.35622863 
+30 -75.7345212246 30 -2272.03563674 172071.531153 1953.55676485 
+30 -82.4317925461 30 -2472.95377638 203850.012671 2107.42621894 
+30 -80.1373279794 30 -2404.11983938 192659.74007 2053.19570437 
+30 -74.6425552436 30 -2239.27665731 167145.331599 1929.74474156 
+30 -76.6804004989 30 -2300.41201497 176396.51462 1974.47227273 
+30 -71.6522525928 30 -2149.56757778 154021.359049 1866.3676058 
+30 -83.4591236494 30 -2503.77370948 208962.75961 2132.21945531 
+30 -82.5208984588 30 -2475.62695376 204290.960473 2109.56412852 
+30 -73.4847195834 30 -2204.5415875 162000.120368 1904.88706215 
+30 -74.1788470667 30 -2225.365412 165075.040565 1919.74106752 
+30 -76.7894372666 30 -2303.683118 176898.530272 1976.90057341 
+30 -73.4402617527 30 -2203.20785258 161804.161389 1903.94061063 
+30 -78.0085341955 30 -2340.25602586 182559.94222 2004.29331045 
+30 -79.7598248307 30 -2392.79474492 190848.889711 2044.42457993 
+30 -78.6539730258 30 -2359.61919077 185593.424182 2018.97664114 
+30 -70.3945012854 30 -2111.83503856 148661.574336 1840.51199572 
+30 -80.8137271717 30 -2424.41181515 195925.754981 2069.01847953 
+30 -83.8691962415 30 -2516.07588724 211021.262346 2142.20441455 
+30 -74.4129575181 30 -2232.38872554 166118.647398 1924.78351885 
+30 -79.7914981725 30 -2393.74494518 191000.495418 2045.15885346 
+30 -73.5780151739 30 -2207.34045522 162411.729508 1906.87513616 
+30 -72.3075510879 30 -2169.22653264 156851.45833 1880.02662833 
+30 -80.9942444232 30 -2429.8273327 196802.02889 2073.26446113 
+30 -75.3185110236 30 -2259.55533071 170186.343084 1944.44283215 
+30 -80.5435618192 30 -2416.30685458 194617.960516 2062.68213121 
+30 -84.3489953406 30 -2530.46986022 213442.590449 2153.95120574 
+30 -78.5312916327 30 -2355.93874898 185014.912965 2016.1760961 
+30 -72.6829091899 30 -2180.4872757 158484.158649 1887.90861135 
+30 -82.5443730267 30 -2476.3311908 204407.205551 2110.12774799 
+30 -77.9964294303 30 -2339.89288291 182503.290116 2004.01912851 
+30 -84.2994932544 30 -2528.98479763 213192.136888 2152.7360645 
+30 -81.0518333711 30 -2431.55500113 197081.990785 2074.62107889 
+30 -84.743194956 30 -2542.29584868 215442.27274 2163.65396749 
+30 -84.5969850455 30 -2537.90955136 214699.496364 2160.04974303 
+30 -84.8206711142 30 -2544.62013343 215836.387448 2165.5664339 
+30 -79.7830565752 30 -2393.49169726 190960.083495 2044.96312504 
+30 -73.6072288182 30 -2208.21686455 162540.724029 1907.49819853 
+30 -73.7251571921 30 -2211.75471576 163061.96409 1910.01595256 
+30 -74.2582807771 30 -2227.74842331 165428.767919 1921.45012901 
+30 -81.5324710496 30 -2445.97413149 199426.315064 2085.98222203 
+30 -82.231784121 30 -2466.95352363 202861.989591 2102.63610987 
+30 -73.4928963197 30 -2204.78688959 162036.174284 1905.06119918 
+30 -77.4122922837 30 -2322.36876851 179779.889899 1990.84023028 
+30 -73.6789009976 30 -2210.36702993 162857.413566 1909.02789208 
+30 -79.8908016293 30 -2396.72404888 191476.205549 2047.46292652 
+30 -70.7516694874 30 -2122.55008462 150173.962058 1847.80605817 
+30 -77.1656173325 30 -2314.96851997 178635.974949 1985.30566175 
+30 -74.815156991 30 -2244.45470973 167919.231468 1933.4847896 
+30 -73.552403556 30 -2206.57210668 162298.682066 1906.32910766 
+30 -79.5473926412 30 -2386.42177924 189833.63028 2039.50760692 
+30 -81.0718490762 30 -2432.15547229 197179.341379 2075.09282009 
+30 -70.6093512925 30 -2118.28053877 149570.414698 1844.89506002 
+30 -77.0863102827 30 -2312.58930848 178268.97699 1983.53015224 
+30 -80.5394359081 30 -2416.18307724 194598.022092 2062.58553353 
+30 -81.6110596134 30 -2448.3317884 199810.951537 2087.84646297 
+30 -71.8895541211 30 -2156.68662363 155043.239752 1871.29903317 
+30 -84.43876434 30 -2533.1629302 213897.147698 2156.15666523 
+100 -77.3419931998 100 -7734.19931998 598178.391212 4297.53697306 
+100 -77.1961902032 100 -7719.61902032 595925.178188 4286.63541543 
+100 -71.298084549 100 -7129.8084549 508341.686036 3863.46321881 
+100 -84.2308124842 100 -8423.08124842 709482.977175 4836.83785466 
+100 -70.1604941676 100 -7016.04941676 492249.494185 3785.8462355 
+100 -81.2725217772 100 -8127.25217772 660522.279602 4599.43009357 
+100 -84.2024165156 100 -8420.24165156 709004.694707 4834.51743225 
+100 -81.0093295802 100 -8100.93295802 656251.147903 4578.73241557 
+100 -80.0260534744 100 -8002.60534744 640416.923469 4502.01948366 
+100 -73.3178050279 100 -7331.78050279 537550.053411 4004.45575448 
+100 -78.8442856999 100 -7884.42856999 621642.138753 4411.09997952 
+100 -72.8495626784 100 -7284.95626784 530705.878244 3971.40548452 
+100 -77.0539572636 100 -7705.39572636 593731.232998 4276.02127183 
+100 -81.4874617794 100 -8148.74617794 664020.642725 4616.38455918 
+100 -83.5166770164 100 -8351.66770164 697503.533987 4778.72597739 
+100 -71.6663942422 100 -7166.63942422 513607.206368 3888.87004623 
+100 -84.7227624201 100 -8472.27624201 717794.64721 4877.16633 
+100 -71.3400690617 100 -7134.00690617 508940.545374 3866.35255421 
+100 -84.142650608 100 -8414.2650608 707998.565135 4829.63619915 
+100 -83.5727589814 100 -8357.27589814 698440.604376 4783.27112443 
+100 -84.271738543 100 -8427.1738543 710172.591706 4840.18361217 
+100 -80.0709558686 100 -8007.09558686 641135.797372 4505.50159719 
+100 -75.2062467083 100 -7520.62467083 565597.954394 4139.9741552 
+100 -81.9521132593 100 -8195.21132593 671614.886767 4653.19415069 
+100 -74.1072483055 100 -7410.72483055 549188.425141 4060.67400494 
+100 -76.0396565514 100 -7603.96565514 578202.936845 4200.91554285 
+100 -79.9729419556 100 -7997.29419556 639567.144503 4497.90336763 
+100 -74.7525886127 100 -7475.25886127 558794.950429 4107.09328061 
+100 -70.0824968682 100 -7008.24968682 491155.636727 3780.57194147 
+100 -83.9292757435 100 -8392.92757435 704412.332683 4812.23847406 
+100 -76.2073819692 100 -7620.73819692 580756.50666 4213.26407838 
+100 -79.419125628 100 -7941.9125628 630739.751552 4455.15094369 
+100 -72.737268053 100 -7273.7268053 529071.016382 3963.51191178 
+100 -77.4672541908 100 -7746.72541908 600117.547187 4306.91960046 
+100 -70.7245825556 100 -7072.45825556 500196.657767 3824.17183244 
+100 -80.0527703141 100 -8005.27703141 640844.603496 4504.0910917 
+100 -79.9503118928 100 -7995.03118928 639205.237176 4496.15040615 
+100 -82.3779344373 100 -8237.79344373 678612.408215 4687.11720498 
+100 -81.6257951201 100 -8162.57951201 666277.042898 4627.32072669 
+100 -75.9103362559 100 -7591.03362559 576237.915049 4191.41373461 
+100 -75.9405877501 100 -7594.05877501 576697.286783 4193.63496454 
+100 -73.7536865537 100 -7375.36865537 543960.628026 4035.41892375 
+100 -75.7032160176 100 -7570.32160176 573097.691541 4176.23041766 
+100 -76.4603313039 100 -7646.03313039 584618.22631 4231.94030329 
+100 -84.4563572707 100 -8445.63572707 713287.628344 4855.29724854 
+100 -75.7147685561 100 -7571.47685561 573272.61775 4177.07616736 
+100 -79.4332550105 100 -7943.32550105 630964.200156 4456.23786326 
+100 -79.5105813933 100 -7951.05813933 632193.25535 4462.18982327 
+100 -82.1930448074 100 -8219.30448074 675569.661471 4672.36569534 
+100 -74.4857904039 100 -7448.57904039 554813.297209 4087.85201003 
+100 -70.1038600105 100 -7010.38600105 491455.118837 3782.01594416 
+100 -75.6781453768 100 -7567.81453768 572718.168768 4174.3954804 
+100 -83.6898474309 100 -8368.98474309 700399.056301 4792.77066293 
+100 -78.5214760611 100 -7852.14760611 616562.220281 4386.50741125 
+100 -70.7782441925 100 -7077.82441925 500955.985097 3827.83431501 
+100 -77.8323175397 100 -7783.23175397 605786.965361 4334.35403295 
+100 -71.9574150574 100 -7195.74150574 517786.958175 3909.04125323 
+100 -74.2548516055 100 -7425.48516055 551378.298696 4071.25436446 
+100 -74.029222681 100 -7402.9222681 548032.581075 4055.08984867 
+100 -75.3967978254 100 -7539.67978254 568467.712232 4153.8465666 
+100 -71.9987913683 100 -7199.87913683 518382.595849 3911.91600083 
+100 -81.3711303457 100 -8137.11303457 662126.085373 4607.202601 
+100 -84.1823096437 100 -8418.23096437 708666.125696 4832.87485437 
+100 -83.2281377819 100 -8322.81377819 692692.291865 4755.39111487 
+100 -71.8955908951 100 -7189.55908951 516897.599016 3904.74901784 
+100 -76.2001449153 100 -7620.01449153 580646.208512 4212.73068027 
+100 -76.3819480948 100 -7638.19480948 583420.199475 4226.14612714 
+100 -77.5156319172 100 -7751.56319172 600867.319152 4310.54751597 
+100 -71.7615947078 100 -7176.15947078 514972.6475 3895.45925073 
+100 -82.1045429231 100 -8210.45429231 674115.596861 4665.316627 
+100 -80.2970643167 100 -8029.70643167 644761.853789 4523.06660815 
+100 -73.9848335795 100 -7398.48335795 547375.559979 4051.91571595 
+100 -73.2152093775 100 -7321.52093775 536046.688419 3997.19541865 
+100 -76.3710935029 100 -7637.10935029 583254.392283 4225.34422766 
+100 -72.066001884 100 -7206.6001884 519350.862755 3916.58930906 
+100 -72.9853707279 100 -7298.53707279 532686.434029 3980.96874333 
+100 -81.0173091152 100 -8101.73091152 656380.437627 4579.35891535 
+100 -83.6049486004 100 -8360.49486004 698978.743048 4785.88134374 
+100 -74.9563671012 100 -7495.63671012 561845.696901 4121.83756675 
+100 -83.5468840796 100 -8354.68840796 698008.183941 4781.17370951 
+100 -81.6667520108 100 -8166.67520108 666945.8384 4630.56231197 
+100 -76.5137916075 100 -7651.37916075 585436.030615 4235.89567406 
+100 -82.6951035937 100 -8269.51035937 683848.015838 4712.50232021 
+100 -72.5784971916 100 -7257.84971916 526763.82546 3952.37288432 
+100 -77.3753359395 100 -7737.53359395 598694.261174 4300.03296602 
+100 -74.0483385792 100 -7404.83385792 548315.644633 4056.45737672 
+100 -81.9740291001 100 -8197.40291001 671974.14469 4654.9356507 
+100 -72.3416691017 100 -7234.16691017 523331.708842 3935.80437145 
+100 -74.3682707659 100 -7436.82707659 553063.969671 4079.39917144 
+100 -75.4511103015 100 -7545.11103015 569287.004573 4157.80724711 
+100 -77.9250575345 100 -7792.50575345 607231.459176 4341.34465204 
+100 -74.5586142911 100 -7455.86142911 555898.696501 4093.09694678 
+100 -84.6146487832 100 -8461.46487832 715963.87887 4868.28277239 
+100 -82.9358684843 100 -8293.58684843 687835.828124 4731.83946941 
+100 -83.5094644326 100 -8350.94644326 697383.064982 4778.14166383 
+100 -83.8343659993 100 -8383.43659993 702820.092251 4804.51454625 
+100 -75.2022776751 100 -7520.22776751 565538.256753 4139.68558957 
+100 -77.5703328946 100 -7757.03328946 601715.654538 4314.65244045 
+100 -81.6020292606 100 -8160.20292606 665889.117945 4625.44051657 
+100 -83.9162963755 100 -8391.62963755 704194.479738 4811.18165775 
+100 -83.7781075115 100 -8377.81075115 701877.129822 4799.94038033 
+100 -81.8251198855 100 -8182.51198855 669535.024428 4643.11232242 
+100 -74.8520240892 100 -7485.20240892 560282.551026 4114.2826949 
+100 -73.0274046648 100 -7302.74046648 533300.183208 3983.93240438 
+100 -76.0029681776 100 -7600.29681776 577645.117181 4198.21816546 
+100 -76.0582430733 100 -7605.82430733 578485.63394 4202.28256202 
+100 -84.150260105 100 -8415.0260105 708126.627574 4830.25748761 
+100 -78.566481654 100 -7856.6481654 617269.203949 4389.92981561 
+100 -77.3691940221 100 -7736.91940221 598599.218363 4299.57310676 
+100 -77.5685954388 100 -7756.85954388 601688.699836 4314.52201058 
+100 -82.1593216762 100 -8215.93216762 675015.41383 4669.67876496 
+100 -81.737519008 100 -8173.7519008 668102.201358 4636.16720927 
+100 -75.1318311908 100 -7513.18311908 564479.205808 4134.56645106 
+100 -78.430815435 100 -7843.0815435 615139.28098 4379.61936631 
+100 -75.0104075154 100 -7501.04075154 562656.123563 4125.75459902 
+100 -70.6612449763 100 -7066.12449763 499301.15416 3819.85265836 
+100 -78.4665079092 100 -7846.65079092 615699.286346 4382.33016196 
+100 -83.0406793368 100 -8304.06793368 689575.442473 4740.27551402 
+100 -81.0256802011 100 -8102.56802011 656516.085205 4580.01622552 
+100 -80.632847301 100 -8063.2847301 650165.606386 4549.24591368 
+100 -83.3258316987 100 -8332.58316987 694319.422829 4763.2825349 
+100 -77.5931346364 100 -7759.31346364 602069.454271 4316.36443476 
+100 -81.483644248 100 -8148.3644248 663958.427994 4616.08302935 
+100 -70.9618290744 100 -7096.18290744 503558.118559 3840.38602011 
+100 -71.1856179718 100 -7118.56179718 506739.220602 3855.73205808 
+100 -70.7883963201 100 -7078.83963201 501099.705358 3828.52753599 
+100 -70.7538993611 100 -7075.38993611 500611.42748 3826.172389 
+100 -83.1931978446 100 -8319.31978446 692110.816761 4752.57108919 
+100 -73.8947344625 100 -7389.47344625 546043.178128 4045.47905448 
+100 -78.1348959406 100 -7813.48959406 610506.196365 4357.19374198 
+100 -83.0368447884 100 -8303.68447884 689511.759242 4739.96668424 
+100 -76.0351015015 100 -7603.51015015 578133.666035 4200.58057642 
+100 -84.9383733229 100 -8493.83733229 721452.726274 4894.91769806 
+100 -78.7766540645 100 -7877.66540645 620576.12256 4405.93897764 
+100 -73.8568631101 100 -7385.68631101 545483.622846 4042.77595645 
+100 -81.4685104733 100 -8146.85104733 663711.819874 4614.88782319 
+100 -80.4427702662 100 -8044.27702662 647103.92881 4534.41271839 
+100 -84.8178165072 100 -8481.78165072 719406.199704 4884.98645725 
+100 -77.9806326805 100 -7798.06326805 608097.907326 4345.53795493 
+100 -81.8921435671 100 -8189.21435671 670632.317802 4648.43123009 
+100 -82.3665356743 100 -8236.65356743 678424.619899 4686.20676031 
+100 -74.4152553204 100 -7441.52553204 553763.02244 4082.7769739 
+100 -77.6250775922 100 -7762.50775922 602565.26712 4318.76364162 
+100 -82.7537084797 100 -8275.37084797 684817.626714 4717.20386237 
+100 -70.2947289297 100 -7029.47289297 494134.89153 3794.93763532 
+100 -83.2435133345 100 -8324.35133345 692948.251227 4756.6324728 
+100 -77.4447577586 100 -7744.47577586 599769.050429 4305.23335775 
+100 -78.5704666298 100 -7857.04666298 617331.822643 4390.23294664 
+100 -74.6596021801 100 -7465.96021801 557405.619769 4100.3790934 
+100 -78.3528177445 100 -7835.28177445 613916.404851 4373.69997989 
+100 -74.5620498426 100 -7456.20498426 555949.927673 4093.34451376 
+100 -70.0725495999 100 -7007.25495999 491016.220743 3779.89972972 
+100 -80.7176961265 100 -8071.76961265 651534.646797 4555.87899367 
+100 -71.5038803249 100 -7150.38803249 511280.490152 3877.64274995 
+100 -84.7442175882 100 -8474.42175882 718158.241464 4878.93066335 
+100 -73.076390171 100 -7307.6390171 534015.880043 3987.38842479 
+100 -78.2059460373 100 -7820.59460373 611616.999559 4362.5701327 
+100 -73.1018409253 100 -7310.18409253 534387.914666 3989.18497102 
+100 -76.1114879672 100 -7611.14879672 579295.860058 4206.20058037 
+100 -77.6687487664 100 -7766.87487664 603243.453493 4322.04539555 
+100 -82.8470338629 100 -8284.70338629 686363.101988 4724.69792528 
+100 -76.2107235053 100 -7621.07235053 580807.43772 4213.51037984 
+100 -76.5547327359 100 -7655.47327359 586062.710427 4238.92672029 
+100 -78.0504051366 100 -7805.04051366 609186.574199 4350.80685815 
+100 -78.1719098525 100 -7817.19098525 611084.748998 4359.99397036 
+100 -78.4195116663 100 -7841.95116663 614961.980998 4378.76112583 
+100 -79.3786238287 100 -7937.86238287 630096.592095 4452.0364009 
+100 -70.5395593943 100 -7053.95593943 497582.943954 3811.56582129 
+100 -79.948837282 100 -7994.8837282 639181.658274 4496.03619817 
+100 -76.6773899996 100 -7667.73899996 587942.213715 4248.01759358 
+100 -70.7976307989 100 -7079.76307989 501230.452674 3829.15818637 
+100 -80.4958850951 100 -8049.58850951 647958.751725 4538.55404589 
+100 -72.6552445976 100 -7265.52445976 527878.456754 3957.75417228 
+100 -75.510440156 100 -7551.0440156 570182.657256 4162.13718589 
+100 -84.482529575 100 -8448.2529575 713729.78034 4857.44257776 
+100 -74.4151640327 100 -7441.51640327 553761.663801 4082.77040892 
+100 -77.2809832731 100 -7728.09832731 597235.037566 4292.97272964 
+100 -77.1823529104 100 -7718.23529104 595711.560079 4285.60191812 
+100 -79.7718894387 100 -7977.18894387 636355.434462 4482.34744871 
+100 -73.9202968233 100 -7392.02968233 546421.028244 4047.30439916 
+100 -75.517294789 100 -7551.7294789 570286.181224 4162.63766915 
+100 -70.540371211 100 -7054.0371211 497594.397059 3811.62105727 
+100 -75.767119661 100 -7576.7119661 574065.642172 4180.91041171 
+100 -79.4866392723 100 -7948.66392723 631812.58228 4460.34631322 
+100 -80.3510191759 100 -8035.10191759 645628.628261 4527.26559337 
+100 -84.183190832 100 -8418.3190832 708680.961866 4832.94683225 
+100 -80.8650339759 100 -8086.50339759 653915.371993 4567.41427503 
+100 -73.2781009937 100 -7327.81009937 536968.008525 4001.64479014 
+100 -76.8625883366 100 -7686.25883366 590785.74858 4261.77227206 
+100 -74.654016347 100 -7465.4016347 557322.215674 4099.9760375 
+100 -83.3456003271 100 -8334.56003271 694648.909389 4764.88054612 
+100 -72.6159238653 100 -7261.59238653 527307.239881 3954.99638974 
+100 -71.8115226845 100 -7181.15226845 515689.479027 3898.91858842 
+100 -83.0691272759 100 -8306.91272759 690047.990638 4742.567135 
+100 -71.1247804151 100 -7112.47804151 505873.43891 3851.55524351 
+100 -70.1758227002 100 -7017.58227002 492464.609165 3786.88348908 
+100 -82.4049973249 100 -8240.49973249 679058.358411 4689.27929875 
+100 -77.6755039904 100 -7767.55039904 603348.392016 4322.5532001 
+100 -72.3564488096 100 -7235.64488096 523545.568433 3936.83672014 
+100 -78.7231330749 100 -7872.31330749 619733.168113 4401.85800788 
+100 -79.5821968655 100 -7958.21968655 633332.605794 4467.70753681 
+100 -82.5412718566 100 -8254.12718566 681306.15597 4700.17760021 
+100 -76.0797600808 100 -7607.97600808 578812.989395 4203.86554677 
+100 -80.90231062 100 -8090.231062 654518.386366 4570.33615528 
+100 -71.6363937952 100 -7163.63937952 513177.291598 3886.7954735 
+100 -80.9365467082 100 -8093.65467082 655072.459305 4573.02092975 
+100 -70.86857487 100 -7086.857487 502235.490411 3834.00601488 
+100 -82.5397263345 100 -8253.97263345 681280.642338 4700.05389585 
+100 -80.0428470207 100 -8004.28470207 640685.735917 4503.32156203 
+100 -83.9919316444 100 -8399.19316444 705464.458136 4817.34246157 
+100 -77.4603573597 100 -7746.03573597 600010.69623 4306.40258775 
+100 -71.980992674 100 -7198.0992674 518126.330633 3910.67917148 
+100 -79.7967324164 100 -7979.67324164 636751.850434 4484.26742113 
+100 -81.2252758956 100 -8122.52758956 659754.544431 4595.70953242 
+100 -78.5891375454 100 -7858.91375454 617625.254013 4391.6534262 
+100 -81.9404493585 100 -8194.04493585 671423.724107 4652.26749714 
+100 -80.3025189334 100 -8030.25189334 644849.454705 4523.49097619 
+100 -83.3178376568 100 -8331.78376568 694186.207181 4762.63644176 
+100 -73.8896373553 100 -7388.96373553 545967.850851 4045.11516086 
+100 -72.105975109 100 -7210.5975109 519927.164642 3919.37088544 
+100 -75.1337497404 100 -7513.37497404 564508.035005 4134.70580067 
+100 -72.6777959228 100 -7267.77959228 528206.202019 3959.33652029 
+100 -77.3995603306 100 -7739.95603306 599069.193937 4301.84706886 
+100 -78.6226359112 100 -7862.26359112 618151.887763 4394.20284904 
+100 -72.6174608537 100 -7261.74608537 527329.562084 3955.10415829 
+100 -83.4468580209 100 -8344.68580209 696337.811356 4773.07191173 
+100 -83.1895355739 100 -8318.95355739 692049.8829 4752.27557557 
+100 -80.5201209883 100 -8052.01209883 648348.988397 4540.44463952 
+100 -75.8359775513 100 -7583.59775513 575109.549115 4185.9578017 
+100 -71.5448613062 100 -7154.48613062 511866.717933 3880.4714364 
+100 -71.2736083196 100 -7127.36083196 507992.724289 3861.77960065 
+100 -70.9883685002 100 -7098.83685002 503934.846232 3842.20330991 
+100 -82.0042043874 100 -8200.42043874 672468.953721 4657.33425763 
+100 -82.4837459034 100 -8248.37459034 680356.833826 4695.57480437 
+100 -79.6789270736 100 -7967.89270736 634873.14196 4475.16839211 
+100 -70.1207831392 100 -7012.07831392 491692.422806 3783.16015618 
+100 -75.3245256324 100 -7532.45256324 567378.416175 4148.58076679 
+100 -80.1576820303 100 -8015.76820303 642525.398846 4512.23278916 
+100 -77.3159611427 100 -7731.59611427 597775.784741 4295.58902085 
+100 -72.7031613245 100 -7270.31613245 528574.966658 3961.11692998 
+100 -74.9739422671 100 -7497.39422671 562109.201908 4123.11115387 
+100 -74.7876968658 100 -7478.76968658 559319.960249 4109.63055908 
+100 -79.7278878213 100 -7972.78878213 635653.609644 4478.94832867 
+100 -73.837655669 100 -7383.7655669 545199.939469 4041.40555817 
+100 -75.2970970846 100 -7529.70970846 566965.282936 4146.58367197 
+100 -76.0897137097 100 -7608.97137097 578964.453242 4204.59798194 
+100 -71.5005358503 100 -7150.05358503 511232.662688 3877.41197381 
+100 -78.5542428707 100 -7855.42428707 617076.907299 4388.99892932 
+100 -73.1005137984 100 -7310.05137984 534368.511759 3989.0912743 
+100 -80.4829668653 100 -8048.29668653 647750.795544 4537.54656056 
+100 -78.876406313 100 -7887.6406313 622148.747285 4413.55272064 
+100 -70.1172472232 100 -7011.72472232 491642.835816 3782.92106102 
+100 -73.0319571426 100 -7303.19571426 533366.676407 3984.25348918 
+100 -75.4653908443 100 -7546.53908443 569502.521528 4158.84913053 
+100 -77.1848842063 100 -7718.48842063 595750.634994 4285.79096446 
+100 -81.9121796113 100 -8191.21796113 670960.516867 4650.02213531 
+100 -79.8266915814 100 -7982.66915814 637230.068884 4486.58361547 
+100 -72.8735286858 100 -7287.35286858 531055.118311 3973.09176984 
+100 -74.0259988276 100 -7402.59988276 547984.850242 4054.85925414 
+100 -77.6697682226 100 -7766.97682226 603259.289575 4322.12202732 
+100 -72.9800842513 100 -7298.00842513 532609.269732 3980.59613803 
+100 -75.6021129803 100 -7560.21129803 571567.948709 4168.8344611 
+100 -76.6303091664 100 -7663.03091664 587220.428294 4244.52636855 
+100 -70.3114963231 100 -7031.14963231 494370.651519 3796.07451679 
+100 -82.5120959269 100 -8251.20959269 680824.597426 4697.84274731 
+100 -77.9837211428 100 -7798.37211428 608146.076327 4345.77107878 
+100 -84.5691269953 100 -8456.91269953 715193.724075 4864.54580289 
+100 -70.9867633771 100 -7098.67633771 503912.057476 3842.09337894 
+100 -72.6004899718 100 -7260.04899718 527083.114415 3953.91434714 
+100 -71.6883951559 100 -7168.83951559 513922.600003 3890.39201213 
+100 -70.5669156287 100 -7056.69156287 497968.958135 3813.4275016 
+100 -77.4091126067 100 -7740.91126067 599217.071456 4302.56257576 
+100 -79.2309461935 100 -7923.09461935 627754.283471 4440.69405187 
+100 -70.9790719724 100 -7097.90719724 503802.865806 3841.5666491 
+100 -71.834011675 100 -7183.4011675 516012.523332 3900.47758747 
+100 -81.5216098392 100 -8152.16098392 664577.287077 4619.08241079 
+100 -78.7267021038 100 -7872.67021038 619789.362414 4402.13005681 
+100 -74.9989455692 100 -7499.89455692 562484.183649 4124.92355432 
+100 -83.3086308584 100 -8330.86308584 694032.79755 4761.8924106 
+100 -70.8538292479 100 -7085.38292479 502026.511908 3832.99798642 
+100 -76.2389910873 100 -7623.89910873 581238.376201 4215.59440329 
+100 -80.5349518738 100 -8053.49518738 648587.847331 4541.60185697 
+100 -81.8913824469 100 -8189.13824469 670619.851907 4648.37080342 
+100 -79.840040419 100 -7984.0040419 637443.20541 4487.615926 
+100 -78.4916632203 100 -7849.16632203 616094.119509 4384.2414395 
+100 -81.226534972 100 -8122.6534972 659774.998357 4595.80865435 
+100 -71.0453002973 100 -7104.53002973 504743.469434 3846.10409643 
+100 -71.405762127 100 -7140.5762127 509878.286494 3870.87702715 
+100 -82.3463427788 100 -8234.63427788 678092.016905 4684.59422758 
+100 -74.3154437384 100 -7431.54437384 552278.517803 4075.60397967 
+100 -77.5948973408 100 -7759.48973408 602096.809332 4316.49680331 
+100 -76.494140349 100 -7649.4140349 585135.350773 4234.44140299 
+100 -72.9838046256 100 -7298.38046256 532663.573763 3980.85835725 
+100 -81.8708738534 100 -8187.08738534 670283.998552 4646.74280812 
+100 -73.7172847861 100 -7371.72847861 543423.807624 4032.82582615 
+100 -73.9815354447 100 -7398.15354447 547326.758676 4051.67995477 
+100 -80.6565725008 100 -8065.65725008 650548.268757 4551.09991253 
+100 -81.6007876627 100 -8160.07876627 665868.854717 4625.34230443 
+100 -81.7084127289 100 -8170.84127289 667626.471067 4633.86132351 
+100 -78.8508051461 100 -7885.08051461 621744.947219 4411.59772323 
+100 -77.3588135577 100 -7735.88135577 598438.603505 4298.79598363 
+100 -74.2663150387 100 -7426.63150387 551548.554943 4072.07698712 
+100 -71.3125555348 100 -7131.25555348 508548.057691 3864.45889962 
+100 -76.1692100923 100 -7616.92100923 580174.856609 4210.45125781 
+100 -71.2623081076 100 -7126.23081076 507831.655683 3861.00250814 
+100 -72.7589889013 100 -7275.89889013 529387.046594 3965.03776072 
+100 -74.1109786311 100 -7411.09786311 549243.715366 4060.94113025 
+100 -82.6144361829 100 -8261.44361829 682514.506581 4706.03644245 
+100 -73.0896192705 100 -7308.96192705 534209.244511 3988.32217438 
+100 -71.7530508962 100 -7175.30508962 514850.031291 3894.86752921 
+100 -73.5171034937 100 -7351.71034937 540476.45061 4018.58949432 
+100 -84.1563370606 100 -8415.63370606 708228.906746 4830.75369108 
+100 -70.5237068865 100 -7052.37068865 497359.323302 3810.48734929 
+100 -79.6956524818 100 -7969.56524818 635139.702451 4476.45938105 
+100 -72.364379986 100 -7236.4379986 523660.349076 3937.39079541 
+100 -75.3236896414 100 -7532.36896414 567365.822119 4148.51988649 
+100 -71.4013814437 100 -7140.13814437 509815.727207 3870.57518243 
+100 -74.7005759 100 -7470.05759 558017.603979 4103.33658014 
+100 -72.3965500864 100 -7239.65500864 524126.046441 3939.63885699 
+100 -84.9451898422 100 -8494.51898422 721568.527733 4895.47966406 
+100 -83.4985597235 100 -8349.85597235 697200.94759 4777.25833864 
+100 -81.6358347651 100 -8163.58347651 666440.95178 4628.11517199 
+100 -76.3782397587 100 -7637.82397587 583363.550863 4225.87215492 
+100 -74.6733835867 100 -7467.33835867 557611.421629 4101.37364918 
+100 -81.7087721781 100 -8170.87721781 667632.345084 4633.88979498 
+100 -75.5775368669 100 -7557.75368669 571196.407886 4167.03819726 
+100 -71.1901665813 100 -7119.01665813 506803.981787 3856.04449248 
+100 -77.1911438442 100 -7719.11438442 595847.268798 4286.25848438 
+100 -70.9414155412 100 -7094.14155412 503268.443899 3838.98868064 
+100 -76.5926787953 100 -7659.26787953 586643.844504 4241.73752553 
+100 -74.5141450662 100 -7451.41450662 555235.781495 4089.89354481 
+100 -82.1152069582 100 -8211.52069582 674290.721378 4666.1655895 
+100 -75.0496006507 100 -7504.96006507 563244.255783 4128.59727729 
+100 -77.0286947415 100 -7702.86947415 593341.981358 4274.13816993 
+100 -83.3580796887 100 -8335.80796887 694856.944939 4765.88952547 
+100 -70.9933348921 100 -7099.33348921 504005.35991 3842.54346232 
+100 -81.0439977359 100 -8104.39977359 656812.956902 4581.45479017 
+100 -75.6598268494 100 -7565.98268494 572440.939889 4173.05513232 
+100 -80.2329528154 100 -8023.29528154 643732.671747 4518.0809767 
+100 -71.8246633398 100 -7182.46633398 515878.226388 3899.82947359 
+100 -75.0918373141 100 -7509.18373141 563878.403121 4131.66242232 
+100 -70.9675733709 100 -7096.75733709 503639.647015 3840.77930165 
+100 -79.7382612842 100 -7973.82612842 635819.031263 4479.7495031 
+100 -84.4911429667 100 -8449.11429667 713875.323983 4858.1487625 
+100 -78.7503171563 100 -7875.03171563 620161.245222 4403.93043322 
+100 -74.8280801559 100 -7482.80801559 559924.157982 4112.55058952 
+100 -80.3083766588 100 -8030.83766588 644943.536157 4523.94673914 
+100 -81.7867214345 100 -8178.67214345 668906.780301 4640.06709792 
+100 -73.2803523355 100 -7328.03523355 537001.003842 4001.80413837 
+100 -79.0224722697 100 -7902.24722697 624455.112361 4424.71938113 
+100 -78.0419704713 100 -7804.19704713 609054.915504 4350.16965134 
+100 -72.1757113806 100 -7217.57113806 520933.331329 3924.22737819 
+100 -72.0472689756 100 -7204.72689756 519080.896684 3915.28631098 
+100 -72.3715023162 100 -7237.15023162 523763.434751 3937.88841796 
+100 -82.7051523891 100 -8270.51523891 684014.223171 4713.30823488 
+100 -82.4489332271 100 -8244.89332271 679782.659028 4692.79096207 
+100 -80.0851907879 100 -8008.51907879 641363.778353 4506.60591479 
+100 -75.2838719402 100 -7528.38719402 566766.137431 4145.62100731 
+100 -77.9446365087 100 -7794.46365087 607536.636047 4342.82158896 
+100 -76.4126256591 100 -7641.26256591 583888.936012 4228.41311591 
+100 -80.1051336246 100 -8010.51336246 641683.243302 4508.15338245 
+100 -73.9741395246 100 -7397.41395246 547217.33184 4051.15131039 
+100 -74.4515242025 100 -7445.15242025 554302.945607 4085.38591753 
+100 -84.118319886 100 -8411.8319886 707589.174045 4827.65007051 
+100 -71.1149649132 100 -7111.49649132 505733.82346 3850.88170502 
+100 -71.1928618757 100 -7119.28618757 506842.358205 3856.22963634 
+100 -71.7137414397 100 -7171.37414397 514286.071128 3892.14600204 
+100 -79.7900404592 100 -7979.00404592 636645.055648 4483.75017709 
+100 -77.5222847637 100 -7752.22847637 600970.463498 4311.04660558 
+100 -77.6757572444 100 -7767.57572444 603352.326349 4322.57223863 
+100 -77.2234895755 100 -7722.34895755 596346.734222 4288.67494717 
+100 -72.0371145151 100 -7203.71145151 518934.586766 3914.58014754 
+100 -70.0669515942 100 -7006.69515942 490937.77057 3779.52147387 
+100 -84.5830729338 100 -8458.30729338 715429.622692 4865.69043113 
+100 -74.6560815749 100 -7465.60815749 557353.051612 4100.12505412 
+100 -81.5559569159 100 -8155.59569159 665137.410846 4621.79716194 
+100 -77.2145400841 100 -7721.45400841 596208.52004 4288.00624999 
+100 -76.4034695622 100 -7640.34695622 583749.016114 4227.73640666 
+100 -75.9021858129 100 -7590.21858129 576114.181118 4190.81544106 
+100 -82.8624899277 100 -8286.24899277 686619.223702 4725.93989369 
+100 -75.0997409809 100 -7509.97409809 563997.10954 4132.23619525 
+100 -75.3426973349 100 -7534.26973349 567652.20417 4149.90427751 
+100 -71.6638572905 100 -7166.38572905 513570.844175 3888.69457765 
+100 -76.5890168729 100 -7658.90168729 586587.750555 4241.46621059 
+100 -71.6819735436 100 -7168.19735436 513830.53311 3889.94773169 
+100 -82.3258640017 100 -8232.58640017 677754.788363 4682.95928181 
+100 -73.0659966339 100 -7306.59966339 533863.98641 3986.65494047 
+100 -73.0966886821 100 -7309.66886821 534312.589629 3988.82122644 
+100 -81.234790032 100 -8123.4790032 659909.111154 4596.45858069 
+100 -83.8985310979 100 -8389.85310979 703896.352038 4809.73543245 
+100 -70.7923609172 100 -7079.23609172 501155.836423 3828.79827982 
+100 -75.059094515 100 -7505.9094515 563386.766942 4129.28609842 
+100 -78.4846404505 100 -7848.46404505 615983.878664 4383.7077922 
+100 -79.5172011446 100 -7951.72011446 632298.527787 4462.69963608 
+100 -75.23540248 100 -7523.540248 566036.578632 4142.09438696 
+100 -73.8665116746 100 -7386.65116746 545626.154697 4043.4644943 
+100 -83.8199925432 100 -8381.99925432 702579.114994 4803.34559361 
+100 -80.740575291 100 -8074.0575291 651904.049833 4557.66881094 
+100 -72.111602809 100 -7211.1602809 520008.325969 3919.76262282 
+100 -70.1771299818 100 -7017.71299818 492482.957248 3786.97196128 
+100 -80.7635496266 100 -8076.35496266 652275.094828 4559.46660007 
+100 -84.451494965 100 -8445.1494965 713205.500182 4854.8987635 
+100 -79.7012935378 100 -7970.12935378 635229.619161 4476.89486196 
+100 -72.3349106525 100 -7233.49106525 523233.92991 3935.33237292 
+100 -76.9213850481 100 -7692.13850481 591689.947772 4266.14627624 
+100 -80.5035840373 100 -8050.35840373 648082.704285 4539.15456133 
+100 -80.0400359908 100 -8004.00359908 640640.73614 4503.10359072 
+100 -80.2080636048 100 -8020.80636048 643333.346722 4516.1465746 
+100 -77.5543496882 100 -7755.43496882 601467.715556 4313.45270356 
+100 -72.6597563498 100 -7265.97563498 527944.019282 3958.07070553 
+100 -83.9364097841 100 -8393.64097841 704532.088744 4812.81941926 
+100 -82.9424690717 100 -8294.24690717 687945.31757 4732.37041517 
+100 -70.7483657873 100 -7074.83657873 500533.126158 3825.79471632 
+100 -82.7010487761 100 -8270.10487761 683946.346867 4712.97911239 
+100 -79.9906100982 100 -7999.06100982 639849.770389 4499.2723267 
+100 -84.226393475 100 -8422.6393475 709408.53578 4836.47669521 
+100 -81.4585793004 100 -8145.85793004 663550.014164 4614.10362257 
+100 -79.4784088371 100 -7947.84088371 631681.747127 4459.71271354 
+100 -82.9147676705 100 -8291.47676705 687485.869785 4730.14242975 
+100 -71.6228447837 100 -7162.28447837 512983.189491 3885.8588355 
+100 -73.8633117574 100 -7386.33117574 545578.882376 4043.23613249 
+100 -78.067459846 100 -7806.7459846 609452.82868 4352.09549379 
+100 -80.4377056359 100 -8043.77056359 647022.448797 4534.0179799 
+100 -83.9307931061 100 -8393.07931061 704437.803142 4812.36203294 
+100 -72.9609640693 100 -7296.09640693 532330.227792 3979.24872879 
+100 -83.1928621681 100 -8319.28621681 692105.231572 4752.54400244 
+100 -73.1453783825 100 -7314.53783825 535024.637872 3992.25974341 
+100 -73.1137871022 100 -7311.37871022 534562.586442 3990.02846445 
+100 -73.9782366599 100 -7397.82366599 547277.949931 4051.44415801 
+100 -79.6062880149 100 -7960.62880149 633716.109151 4469.56482572 
+100 -79.4480698903 100 -7944.80698903 631199.58093 4457.37772992 
+100 -81.2023900252 100 -8120.23900252 659382.814581 4593.90809784 
+100 -71.3111255513 100 -7131.11255513 508527.66274 3864.36049982 
+100 -75.0374558122 100 -7503.74558122 563061.977477 4127.71624785 
+100 -80.864257914 100 -8086.4257914 653902.820798 4567.3534592 
+100 -70.4941298589 100 -7049.41298589 496942.234457 3808.47584764 
+100 -80.599140388 100 -8059.9140388 649622.143128 4546.61286467 
+100 -70.8639801481 100 -7086.39801481 502170.368243 3833.69189084 
+100 -80.3096961493 100 -8030.96961493 644964.729559 4524.04940742 
+100 -82.9907201824 100 -8299.07201824 688745.963639 4736.25301774 
+100 -71.424200671 100 -7142.4200671 510141.644149 3872.14771907 
+100 -72.4514611844 100 -7245.14611844 524921.422775 3943.47846092 
+100 -70.6226745152 100 -7062.26745152 498756.215568 3817.22439155 
+100 -77.1172011252 100 -7711.72011252 594706.270938 4280.73835188 
+100 -83.6429584942 100 -8364.29584942 699614.450567 4788.9648566 
+100 -75.6543647649 100 -7565.43647649 572358.290798 4172.65554208 
+100 -79.1396581901 100 -7913.96581901 626308.549844 4433.69360374 
+100 -71.5420371352 100 -7154.20371352 511826.307745 3880.27644589 
+100 -79.6972526494 100 -7969.72526494 635165.207987 4476.58290831 
+100 -79.7105578387 100 -7971.05578387 635377.303096 4477.61012089 
+100 -79.4597743838 100 -7945.97743838 631385.574513 4458.2784366 
+100 -74.1823793321 100 -7418.23793321 550302.540338 4066.05675336 
+100 -84.4225279032 100 -8442.25279032 712716.321756 4852.52528902 
+100 -73.4432147994 100 -7344.32147994 539390.580008 4013.34486304 
+100 -73.2552323118 100 -7325.52323118 536632.906105 4000.02644975 
+100 -78.9465690249 100 -7894.65690249 623256.07608 4418.91395784 
+100 -73.9869873613 100 -7398.69873613 547407.42988 4052.069681 
+100 -78.5541754841 100 -7855.41754841 617075.848599 4388.99380428 
+100 -80.9541717796 100 -8095.41717796 655357.792852 4574.40353481 
+100 -72.2890645919 100 -7228.90645919 522570.885957 3932.1317683 
+100 -74.0717429381 100 -7407.17429381 548662.310188 4058.1321936 
+100 -72.8693164416 100 -7286.93164416 530993.727867 3972.79534823 
+100 -82.6522095 100 -8265.22095 683138.773523 4709.06334387 
+100 -75.4744804251 100 -7547.44804251 569639.719544 4159.51239666 
+100 -79.2491718471 100 -7924.91718471 628043.123845 4442.09268961 
+100 -70.7113202296 100 -7071.13202296 500009.080861 3823.26710373 
+100 -77.7117850575 100 -7771.17850575 603912.153682 4325.28130576 
+100 -77.451123078 100 -7745.1123078 599867.646604 4305.71042532 
+100 -79.5660835481 100 -7956.60835481 633076.165118 4466.46561672 
+100 -77.4262444987 100 -7742.62444987 599482.333717 4303.84605734 
+100 -73.1501206238 100 -7315.01206238 535094.014728 3992.59477208 
+100 -76.1947102049 100 -7619.47102049 580563.386321 4212.33015609 
+100 -70.5012845229 100 -7050.12845229 497043.111937 3808.96234838 
+100 -84.2909800308 100 -8429.09800308 710496.931455 4841.7572072 
+100 -75.2661454257 100 -7526.61454257 566499.264724 4144.33096005 
+100 -71.2149013911 100 -7121.49013911 507156.218014 3857.74383659 
+100 -73.9829554327 100 -7398.29554327 547347.769456 4051.7814587 
+100 -77.1581462784 100 -7715.81462784 595337.953712 4283.79440286 
+100 -73.6361678782 100 -7363.61678782 542228.521979 4027.0521902 
+100 -79.9265206119 100 -7992.65206119 638824.869712 4494.30804703 
+100 -83.8373094407 100 -8383.73094407 702869.445425 4804.75395353 
+100 -76.8479308701 100 -7684.79308701 590560.447902 4260.68241233 
+100 -84.9426005477 100 -8494.26005477 721524.538781 4895.26619253 
+100 -75.7201968951 100 -7572.01968951 573354.821783 4177.47361668 
+100 -80.5417895731 100 -8054.17895731 648697.986763 4542.13545988 
+100 -78.333187559 100 -7833.3187559 613608.827315 4372.21116768 
+100 -71.3679759975 100 -7136.79759975 509338.799799 3868.274059 
+100 -73.6605068424 100 -7366.05068424 542587.026828 4028.78386704 
+100 -79.1972197653 100 -7919.72197653 627219.961855 4438.10675986 
+100 -74.5607417667 100 -7456.07417667 555930.42128 4093.25025198 
+100 -82.9692804202 100 -8296.92804202 688390.149344 4734.52754567 
+100 -72.771109073 100 -7277.1109073 529563.431571 3965.88938517 
+100 -74.2656064926 100 -7426.56064926 551538.030772 4072.02613763 
+100 -79.4499157721 100 -7944.99157721 631228.91162 4457.51976867 
+100 -73.4798470775 100 -7347.98470775 539928.792653 4015.94434557 
+100 -84.2039804296 100 -8420.39804296 709031.032018 4834.64520902 
+100 -70.4735784461 100 -7047.35784461 496652.525899 3807.07868338 
+100 -74.3660032741 100 -7436.60032741 553030.244297 4079.2362133 
+100 -73.0053882704 100 -7300.53882704 532978.671651 3982.37988758 
+100 -76.2424860136 100 -7624.24860136 581291.667353 4215.85212173 
+100 -75.8137583821 100 -7581.37583821 574772.596002 4184.32858406 
+100 -71.6046470896 100 -7160.46470896 512722.548482 3884.60112469 
+100 -84.6780231561 100 -8467.80231561 717036.760562 4873.48874492 
+100 -81.9550538408 100 -8195.50538408 671663.085005 4653.42779043 
+100 -84.3238168754 100 -8432.38168754 711050.609244 4844.44350403 
+100 -84.0812806865 100 -8408.12806865 706966.176189 4824.62767923 
+100 -84.3013245304 100 -8430.13245304 710671.331758 4842.60334746 
+100 -84.4377192028 100 -8443.77192028 712972.842417 4853.76991408 
+100 -79.1498200355 100 -7914.98200355 626469.401166 4434.47245574 
+100 -74.2020856637 100 -7420.20856637 550594.951684 4067.46954426 
+100 -70.607531017 100 -7060.7531017 498542.343631 3816.19289061 
+100 -84.3904177412 100 -8439.04177412 712174.260653 4849.89525891 
+100 -78.7491351365 100 -7874.91351365 620142.628475 4403.84030453 
+100 -79.519019737 100 -7951.9019737 632327.449994 4462.83970063 
+100 -77.9053472567 100 -7790.53472567 606924.313119 4339.85819745 
+100 -78.3349288564 100 -7833.49288564 613636.107893 4372.34321732 
+100 -83.2291073575 100 -8322.91073575 692708.431153 4755.46938737 
+100 -78.2267348379 100 -7822.67348379 611942.20434 4364.14418461 
+100 -83.5265039897 100 -8352.65039897 697667.686875 4779.5221744 
+100 -74.0637164384 100 -7406.37164384 548543.409267 4057.55775524 
+100 -81.0996002566 100 -8109.96002566 657714.516178 4585.82358025 
+100 -77.3446091329 100 -7734.46091329 598218.856192 4297.73275813 
+100 -73.6879176773 100 -7368.79176773 542990.921162 4030.73481162 
+100 -78.0111210922 100 -7801.11210922 608573.501407 4347.8397043 
+100 -77.8170600139 100 -7781.70600139 605549.482921 4333.20476457 
+100 -83.8092617034 100 -8380.92617034 702399.234727 4802.47301938 
+100 -81.7334458357 100 -8173.34458357 668035.616818 4635.8444695 
+100 -82.654591092 100 -8265.4591092 683178.142858 4709.25423656 
+100 -72.6699016948 100 -7266.99016948 528091.461234 3958.78255193 
+100 -82.964030837 100 -8296.4030837 688303.041272 4734.10512927 
+100 -76.4675748601 100 -7646.75748601 584729.000498 4232.47606534 
+100 -77.9176873042 100 -7791.76873042 607116.599483 4340.78877916 
+100 -74.8827326103 100 -7488.27326103 560742.364319 4116.50499007 
+100 -76.6198279413 100 -7661.98279413 587059.803375 4243.74944702 
+100 -81.6587221193 100 -8165.87221193 666814.689816 4629.92664378 
+100 -73.8828743261 100 -7388.28743261 545867.911868 4044.63237353 
+100 -73.4613561052 100 -7346.13561052 539657.084081 4014.63203014 
+100 -84.0400055652 100 -8404.00055652 706272.25354 4821.26125378 
+100 -75.1911288089 100 -7519.11288089 565370.585156 4138.87510376 
+100 -82.0956551607 100 -8209.56551607 673969.659626 4664.60916023 
+100 -84.7508965966 100 -8475.08965966 718271.447393 4879.47999547 
+100 -78.6995014523 100 -7869.95014523 619361.152885 4400.05701079 
+100 -76.6536347781 100 -7665.36347781 587577.97247 4246.2557754 
+100 -83.9080839543 100 -8390.80839543 704056.655287 4810.51306655 
+100 -76.0031362279 100 -7600.31362279 577647.671648 4198.23051767 
+100 -82.3302675336 100 -8233.02675336 677827.295215 4683.31080724 
+100 -84.9461566076 100 -8494.61566076 721584.952239 4895.55936968 
+100 -72.8653897149 100 -7286.53897149 530936.50183 3972.51903486 
+100 -75.3417629061 100 -7534.17629061 567638.123779 4149.83621163 
+100 -73.7012148393 100 -7370.12148393 543186.906879 4031.6814973 
+100 -79.2887559165 100 -7928.87559165 628670.681479 4445.1315176 
+100 -73.1712775813 100 -7317.12775813 535403.586288 3994.08973749 
+100 -76.3493315761 100 -7634.93315761 582922.043212 4223.73688712 
+100 -79.4175790508 100 -7941.75790508 630715.18623 4455.03198352 
+100 -82.565231542 100 -8256.5231542 681701.745958 4702.09565094 
+100 -71.002982175 100 -7100.2982175 504142.347775 3843.20428343 
+100 -78.379093152 100 -7837.9093152 614328.224333 4375.69338878 
+100 -84.1533383678 100 -8415.33383678 708178.435845 4830.5088333 
+100 -79.4077671616 100 -7940.77671616 630559.348559 4454.27732489 
+100 -83.5044939134 100 -8350.44939134 697300.050373 4777.73901708 
+100 -83.4983313952 100 -8349.83313952 697197.134579 4777.23984441 
+100 -75.5583221141 100 -7555.83221141 570906.00407 4165.63421507 
+100 -82.7190104457 100 -8271.90104457 684243.468911 4714.41981844 
+100 -71.9243529463 100 -7192.43529463 517311.254674 3906.74539101 
+100 -73.405475017 100 -7340.5475017 538836.376246 4010.66819369 
+100 -79.2817865961 100 -7928.17865961 628560.168587 4444.59637644 
+100 -73.2738712311 100 -7327.38712311 536906.020519 4001.34542452 
+100 -78.732420669 100 -7873.2420669 619879.406439 4402.56598052 
+100 -80.5171531868 100 -8051.71531868 648301.195731 4540.21309569 
+100 -70.3149807292 100 -7031.49807292 494419.651495 3796.31080565 
+100 -72.6892498246 100 -7268.92498246 528372.704006 3960.14039547 
+100 -70.9381346182 100 -7093.81346182 503221.894311 3838.76413501 
+100 -83.807795281 100 -8380.7795281 702374.654986 4802.35378673 
+100 -71.1306794249 100 -7113.06794249 505957.355545 3851.96007916 
+100 -79.8929126763 100 -7989.29126763 638287.749589 4491.70646626 
+100 -75.9215930453 100 -7592.15930453 576408.829053 4192.24016265 
+100 -71.5957229003 100 -7159.57229003 512594.753761 3883.98446156 
+100 -83.8575542378 100 -8385.75542378 703208.940274 4806.40081578 
+100 -80.4630166309 100 -8046.30166309 647429.704535 4535.9909811 
+100 -76.1996896333 100 -7619.96896333 580639.270021 4212.69712602 
+100 -73.8264517494 100 -7382.64517494 545034.497791 4040.60635958 
+100 -74.2069298827 100 -7420.69298827 550666.844262 4067.8168966 
+100 -74.0006650755 100 -7400.06650755 547609.843162 4053.04755312 
+100 -77.8943407581 100 -7789.43407581 606752.832214 4339.02830918 
+100 -84.1047457085 100 -8410.47457085 707360.825069 4826.54226108 
+100 -78.8199184982 100 -7881.99184982 621257.955206 4409.23997978 
+100 -72.3958048672 100 -7239.58048672 524115.256237 3939.58676902 
+100 -75.6011564369 100 -7560.11564369 571553.48546 4168.76453621 
+100 -71.6986031518 100 -7169.86031518 514068.969391 3891.09833908 
+100 -79.6407325226 100 -7964.07325226 634264.627673 4472.22130706 
+100 -76.2613122664 100 -7626.13122664 581578.774859 4217.24059363 
+100 -80.6178657353 100 -8061.78657353 649924.027571 4548.07547352 
+100 -83.4856890954 100 -8348.56890954 696986.028373 4776.21591913 
+100 -74.3793783271 100 -7437.93783271 553229.192032 4080.19751434 
+100 -78.4539645148 100 -7845.39645148 615502.454809 4381.37736276 
+100 -73.4662069685 100 -7346.62069685 539728.356634 4014.97626575 
+100 -71.6687638974 100 -7166.87638974 513641.171859 3889.03394955 
+100 -73.9017778701 100 -7390.17778701 546147.277236 4045.98194151 
+100 -79.9399715161 100 -7993.99715161 639039.9046 4495.34959421 
+100 -81.6032466054 100 -8160.32466054 665908.985655 4625.53681176 
+100 -81.462532797 100 -8146.2532797 663614.42497 4614.41579286 
+100 -71.7911311734 100 -7179.11311734 515396.651516 3897.50542964 
+100 -74.9657945938 100 -7496.57945938 561987.035908 4122.52069306 
+100 -79.5832374183 100 -7958.32374183 633349.167798 4467.78774544 
+100 -76.5893083845 100 -7658.93083845 586592.215881 4241.48780845 
+100 -74.4401199252 100 -7444.01199252 554133.145448 4084.56542743 
+100 -84.6841768442 100 -8468.41768442 717140.980778 4873.99446178 
+100 -72.5048301886 100 -7250.48301886 525695.040068 3947.21312487 
+100 -74.6323229497 100 -7463.23229497 556998.362887 4098.41100706 
+100 -83.9540885573 100 -8395.40885573 704828.898549 4814.25927135 
+100 -76.8858474731 100 -7688.58474731 591143.354166 4263.50215215 
+100 -81.807003237 100 -8180.7003237 669238.577862 4641.67538122 
+100 -73.2289573719 100 -7322.89573719 536248.019778 3998.16770546 
+100 -70.2309752814 100 -7023.09752814 493238.988897 3790.61750628 
+100 -77.0775610218 100 -7707.75610218 594095.041307 4277.78130398 
+100 -70.6973842549 100 -7069.73842549 499812.014049 3822.31660961 
+100 -75.9652006108 100 -7596.52006108 577071.170383 4195.44285039 
+100 -75.7104783702 100 -7571.04783702 573207.653504 4176.76207159 
+100 -78.8084368624 100 -7880.84368624 621076.972069 4408.36376819 
+100 -84.186248445 100 -8418.6248445 708732.442725 4833.19659251 
+100 -79.2090767375 100 -7920.90767375 627407.78376 4439.01622696 
+100 -79.0943339893 100 -7909.43339893 625591.366921 4430.22099963 
+100 -84.3135450858 100 -8431.35450858 710877.388494 4843.60307976 
+100 -75.726549882 100 -7572.6549882 573451.035703 4177.93880381 
+100 -71.1244576307 100 -7112.44576307 505868.847326 3851.53309255 
+100 -76.4888776935 100 -7648.88776935 585054.841081 4234.05201117 
+100 -71.3540372302 100 -7135.40372302 509139.862905 3867.31422145 
+100 -80.3336683551 100 -8033.36683551 645349.827139 4525.9149648 
+100 -73.6956267556 100 -7369.56267556 543104.54029 4031.28363456 
+100 -80.8331138552 100 -8083.31138552 653399.229553 4564.91336313 
+100 -81.6776645192 100 -8167.76645192 667124.088131 4631.42627936 
+100 -72.1775458041 100 -7217.75458041 520959.81183 3924.35519464 
+100 -74.8033056678 100 -7480.33056678 559553.453883 4110.75900525 
+100 -82.588802358 100 -8258.8802358 682091.027493 4703.98313157 
+100 -82.096207705 100 -8209.6207705 673978.731954 4664.65314051 
+100 -76.5445838799 100 -7654.45838799 585907.332135 4238.17520097 
+100 -78.5888578435 100 -7858.88578435 617620.857715 4391.63214396 
+100 -80.687691425 100 -8068.7691425 651050.35475 4553.53254519 
+100 -71.5242315585 100 -7152.42315585 511571.570004 3879.04727112 
+100 -75.6877412068 100 -7568.77412068 572863.416899 4175.09773148 
+100 -79.4674269487 100 -7946.74269487 631507.194585 4458.86740555 
+100 -82.8747060251 100 -8287.47060251 686821.689875 4726.92168431 
+100 -82.8968688275 100 -8289.68688275 687189.086141 4728.70325863 
+100 -80.9919946628 100 -8099.19946628 655970.319945 4577.37161307 
+100 -77.9733565338 100 -7797.33565338 607984.432915 4344.98877324 
+100 -81.3399944688 100 -8133.99944688 661619.470019 4604.74736392 
+100 -76.0863534057 100 -7608.63534057 578913.317457 4204.35070377 
+100 -78.5406274866 100 -7854.06274866 616863.016599 4387.96351428 
+100 -79.9910081908 100 -7999.10081908 639856.139137 4499.30317521 
+100 -83.8982181378 100 -8389.82181378 703891.100671 4809.70995801 
+100 -73.3742058373 100 -7337.42058373 538377.408226 4008.45152654 
+100 -84.178217329 100 -8417.8217329 708597.227269 4832.54059302 
+100 -71.0178032476 100 -7101.78032476 504352.837811 3844.21968094 
+100 -78.7169423434 100 -7871.69423434 619635.701189 4401.38615009 
+100 -78.7678964309 100 -7876.78964309 620438.150816 4405.271013 
+100 -75.5218835535 100 -7552.18835535 570355.489547 4162.97273885 
+100 -82.6788419149 100 -8267.88419149 683579.090039 4711.19834541 
+100 -73.4996766481 100 -7349.96766481 540220.246738 4017.35204207 
+100 -73.2401674865 100 -7324.01674865 536412.213345 3998.96064801 
+100 -81.7071042201 100 -8170.71042201 667605.088004 4633.75767947 
+100 -82.3468112511 100 -8234.68112511 678099.732322 4684.63163348 
+100 -72.1408721711 100 -7214.08721711 520430.543761 3921.80053838 
+100 -73.5318067682 100 -7353.18067682 540692.66066 4019.63378638 
+100 -74.4926433211 100 -7449.26433211 554915.390897 4088.34534618 
+100 -71.0782121901 100 -7107.82121901 505211.224814 3848.3605936 
+100 -70.7534879919 100 -7075.34879919 500605.606303 3826.14431153 
+100 -84.4134746878 100 -8441.34746878 712563.470887 4851.78366772 
+100 -73.355877034 100 -7335.5877034 538108.469542 4007.15265513 
+100 -84.1464739948 100 -8414.64739948 708062.908576 4829.94835789 
+100 -77.9536903383 100 -7795.36903383 607677.783735 4343.50469283 
+100 -84.6212680147 100 -8462.12680147 716075.900041 4868.82633017 
+100 -79.4407380878 100 -7944.07380878 631083.086793 4456.81358875 
+100 -78.8016646625 100 -7880.16646625 620970.235358 4407.84701513 
+100 -74.7165733452 100 -7471.65733452 558256.633245 4104.49173286 
+100 -72.1392486164 100 -7213.92486164 520407.119094 3921.68747393 
+100 -72.3718988578 100 -7237.18988578 523769.174429 3937.916125 
+100 -80.9107558434 100 -8091.07558434 654655.041115 4570.99831596 
+100 -77.6018403762 100 -7760.18403762 602204.562978 4317.01821395 
+100 -79.1284970607 100 -7912.84970607 626131.904708 4432.83828089 
+100 -71.607600577 100 -7160.7600577 512764.84604 3884.80522876 
+100 -76.3053935358 100 -7630.53935358 582251.308266 4220.49305749 
+100 -74.8151367563 100 -7481.51367563 559730.468787 4111.61450204 
+100 -82.8278131963 100 -8282.78131963 686044.663889 4723.15378645 
+100 -70.8972471428 100 -7089.72471428 502641.965243 3835.96670836 
+100 -80.7876190196 100 -8078.76190196 652663.938685 4561.35064588 
+100 -76.3107798535 100 -7631.07798535 582333.512185 4220.89061129 
+100 -82.8605493881 100 -8286.05493881 686587.06449 4725.78394898 
+100 -81.6566814677 100 -8165.66814677 666781.362832 4629.76511049 
+100 -84.1978609812 100 -8419.78609812 708927.97938 4834.14524445 
+100 -76.8622173132 100 -7686.22173132 590780.04503 4261.74468187 
+100 -74.9629222165 100 -7496.29222165 561943.970724 4122.31254808 
+100 -81.4327392312 100 -8143.27392312 663129.101869 4612.06366127 
+100 -81.9417873964 100 -8194.17873964 671445.652171 4652.37379237 
+100 -81.9005104671 100 -8190.05104671 670769.361477 4649.09553122 
+100 -70.5423254869 100 -7054.23254869 497621.968509 3811.75402883 
+100 -77.7486433057 100 -7774.86433057 604485.153588 4328.05415967 
+100 -80.1893972672 100 -8018.93972672 643033.943408 4514.69622387 
+100 -80.636964066 100 -8063.6964066 650231.997378 4549.56757673 
+100 -78.2236066323 100 -7822.36066323 611893.263457 4363.9073007 
+100 -75.2931011101 100 -7529.31011101 566905.107477 4146.29278461 
+100 -83.2153055852 100 -8321.53055852 692478.708364 4754.35527786 
+100 -79.9978070856 100 -7999.78070856 639964.913851 4499.83005154 
+100 -79.6440403525 100 -7964.40403525 634317.316368 4472.47648096 
+100 -75.8192607526 100 -7581.92607526 574856.030107 4184.73199866 
+100 -80.2359127148 100 -8023.59127148 643780.168918 4518.31106281 
+100 -72.6762989884 100 -7267.62989884 528184.443465 3959.23146985 
+100 -74.9140329226 100 -7491.40329226 561211.232872 4118.77108205 
+100 -82.0762591284 100 -8207.62591284 673651.231252 4663.06550844 
+100 -70.6375595792 100 -7063.75595792 498966.482331 3818.23851271 
+100 -81.8861430591 100 -8188.61430591 670534.042509 4647.9548549 
+100 -73.0237383414 100 -7302.37383414 533246.636136 3983.67383483 
+100 -74.3178701892 100 -7431.78701892 552314.582946 4075.77823926 
+100 -81.7784853912 100 -8177.84853912 668772.067288 4639.41412296 
+100 -71.4306098229 100 -7143.06098229 510233.201967 3872.58948528 
+100 -76.9022086825 100 -7690.22086825 591394.970025 4264.71932842 
+100 -84.2722734756 100 -8427.22734756 710181.607675 4840.22735469 
+100 -70.0131830246 100 -7001.31830246 490184.579724 3775.88994106 
+100 -84.500910671 100 -8450.0910671 714040.390423 4858.94967544 
+100 -84.1350059697 100 -8413.50059697 707869.922951 4829.01209983 
+100 -81.1573757532 100 -8115.73757532 658651.963915 4590.36638019 
+100 -73.2354712729 100 -7323.54712729 536343.425256 3998.6284481 
+100 -81.2173412194 100 -8121.73412194 659625.651474 4595.08490432 
+100 -80.5310669482 100 -8053.10669482 648525.274382 4541.29870454 
+100 -83.271221283 100 -8327.1221283 693409.629395 4758.87009377 
+100 -75.8992810043 100 -7589.92810043 576070.085697 4190.60222598 
+100 -73.625387174 100 -7362.5387174 542069.763652 4026.28535033 
+100 -84.7658555575 100 -8476.58555575 718525.02684 4880.71049531 
+100 -70.6512329546 100 -7065.12329546 499159.671801 3819.17027662 
+100 -74.0649164184 100 -7406.49164184 548561.184407 4057.64363099 
+100 -76.4698291361 100 -7646.98291361 584763.476811 4232.64281121 
+100 -71.3844060581 100 -7138.44060581 509573.342827 3869.40569899 
+100 -82.1943762725 100 -8219.43762725 675591.549082 4672.47180473 
+100 -78.7726610315 100 -7877.26610315 620513.212599 4405.63441041 
+100 -76.171998409 100 -7617.1998409 580217.334162 4210.65667479 
+100 -79.1468229319 100 -7914.68229319 626421.958021 4434.24273277 
+100 -72.7684950731 100 -7276.84950731 529525.387521 3965.70569992 
+100 -73.7824335041 100 -7378.24335041 544384.749379 4037.46766313 
+100 -83.6234500378 100 -8362.34500378 699288.139622 4787.38207302 
+100 -70.3653571708 100 -7036.53571708 495128.348977 3799.72835196 
+100 -82.1693209389 100 -8216.93209389 675179.730356 4670.47534943 
+100 -75.0832687627 100 -7508.32687627 563749.724809 4131.04045214 
+100 -70.5437835742 100 -7054.37835742 497642.540096 3811.85324155 
+100 -84.7946427115 100 -8479.46427115 719013.143257 4883.0791095 
+100 -76.1249216053 100 -7612.49216053 579500.368941 4207.18954069 
+100 -71.2933378885 100 -7129.33378885 508274.002728 3863.13666892 
+100 -84.6071329853 100 -8460.71329853 715836.695199 4867.66564353 
+100 -82.2764968717 100 -8227.64968717 676942.193748 4679.01972656 
+100 -81.8971663135 100 -8189.71663135 670714.585018 4648.83000931 
+100 -74.1917837525 100 -7419.17837525 550442.077638 4066.73092881 
+100 -75.4625662695 100 -7546.25662695 569459.890797 4158.64303831 
+100 -74.642435014 100 -7464.2435014 557149.310482 4099.14046488 
+100 -74.7463120919 100 -7474.63120919 558701.117134 4106.63980544 
+100 -82.7777211848 100 -8277.77211848 685215.112455 4719.13125931 
+100 -78.3155092763 100 -7831.55092763 613331.899321 4370.87072341 
+100 -72.9784176114 100 -7297.84176114 532584.943706 3980.4786745 
+100 -75.6188434215 100 -7561.88434215 571820.94804 4170.05763165 
+100 -81.8973383853 100 -8189.73383853 670717.403459 4648.84367133 
+100 -82.3231885065 100 -8232.31885065 677710.736587 4682.74571167 
+100 -81.8481577344 100 -8184.81577344 669912.092452 4644.94006792 
+100 -81.7896427179 100 -8178.96427179 668954.565592 4640.29872116 
+100 -82.1532731324 100 -8215.32731324 674916.028636 4669.19696035 
+100 -74.6254508564 100 -7462.54508564 556895.791552 4097.91533062 
+100 -71.2475140334 100 -7124.75140334 507620.825594 3859.98534289 
+100 -71.8774696068 100 -7187.74696068 516637.063708 3903.49164452 
+100 -82.3755809301 100 -8237.55809301 678573.633357 4686.92921446 
+100 -74.0872659359 100 -7408.72659359 548892.297386 4059.24332209 
+100 -73.1701488576 100 -7317.01488576 535387.068384 3994.00996978 
+100 -71.0882471394 100 -7108.82471394 505353.888135 3849.04882283 
+100 -77.8330453693 100 -7783.30453693 605798.295146 4334.40886231 
+100 -84.4904752848 100 -8449.04752848 713864.041384 4858.09401871 
+100 -76.6539385598 100 -7665.39385598 587582.629673 4246.27830196 
+100 -84.7950819603 100 -8479.50819603 719020.592466 4883.11525743 
+100 -83.8678114799 100 -8386.78114799 703380.980243 4807.23537251 
+100 -84.9652741068 100 -8496.52741068 721909.780404 4897.13571675 
+100 -83.9519035812 100 -8395.19035812 704792.211491 4814.0812985 
+100 -79.5991970566 100 -7959.91970566 633603.217206 4469.01809339 
+100 -73.0939835242 100 -7309.39835242 534273.042744 3988.63025491 
+100 -79.3974715999 100 -7939.74715999 630395.849646 4453.48556923 
+100 -80.1371249168 100 -8013.71249168 642195.878993 4510.63658267 
+100 -75.9345691505 100 -7593.45691505 576605.879207 4193.19297316 
+100 -83.3886773462 100 -8338.86773462 695367.150955 4768.36406141 
+100 -74.6523771339 100 -7465.23771339 557297.741175 4099.85776304 
+100 -72.5678013364 100 -7256.78013364 526608.57908 3951.62339206 
+100 -75.5742021115 100 -7557.42021115 571146.002479 4166.79450711 
+100 -79.8769368542 100 -7987.69368542 638032.504122 4490.47017847 
+100 -84.0024279934 100 -8400.24279934 705640.790879 4818.19788441 
+100 -84.4689735939 100 -8446.89735939 713500.750001 4856.33131602 
+100 -83.2014220176 100 -8320.14220176 692247.662575 4753.23475783 
+100 -77.0529222943 100 -7705.29222943 593715.283408 4275.94411131 
+100 -83.6812617145 100 -8368.12617145 700255.356213 4792.07362678 
+100 -74.6473181062 100 -7464.73181062 557222.210044 4099.49275496 
+100 -83.5497627533 100 -8354.97627533 698056.285613 4781.40702118 
+100 -82.2499874707 100 -8224.99874707 676506.043892 4676.90525078 
+100 -77.0753187625 100 -7707.53187625 594060.476233 4277.61408426 
+100 -77.4637385442 100 -7746.37385442 600063.078924 4306.65604826 
+100 -78.6549623559 100 -7865.49623559 618660.310321 4396.66414572 
+100 -80.3609418167 100 -8036.09418167 645788.096967 4528.03813029 
+100 -77.534340994 100 -7753.4340994 601157.403338 4311.9511642 
+100 -77.5173297551 100 -7751.73297551 600893.641237 4310.6748818 
+100 -83.0579737773 100 -8305.79737773 689862.7008 4741.66856955 
+100 -76.0843240061 100 -7608.43240061 578882.435946 4204.20136972 
+100 -82.9790345745 100 -8297.90345745 688552.017892 4735.31250302 
+100 -71.6188497435 100 -7161.88497435 512925.963859 3885.58269494 
+100 -74.5449983694 100 -7454.49983694 555695.678189 4092.11589502 
+100 -81.9284044542 100 -8192.84044542 671226.345642 4651.31071707 
+100 -81.5180443473 100 -8151.80443473 664519.15542 4618.80066623 
+100 -78.0804323958 100 -7808.04323958 609655.392312 4353.07588057 
+100 -83.2962903039 100 -8329.62903039 693827.197839 4760.89526344 
+100 -70.7155173886 100 -7071.55173886 500068.439953 3823.5534063 
+100 -83.78321664 100 -8378.321664 701962.739055 4800.35565367 
+100 -84.8523515417 100 -8485.23515417 719992.156216 4887.82990223 
+100 -76.3673943501 100 -7636.73943501 583197.891983 4225.07097404 
+100 -84.6969569867 100 -8469.69569867 717357.45228 4875.04486893 
+100 -81.0435107006 100 -8104.35107006 656805.062668 4581.41653659 
+100 -72.781776129 100 -7278.1776129 529718.693649 3966.63902792 
+100 -70.862732028 100 -7086.2732028 502152.679047 3833.60656516 
+100 -81.4929392017 100 -8149.29392017 664109.913974 4616.81722186 
+100 -80.7710819507 100 -8077.10819507 652396.767948 4560.05613486 
+100 -78.1403320488 100 -7814.03320488 610591.14927 4357.60491623 
+100 -83.2408311911 100 -8324.08311911 692903.597739 4756.41591072 
+100 -80.6210391285 100 -8062.10391285 649975.195015 4548.32337726 
+100 -77.8808545857 100 -7788.08545857 606542.751099 4338.01161903 
+100 -76.4077288089 100 -7640.77288089 583814.102173 4228.05118884 
+100 -82.0624156319 100 -8206.24156319 673424.005934 4661.96399059 
+100 -84.1561959214 100 -8415.61959214 708226.531196 4830.74216618 
+100 -83.5358033047 100 -8353.58033047 697823.043376 4780.27570862 
+100 -72.1516641135 100 -7215.16641135 520586.263435 3922.55215689 
+100 -74.4470734068 100 -7444.70734068 554236.673883 4085.0656859 
+100 -83.1900911763 100 -8319.00911763 692059.126992 4752.32040702 
+100 -82.1582756754 100 -8215.82756754 674998.226196 4669.59544179 
+100 -72.206756796 100 -7220.6756796 521381.5727 3926.39097151 
+100 -80.2219693163 100 -8022.19693163 643556.436098 4517.2272572 
+100 -77.9198351327 100 -7791.98351327 607150.070711 4340.95076572 
+100 -75.0827344018 100 -7508.27344018 563741.700525 4131.00166662 
+100 -81.4275737631 100 -8142.75737631 663044.976895 4611.65595007 
+100 -71.5483473973 100 -7154.83473973 511916.601528 3880.71213915 
+100 -81.9159458684 100 -8191.59458684 671022.218752 4650.32122909 
+100 -82.3626341183 100 -8236.26341183 678360.349891 4685.89516416 
+100 -79.2262299731 100 -7922.62299731 627679.551574 4440.33218294 
+100 -81.9102974672 100 -8191.02974672 670929.683117 4649.87267192 
+100 -78.9962126435 100 -7899.62126435 624040.161201 4422.7102744 
+100 -72.3547468538 100 -7235.47468538 523520.939227 3936.717829 
+100 -81.2599972858 100 -8125.99972858 660318.715889 4598.44358623 
+100 -73.0979747566 100 -7309.79747566 534331.391351 3988.91201986 
+100 -79.0919535278 100 -7909.19535278 625553.711284 4430.0386726 
+100 -76.3647155463 100 -7636.47155463 583156.978047 4224.87310137 
+100 -83.8184286113 100 -8381.84286113 702552.897487 4803.21841591 
+100 -73.9573275384 100 -7395.73275384 546968.629663 4049.94982947 
+100 -75.0412922223 100 -7504.12922223 563119.55384 4127.99453864 
+100 -78.380172519 100 -7838.0172519 614345.144411 4375.77529076 
+100 -84.1853834506 100 -8418.53834506 708717.878673 4833.12593474 
+100 -78.5941934843 100 -7859.41934843 617704.724945 4392.03814102 
+100 -81.7133973743 100 -8171.33973743 667707.931046 4634.25616179 
+100 -80.5402611969 100 -8054.02611969 648673.367367 4542.01618384 
+100 -70.984849989 100 -7098.4849989 503884.892796 3841.96233901 
+100 -70.6867852928 100 -7068.67852928 499662.161503 3821.59384428 
+100 -83.6692825027 100 -8366.92825027 700054.883452 4791.101211 
+100 -84.8063211313 100 -8480.63211313 719211.210382 4884.04024908 
+100 -74.9295426704 100 -7492.95426704 561443.63648 4119.89432572 
+100 -79.9921390262 100 -7999.21390262 639874.230598 4499.39080543 
+100 -70.4380137028 100 -7043.80137028 496151.37744 3804.66185294 
+100 -81.3869401513 100 -8138.69401513 662383.402718 4608.44966321 
+100 -82.5999829731 100 -8259.99829731 682275.718716 4704.87863615 
+100 -72.8347086067 100 -7283.47086067 530489.477782 3970.36061739 
+100 -84.7493984062 100 -8474.93984062 718246.053022 4879.35676909 
+100 -71.9262697566 100 -7192.62697566 517338.828109 3906.87846615 
+100 -84.7143402283 100 -8471.43402283 717651.944031 4876.47386958 
+100 -77.7852461284 100 -7778.52461284 605054.451526 4330.80914231 
+100 -72.8609394369 100 -7286.09394369 530871.649563 3972.20589922 
+100 -79.6477922517 100 -7964.77922517 634377.081057 4472.76592466 
+100 -83.5840390913 100 -8358.40390913 698629.159081 4784.18569768 
+100 -76.2123241061 100 -7621.23241061 580831.834565 4213.62836256 
+100 -71.6716672515 100 -7167.16672515 513682.788661 3889.23477518 
+100 -82.4325971727 100 -8243.25971727 679513.307663 4691.48504539 
+100 -83.0684759977 100 -8306.84759977 690037.170459 4742.5146623 
+100 -79.3948715561 100 -7939.48715561 630354.562941 4453.28563582 
+100 -80.180167381 100 -8018.0167381 642885.924124 4513.97920217 
+100 -70.8432718276 100 -7084.32718276 501876.916324 3832.27640205 
+100 -78.7786989309 100 -7877.86989309 620608.340525 4406.0949553 
+100 -79.2900749635 100 -7929.00749635 628691.598772 4445.23280645 
+100 -81.1485825264 100 -8114.85825264 658509.244605 4589.67476671 
+100 -75.0389628313 100 -7503.89628313 563084.59428 4127.82556432 
+100 -72.6722884022 100 -7267.22884022 528126.150161 3958.9500298 
+100 -80.365726786 100 -8036.5726786 645865.004185 4528.41070396 
+100 -74.5365973049 100 -7453.65973049 555570.433779 4091.51067563 
+100 -73.2868739167 100 -7328.68739167 537096.588849 4002.26575945 
+100 -82.6207530162 100 -8262.07530162 682618.882897 4706.54253194 
+100 -79.5290022484 100 -7952.90022484 632486.219863 4463.6085937 
+100 -74.4055411161 100 -7440.55411161 553618.454878 4082.0784216 
+100 -74.7989066216 100 -7479.89066216 559487.643179 4110.44094934 
+100 -75.3104656692 100 -7531.04656692 567166.623931 4147.55695548 
+100 -78.6547488476 100 -7865.47488476 618656.951628 4396.64788602 
+100 -78.9270288089 100 -7892.70288089 622947.58766 4417.42036628 
+100 -75.1134262361 100 -7511.34262361 564202.680093 4133.22983488 
+100 -80.705586626 100 -8070.5586626 651339.171264 4554.93188975 
+100 -73.4663462874 100 -7346.63462874 539730.403682 4014.98615269 
+100 -74.8053825883 100 -7480.53825883 559584.526418 4110.90917562 
+100 -83.4209722198 100 -8342.09722198 695905.860609 4770.9768725 
+100 -84.706742749 100 -8470.6742749 717523.226715 4875.8492767 
+100 -79.1223265494 100 -7912.23265494 626034.255859 4432.36546292 
+100 -72.6089497282 100 -7260.89497282 527205.958063 3954.50741599 
+100 -75.5844817155 100 -7558.44817155 571301.38762 4167.54573381 
+100 -71.9857783272 100 -7198.57783272 518195.228137 3911.01169487 
+100 -70.2741485496 100 -7027.41485496 493845.595438 3793.54260581 
+100 -83.0509819541 100 -8305.09819541 689746.560354 4741.10534688 
+100 -75.1302333697 100 -7513.02333697 564455.196619 4134.45039967 
+100 -79.8711075796 100 -7987.11075796 637939.382599 4490.01914405 
+100 -79.1873383884 100 -7918.73383884 627063.456104 4437.34893455 
+100 -72.34273165 100 -7234.273165 523347.082258 3935.87858217 
+100 -72.9518479707 100 -7295.18479707 532197.212233 3978.60644124 
+100 -77.6596523133 100 -7765.96523133 603102.159742 4321.36166793 
+100 -77.7527986398 100 -7775.27986398 604549.769633 4328.36685156 
+100 -81.114730131 100 -8111.4730131 657959.944423 4587.01289679 
+100 -76.6585290031 100 -7665.85290031 587653.006891 4246.61871195 
+100 -80.6027356913 100 -8060.27356913 649680.100092 4546.89366123 
+100 -82.4912475053 100 -8249.12475053 680480.591497 4696.17483872 
+100 -73.649851927 100 -7364.9851927 542430.068887 4028.02571462 
+100 -71.4581416568 100 -7145.81416568 510626.600904 3874.48765038 
+100 -82.7704449463 100 -8277.04449463 685094.655661 4718.54716594 
+100 -73.4958850397 100 -7349.58850397 540164.511776 4017.08284628 
+100 -79.9548691502 100 -7995.48691502 639278.110083 4496.50337754 
+100 -73.7591896692 100 -7375.91896692 544041.806066 4035.81105616 
+100 -74.9608174585 100 -7496.08174585 561912.415404 4122.16003338 
+100 -70.3315381073 100 -7033.15381073 494652.525254 3797.433781 
+100 -81.5050193855 100 -8150.50193855 664306.818503 4617.77154405 
+100 -73.6323572025 100 -7363.23572025 542172.40272 4026.78112059 
+100 -74.1588162163 100 -7415.88162163 549953.00226 4064.36797076 
+100 -72.2683723036 100 -7226.83723036 522271.763542 3930.68788695 
+100 -73.8960319613 100 -7389.60319613 546062.353962 4045.57168991 
+100 -81.2367643091 100 -8123.67643091 659941.187541 4596.61402693 
+100 -71.8406376175 100 -7184.06376175 516107.721328 3900.9370126 
+100 -80.5710668478 100 -8057.10668478 649169.681299 4544.42073937 
+100 -81.5255887368 100 -8152.55887368 664642.161889 4619.3968376 
+100 -70.8987909906 100 -7089.87909906 502663.856392 3836.07230449 
+100 -83.6897571438 100 -8368.97571438 700397.545079 4792.76333254 
+100 -78.4770414765 100 -7847.70414765 615864.603891 4383.13041576 
+100 -71.2749695004 100 -7127.49695004 508012.127728 3861.87321489 
+100 -73.8582329675 100 -7385.82329675 545503.857708 4042.87370612 
+100 -75.2737119814 100 -7527.37119814 566613.171545 4144.88157777 
+100 -80.7074417079 100 -8070.74417079 651369.114703 4555.07696924 
+100 -70.7734065156 100 -7077.34065156 500887.506983 3827.50401862 
+100 -80.6592636105 100 -8065.92636105 650591.680618 4551.31024406 
+100 -83.6095144627 100 -8360.95144627 699055.090869 4786.25166819 
+100 -79.9802945629 100 -7998.02945629 639684.751837 4498.47302278 
+100 -71.5823305004 100 -7158.23305004 512403.003986 3883.05919368 
+100 -76.6694176029 100 -7666.94176029 587819.959558 4247.42625378 
+100 -75.708481597 100 -7570.8481597 573177.418573 4176.61588887 
+100 -80.7953299952 100 -8079.53299952 652788.534904 4561.95434953 
+100 -71.7422391787 100 -7174.22391787 514694.888237 3894.11884324 
+100 -76.4314343741 100 -7643.14343741 584176.416048 4229.80349431 
+100 -71.478974234 100 -7147.8974234 510924.375755 3875.92444319 
+100 -81.3838379406 100 -8138.38379406 662332.907794 4608.20494412 
+100 -78.8674923341 100 -7886.74923341 622008.134708 4412.8719427 
+100 -80.1787797152 100 -8017.87797152 642863.671663 4513.87140903 
+100 -82.3220099004 100 -8232.20099004 677691.331404 4682.65163227 
+100 -77.9546361306 100 -7795.46361306 607692.529426 4343.5760568 
+100 -83.968191812 100 -8396.8191812 705065.723618 4815.40813856 
+100 -74.3301038453 100 -7433.01038453 552496.433766 4076.65690921 
+100 -75.3770163534 100 -7537.70163534 568169.459434 4152.40475629 
+100 -76.3994236742 100 -7639.94236742 583687.193775 4227.43740969 
+100 -79.6158239943 100 -7961.58239943 633867.943029 4470.30015516 
+100 -83.5905200745 100 -8359.05200745 698737.504632 4784.71122297 
+100 -79.3633237392 100 -7936.33237392 629853.715493 4450.86026812 
+100 -77.2687789608 100 -7726.87789608 597046.420209 4292.06015364 
+100 -79.971033706 100 -7997.1033706 639536.6232 4497.75553174 
+100 -84.1637516981 100 -8416.37516981 708353.709989 4831.3591707 
+100 -70.9706722284 100 -7097.06722284 503683.631656 3840.99147771 
+100 -74.8057417452 100 -7480.57417452 559589.899805 4110.93514466 
+100 -75.6563951254 100 -7565.63951254 572389.012337 4172.80407387 
+100 -77.7698723964 100 -7776.98723964 604815.305256 4329.65184529 
+100 -73.6354844447 100 -7363.54844447 542218.45694 4027.00357359 
+100 -73.9798373948 100 -7397.98373948 547301.634097 4051.558577 
+100 -80.9111048706 100 -8091.11048706 654660.689139 4571.02568352 
+100 -71.6851587803 100 -7168.51587803 513876.198936 3890.16809773 
+100 -75.6084882124 100 -7560.84882124 571664.348976 4169.30052435 
+100 -80.0437202794 100 -8004.37202794 640699.715616 4503.38927738 
+100 -73.9130278374 100 -7391.30278374 546313.568409 4046.78527245 
+100 -78.9057093737 100 -7890.57093737 622611.097176 4415.79121245 
+100 -74.4861704469 100 -7448.61704469 554818.958785 4087.87936781 
+100 -84.021122227 100 -8402.1122227 705954.898029 4819.72168458 
+100 -82.4294853763 100 -8242.94853763 679462.005939 4691.23631626 
+100 -70.082813823 100 -7008.2813823 491160.079335 3780.59336212 
+100 -70.809317696 100 -7080.9317696 501395.947258 3829.95644205 
+100 -83.5029049139 100 -8350.29049139 697273.512906 4777.61030225 
+100 -84.9727208411 100 -8497.27208411 722036.328714 4897.74984147 
+100 -78.8990560315 100 -7889.90560315 622506.104267 4415.28288125 
+100 -82.0954982398 100 -8209.54982398 673967.083124 4664.59667002 
+100 -84.0927710683 100 -8409.27710683 707159.414595 4825.56514531 
+100 -72.6283672157 100 -7262.83672157 527487.972443 3955.86894417 
+100 -78.6289067961 100 -7862.89067961 618250.498396 4394.68022499 
+100 -78.3908350695 100 -7839.08350695 614512.30229 4376.58442377 
+100 -71.1112525094 100 -7111.12525094 505681.023345 3850.62698545 
+100 -71.5128582591 100 -7151.28582591 511408.889639 3878.26230255 
+100 -84.3508319439 100 -8435.08319439 711506.284963 4846.65434495 
+100 -84.425003815 100 -8442.5003815 712758.126917 4852.72812505 
+100 -73.6822523743 100 -7368.22523743 542907.431496 4030.33152654 
+100 -77.0440761995 100 -7704.40761995 593578.967743 4275.28464822 
+100 -74.510062476 100 -7451.0062476 555174.941018 4089.5995489 
+100 -82.0103850803 100 -8201.03850803 672570.326103 4657.82566781 
+100 -71.9275884739 100 -7192.75884739 517357.798367 3906.97002065 
+300 -75.6022482787 300 -22680.6744836 1714709.98344 10506.5330551 
+300 -72.648120403 300 -21794.4361209 1583324.81943 9871.76319412 
+300 -82.9231519972 300 -24876.9455992 2062874.74115 12192.4500658 
+300 -79.6592036171 300 -23897.7610851 1903676.61627 11420.9390542 
+300 -84.7669492044 300 -25430.0847613 2155630.70322 12642.4013971 
+300 -75.2585693513 300 -22577.5708054 1699155.67824 10431.3391211 
+300 -80.0753514248 300 -24022.6054274 1923618.57174 11517.527723 
+300 -72.0541410299 300 -21616.242309 1557539.77187 9747.29280161 
+300 -75.7709196244 300 -22731.2758873 1722369.67822 10543.5664939 
+300 -81.0554892025 300 -24316.6467608 1970997.69896 11747.0723258 
+300 -71.9704364232 300 -21591.1309269 1553923.11568 9729.83730523 
+300 -79.3328177135 300 -23799.845314 1888108.78991 11345.5478167 
+300 -80.5702799117 300 -24171.0839735 1947471.00151 11633.0779082 
+300 -73.8747105571 300 -22162.4131671 1637241.85797 10132.1489607 
+300 -82.8210487238 300 -24846.3146171 2057797.83351 12167.8313021 
+300 -70.3359798159 300 -21100.7939448 1484145.017 9393.20523637 
+300 -75.5297366417 300 -22658.9209925 1711422.33515 10490.6386509 
+300 -82.9063642538 300 -24871.9092761 2062039.57013 12188.4001188 
+300 -77.0910782232 300 -23127.323467 1782910.30248 10836.3684257 
+300 -70.150030883 300 -21045.0092649 1476308.04987 9355.41501771 
+300 -75.0248039818 300 -22507.4411945 1688616.36375 10380.3957889 
+300 -81.6849050879 300 -24505.4715264 2001727.11577 11895.9987907 
+300 -80.8512123451 300 -24255.3637035 1961075.5613 11698.9937139 
+300 -74.9948502782 300 -22498.4550835 1687268.27048 10373.8799753 
+300 -84.7132765965 300 -25413.9829789 2152901.76951 12629.1592731 
+300 -73.9591838193 300 -22187.7551458 1640988.26136 10150.2474282 
+300 -77.1585267728 300 -23147.5580318 1786031.47612 10851.4684298 
+300 -83.5340541717 300 -25060.2162515 2093381.46191 12340.4019033 
+300 -83.0957024243 300 -24928.7107273 2071468.72842 12234.1258739 
+300 -75.2157191063 300 -22564.7157319 1697221.32021 10421.9887077 
+300 -74.5894808488 300 -22376.8442547 1669077.19599 10285.9648736 
+300 -82.5568093706 300 -24767.0428112 2044688.03204 12104.2640899 
+300 -83.6180456032 300 -25085.413681 2097593.26515 12360.8309837 
+300 -71.734037708 300 -21520.2113124 1543731.64977 9680.65296603 
+300 -81.1784111968 300 -24353.523359 1976980.33333 11776.0635827 
+300 -71.7153299411 300 -21514.5989823 1542926.56457 9676.76784829 
+300 -76.6458597375 300 -22993.7579213 1762376.34447 10737.0377743 
+300 -77.8804087219 300 -23364.1226166 1819607.41881 11013.9340286 
+300 -73.8998361424 300 -22169.9508427 1638355.73456 10137.5299017 
+300 -82.1762321414 300 -24652.8696424 2025879.93869 12013.0779524 
+300 -77.4129924142 300 -23223.8977243 1797831.41836 10908.5596487 
+300 -71.1777223423 300 -21353.3167027 1519880.44735 9565.56931918 
+300 -75.7452866194 300 -22723.5859858 1721204.53352 10537.9330179 
+300 -79.7907836831 300 -23937.2351049 1909970.74823 11451.4228635 
+300 -72.6021211999 300 -21780.63636 1581320.40082 9862.08609508 
+300 -70.0725071809 300 -21021.7521543 1473046.87879 9339.69059007 
+300 -79.5997867464 300 -23879.9360239 1900837.81502 11407.1906745 
+300 -84.7331728514 300 -25419.9518554 2153913.17444 12634.0670758 
+300 -74.7104121079 300 -22413.1236324 1674493.7032 10312.1404252 
+300 -81.3186191649 300 -24395.5857495 1983815.34686 11809.1870906 
+300 -74.9384644681 300 -22481.5393404 1684732.03705 10361.6217017 
+300 -75.6622805854 300 -22698.6841756 1717434.21101 10519.7039507 
+300 -71.2805515127 300 -21384.1654538 1524275.10718 9586.77139958 
+300 -72.3400709693 300 -21702.0212908 1569925.76035 9807.07826949 
+300 -83.7121498844 300 -25113.6449653 2102317.21148 12383.7449333 
+300 -71.8867283263 300 -21566.0184979 1550310.51284 9712.40210174 
+300 -84.5027145316 300 -25350.8143595 2142212.62896 12577.2927858 
+300 -84.6675304218 300 -25400.2591265 2150577.21232 12617.8795834 
+300 -80.2474114487 300 -24074.2234346 1931894.11327 11557.6149805 
+300 -72.9514853326 300 -21885.4455998 1596575.76367 9935.74267835 
+300 -73.5122048027 300 -22053.6614408 1621213.27648 10054.7248464 
+300 -80.674550892 300 -24202.3652676 1952514.94849 11657.5156107 
+300 -73.0796084211 300 -21923.8825263 1602188.7501 9962.84668732 
+300 -75.6039653133 300 -22681.189594 1714787.87133 10506.9096168 
+300 -74.894165163 300 -22468.2495489 1682740.79264 10351.9977245 
+300 -73.9965829146 300 -22198.9748744 1642648.28491 10158.2670527 
+300 -74.0986471254 300 -22229.5941376 1647182.85174 10180.1744053 
+300 -81.4658626934 300 -24439.758808 1991006.03532 11844.0362064 
+300 -80.7626738071 300 -24228.8021421 1956782.84414 11678.1941672 
+300 -70.589855757 300 -21176.9567271 1494878.32074 9444.9676855 
+300 -71.4007889875 300 -21420.2366963 1529421.80041 9611.60308466 
+300 -73.55213767 300 -22065.641301 1622975.08675 10063.2344012 
+300 -70.1865888712 300 -21055.9766614 1477847.17721 9362.83646953 
+300 -74.7855368816 300 -22435.6610645 1677862.958 10328.4232634 
+300 -71.6937653475 300 -21508.1296043 1541998.79691 9672.29074446 
+300 -81.2993455038 300 -24389.8036512 1982875.07381 11804.6302778 
+300 -79.3966938759 300 -23819.0081628 1891150.49953 11360.2772936 
+300 -77.5900278523 300 -23277.0083557 1806063.72664 10948.3934243 
+300 -77.8374279436 300 -23351.2283831 1817599.55666 11004.2170737 
+300 -75.141333279 300 -22542.3999837 1693865.99008 10405.7699508 
+300 -84.9141598661 300 -25474.2479598 2163124.36373 12678.7656196 
+300 -81.0633137279 300 -24318.9941184 1971378.24976 11748.9163959 
+300 -72.1621500821 300 -21648.6450246 1562212.77134 9769.8477311 
+300 -75.1912357205 300 -22557.3707162 1696116.57875 10416.6486259 
+300 -78.6033352384 300 -23581.0005715 1853545.29318 11178.2014516 
+300 -80.828050969 300 -24248.4152907 1959952.14703 11693.5503529 
+300 -76.0892621408 300 -22826.7786423 1736872.74394 10613.6942537 
+300 -81.9353546432 300 -24580.606393 2014020.70215 11955.5883509 
+300 -84.3647839407 300 -25309.4351822 2135225.03081 12543.3892745 
+300 -72.592282888 300 -21777.6848664 1580891.86047 9860.01718068 
+300 -81.4821515193 300 -24444.6454558 1991802.30486 11847.8953879 
+300 -79.3381932815 300 -23801.4579844 1888364.67395 11346.7869201 
+300 -71.2678247942 300 -21380.3474383 1523730.85527 9584.14559039 
+300 -84.2436632836 300 -25273.0989851 2129098.44103 12513.6647305 
+300 -76.2366017601 300 -22870.980528 1743605.83438 10646.2546587 
+300 -84.6105511801 300 -25383.165354 2147683.6113 12603.8389227 
+300 -75.9742119226 300 -22792.2635768 1731624.26318 10588.3147265 
+300 -82.3438246668 300 -24703.1474 2034151.63823 12053.1795061 
+300 -71.2309336334 300 -21369.28009 1522153.77189 9576.53685719 
+300 -70.4567065719 300 -21137.0119716 1489244.25029 9417.79595215 
+300 -83.2527965008 300 -24975.8389503 2079308.43756 12272.1462141 
+300 -80.2346489777 300 -24070.3946933 1931279.66897 11554.6384775 
+300 -72.7101128133 300 -21813.033844 1586028.1516 9884.81491188 
+300 -76.6354852934 300 -22990.645588 1761899.28184 10734.7302695 
+300 -74.7339060624 300 -22420.1718187 1675547.0146 10317.2307775 
+300 -79.9959124662 300 -23998.7737399 1919803.80339 11499.0496735 
+300 -78.985899694 300 -23695.7699082 1871631.70514 11265.764278 
+300 -71.5272273567 300 -21458.168207 1534843.276 9637.76217483 
+300 -84.1347772422 300 -25240.4331727 2123598.22248 12486.9802831 
+300 -74.9639340341 300 -22489.1802102 1685877.42176 10367.1576036 
+300 -80.4631572086 300 -24138.9471626 1942295.90039 11608.0058229 
+300 -77.3687283662 300 -23210.6185099 1795776.0387 10898.6147308 
+300 -83.4148139007 300 -25024.4441702 2087409.35342 12311.4356629 
+300 -84.7469343695 300 -25424.0803109 2154612.86551 12637.4623198 
+300 -73.1195475321 300 -21935.8642596 1603940.46939 9971.30574045 
+300 -70.3161921044 300 -21094.8576313 1483310.06162 9389.17886731 
+300 -71.4309728758 300 -21429.2918627 1530715.1658 9617.84353241 
+300 -71.7339132105 300 -21520.1739631 1543726.29135 9680.62710766 
+300 -72.7941085921 300 -21838.2325776 1589694.67372 9902.51755414 
+300 -79.3277468803 300 -23798.3240641 1887867.42753 11344.3790361 
+300 -79.9765869667 300 -23992.97609 1918876.33885 11494.557292 
+300 -79.0847006152 300 -23725.4101846 1876316.96142 11288.4495525 
+300 -81.8048016827 300 -24541.4405048 2007607.6735 11924.5023549 
+300 -78.468440687 300 -23540.5322061 1847188.85516 11147.4309706 
+300 -70.7469269685 300 -21224.0780906 1501538.30265 9477.08956097 
+300 -79.4697867566 300 -23840.936027 1894634.10214 11377.14711 
+300 -83.2943824924 300 -24988.3147477 2081386.24644 12282.2233635 
+300 -70.968752929 300 -21290.6258787 1510969.16769 9522.58019149 
+300 -75.0054144749 300 -22501.6243425 1687743.66017 10376.1776923 
+300 -84.2755600572 300 -25282.6680172 2130711.00689 12521.488334 
+300 -78.2793148339 300 -23483.7944502 1838295.33926 11104.381835 
+300 -74.690082507 300 -22407.0247521 1673582.52747 10307.7370185 
+300 -81.0773825424 300 -24323.2147627 1972062.58798 11752.2325708 
+300 -72.245287001 300 -21673.5861003 1565814.44816 9787.23258828 
+300 -76.0824896037 300 -22824.7468811 1736563.56729 10612.1991644 
+300 -72.4355574532 300 -21730.667236 1574072.99507 9827.09829443 
+300 -81.4035249981 300 -24421.0574994 1987960.16464 11829.2743857 
+300 -73.2457752691 300 -21973.7325807 1609483.07843 9998.07207764 
+300 -76.8049263266 300 -23041.477898 1769699.01241 10772.4581146 
+300 -83.30064916 300 -24990.194748 2081699.44514 12283.742357 
+300 -72.700684966 300 -21810.2054898 1585616.87836 9882.82925454 
+300 -77.9570264962 300 -23387.1079489 1823189.39404 11031.2692715 
+300 -72.8252413607 300 -21847.5724082 1591054.73377 9909.08435866 
+300 -72.3848785942 300 -21715.4635783 1571871.19473 9816.46938419 
+300 -76.8395419078 300 -23051.8625723 1771294.56018 10780.1762366 
+300 -72.2157825132 300 -21664.734754 1564535.7732 9781.06049714 
+300 -76.302410763 300 -22890.7232289 1746617.36647 10660.8187516 
+300 -74.2234118099 300 -22267.023543 1652734.45821 10206.9967025 
+300 -74.7213219389 300 -22416.3965817 1674982.78569 10314.5040139 
+300 -79.7078009763 300 -23912.3402929 1906000.06094 11432.1917974 
+300 -77.044307266 300 -23113.2921798 1780747.58463 10825.9056187 
+300 -79.1762216181 300 -23752.8664854 1880662.22092 11309.4894424 
+300 -76.6612611853 300 -22998.3783556 1763084.68996 10740.4639909 
+300 -78.9176893573 300 -23675.3068072 1868400.50805 11250.1198701 
+300 -71.3418450907 300 -21402.5535272 1526897.65828 9599.42445323 
+300 -72.3040305105 300 -21691.2091532 1568361.84842 9799.52901328 
+300 -80.3357043273 300 -24100.7112982 1936147.61693 11578.2203022 
+300 -77.1945319385 300 -23158.3595815 1787698.72836 10859.5346523 
+300 -80.859643746 300 -24257.8931238 1961484.59602 11700.975652 
+300 -74.4263609284 300 -22327.9082785 1661784.96031 10250.7270946 
+300 -76.0710530201 300 -22821.315906 1736041.53228 10609.6747637 
+300 -77.4773392857 300 -23243.2017857 1800821.43084 10923.0271095 
+300 -83.0253678463 300 -24907.6103539 2067963.5118 12217.1273002 
+300 -72.7002417733 300 -21810.072532 1585597.54617 9882.73591754 
+300 -75.3230494256 300 -22596.9148277 1702068.53243 10445.4197915 
+300 -77.4131352286 300 -23223.9405686 1797838.05177 10908.5917447 
+300 -71.6308846239 300 -21489.2653872 1539295.0896 9659.24381332 
+300 -71.1716187481 300 -21351.4856244 1519619.79457 9564.31183222 
+300 -80.3689714236 300 -24110.6914271 1937751.4703 11585.9900658 
+300 -73.0744992115 300 -21922.3497634 1601964.7305 9961.76490843 
+300 -80.3117995514 300 -24093.5398654 1934995.54416 11572.6392241 
+300 -74.9690797427 300 -22490.7239228 1686108.87524 10368.2762781 
+300 -84.0962360265 300 -25228.8708079 2121653.07415 12477.5436005 
+300 -79.2904535675 300 -23787.1360703 1886092.80808 11335.7856387 
+300 -80.9236036088 300 -24277.0810826 1964588.88631 11716.0174045 
+300 -82.6555491134 300 -24796.664734 2049581.93977 12127.9930805 
+300 -70.9797888988 300 -21293.9366697 1511439.12964 9524.84723145 
+300 -83.3082023622 300 -24992.4607087 2082076.97425 12285.5733535 
+300 -80.5015385675 300 -24150.4615703 1944149.31352 11616.9850284 
+300 -71.3931654036 300 -21417.9496211 1529095.2199 9610.027359 
+300 -77.8867584979 300 -23366.0275494 1819904.14479 11015.3700352 
+300 -70.4324925223 300 -21129.7477567 1488220.80087 9412.86031045 
+300 -80.8494295154 300 -24254.8288546 1960989.07589 11698.5746581 
+300 -71.0652998838 300 -21319.5899651 1515083.05427 9542.42552223 
+300 -82.7975560212 300 -24839.2668064 2056630.58493 12162.1712545 
+300 -77.7890055706 300 -23336.7016712 1815338.8163 10993.2765397 
+300 -75.9253420299 300 -22777.602609 1729397.26871 10577.5462783 
+300 -75.0338873049 300 -22510.1661915 1689025.27322 10382.3722113 
+300 -81.2834148765 300 -24385.0244629 1982098.06019 11800.8646894 
+300 -71.0385509849 300 -21311.5652955 1513942.71781 9536.92445667 
+300 -73.1073152387 300 -21932.1945716 1603403.86242 9968.71444782 
+300 -73.3768395367 300 -22013.051861 1615248.17412 10025.9145741 
+300 -80.104918594 300 -24031.4755782 1925039.39489 11524.410085 
+300 -72.8558965673 300 -21856.7689702 1592394.49939 9915.55327269 
+300 -72.3620467911 300 -21708.6140373 1570879.74474 9811.68337276 
+300 -79.9768363506 300 -23993.0509052 1918888.3058 11494.6152564 
+300 -76.3961217999 300 -22918.83654 1750910.22782 10681.5802256 
+300 -70.1724387867 300 -21051.731636 1477251.34958 9359.96345702 
+300 -83.987831821 300 -25196.3495463 2116186.7682 12451.0251023 
+300 -78.837399576 300 -23651.2198728 1864600.67157 11231.722861 
+300 -83.9543078593 300 -25186.2923578 2114497.74244 12442.8314032 
+300 -79.4728134335 300 -23841.84403 1894778.42251 11377.8460118 
+300 -73.3479806188 300 -22004.3941857 1613977.87826 10019.7795367 
+300 -80.2436462688 300 -24073.0938807 1931712.82996 11556.7368028 
+300 -83.374256912 300 -25012.2770736 2085380.01469 12301.5931466 
+300 -83.0048256378 300 -24901.4476913 2066940.32375 12212.1654265 
+300 -74.1931792636 300 -22257.9537791 1651388.35477 10200.4929294 
+300 -79.512897448 300 -23853.8692344 1896690.25817 11387.10456 
+300 -83.4342520536 300 -25030.2756161 2088382.32473 12316.1547332 
+300 -79.2982149329 300 -23789.4644799 1886462.06746 11337.5737253 
+300 -73.334759205 300 -22000.4277615 1613396.0723 10016.9696674 
+300 -79.8844304316 300 -23965.3291295 1914456.66761 11473.1501098 
+300 -76.8731871896 300 -23061.9561569 1772846.07261 10787.6814591 
+300 -74.3448671427 300 -22303.4601428 1658147.78114 10233.1524021 
+300 -80.5726760441 300 -24171.8028132 1947586.83747 11633.639117 
+300 -76.7587689191 300 -23027.6306757 1767572.58179 10762.1721421 
+300 -76.6864404138 300 -23005.9321242 1764243.043 10746.0669119 
+300 -76.6408670092 300 -22992.2601027 1762146.74877 10735.9272413 
+300 -71.602359854 300 -21480.7079562 1538069.381 9653.32920609 
+300 -79.8362947633 300 -23950.888429 1912150.18846 11461.9787316 
+300 -75.3331494487 300 -22599.9448346 1702525.02176 10447.6264879 
+300 -78.7646052077 300 -23629.3815623 1861158.91006 11215.0600112 
+300 -72.7768096152 300 -21833.0428846 1588939.20533 9898.86995453 
+300 -72.4345529327 300 -21730.3658798 1574029.33757 9826.88754085 
+300 -74.8878035466 300 -22466.341064 1682454.93601 10350.6161535 
+300 -82.5159872908 300 -24754.7961872 2042666.44757 12094.4623332 
+300 -72.9408080337 300 -21882.2424101 1596108.44298 9933.48615465 
+300 -72.2359455356 300 -21670.7836607 1565409.54823 9785.27814961 
+300 -83.6114071043 300 -25083.4221313 2097260.21939 12359.2155437 
+300 -70.8862417158 300 -21265.8725147 1507457.77938 9505.64208402 
+300 -76.3925004741 300 -22917.7501422 1750744.23861 10680.7774395 
+300 -79.1757360266 300 -23752.720808 1880639.15261 11309.3777428 
+300 -73.6667568925 300 -22100.0270677 1628037.32132 10087.6859299 
+300 -81.2981160148 300 -24389.4348044 1982815.10026 11804.3396312 
+300 -75.3765082808 300 -22612.9524842 1704485.40018 10457.1031888 
+300 -80.0081999107 300 -24002.4599732 1920393.61588 11501.9065801 
+300 -84.5916150675 300 -25377.4845203 2146722.40192 12599.1748966 
+300 -75.9502359097 300 -22785.0707729 1730531.50042 10583.0307328 
+300 -80.3380527012 300 -24101.4158104 1936260.81355 11578.7686725 
+300 -84.0607774514 300 -25218.2332354 2119864.29172 12468.8656277 
+300 -71.5838868243 300 -21475.1660473 1537275.85586 9649.50012813 
+300 -70.5305583382 300 -21159.1675015 1492367.89785 9432.86030171 
+300 -84.6381962703 300 -25391.4588811 2149087.28037 12610.6499298 
+300 -83.7172461561 300 -25115.1738468 2102573.19119 12384.9866098 
+300 -71.8835824769 300 -21565.0747431 1550174.82892 9711.747276 
+300 -75.6112774838 300 -22683.3832451 1715119.58482 10508.513343 
+300 -70.1683341816 300 -21050.5002545 1477078.53655 9359.13017637 
+300 -84.5669001975 300 -25370.0700593 2145468.18271 12593.089162 
+300 -74.3747417334 300 -22312.42252 1659480.66237 10239.5927489 
+300 -75.295969571 300 -22588.7908713 1700844.91009 10439.5047787 
+300 -74.6326841648 300 -22389.8052494 1671011.26369 10295.3111872 
+300 -73.8637895183 300 -22159.1368555 1636757.8206 10129.8106816 
+300 -78.6221307754 300 -23586.6392326 1854431.8343 11182.4931907 
+300 -72.019538951 300 -21605.8616853 1556044.19721 9740.07444393 
+300 -75.4690500356 300 -22640.7150107 1708673.25398 10477.3483946 
+300 -79.7951471959 300 -23938.5441588 1910179.6548 11452.43467 
+300 -71.6260232704 300 -21487.8069811 1539086.16286 9658.23563977 
+300 -70.1786314262 300 -21053.5894279 1477512.09266 9361.22072758 
+300 -72.9320166784 300 -21879.6050035 1595723.71704 9931.62846009 
+300 -75.0387588027 300 -22511.6276408 1689244.5968 10383.432293 
+300 -76.675502453 300 -23002.6507359 1763739.80293 10743.6327462 
+300 -74.6362124095 300 -22390.8637228 1671169.26085 10296.0747112 
+300 -83.7035430948 300 -25111.0629284 2101884.93799 12381.6481167 
+300 -83.5633660243 300 -25069.0098073 2094850.84239 12347.5289668 
+300 -74.4363557181 300 -22330.9067154 1662231.31578 10252.883911 
+300 -84.2561939454 300 -25276.8581836 2129731.86545 12516.7378727 
+300 -80.1613505971 300 -24048.4051791 1927752.63887 11537.5530649 
+300 -83.603037773 300 -25080.9113319 2096840.37746 12357.179104 
+300 -81.2817835916 300 -24384.5350775 1982018.50315 11800.4791388 
+300 -78.9051874006 300 -23671.5562202 1867808.57962 11247.2539926 
+300 -84.7163755752 300 -25414.9126725 2153059.28718 12629.9236191 
+300 -79.1151995114 300 -23734.5598534 1877764.43812 11295.4581942 
+300 -83.3989442887 300 -25019.6832866 2086615.17254 12307.5837805 
+300 -82.7471343203 300 -24824.1402961 2054126.47146 12150.0288499 
+300 -72.2208158134 300 -21666.244744 1564753.87103 9782.11323653 
+300 -82.8527245418 300 -24855.8173625 2059372.1892 12175.4655119 
+300 -73.2460611586 300 -21973.8183476 1609495.64258 9998.13275419 
+300 -83.8568281089 300 -25157.0484327 2109590.28614 12419.0252199 
+300 -79.5950164091 300 -23878.5049227 1900609.99115 11406.0873327 
+300 -77.8738236923 300 -23362.1471077 1819299.72494 11012.444947 
+300 -80.9358159472 300 -24280.7447842 1965181.89091 11718.890835 
+300 -77.9099103933 300 -23372.973118 1820986.24125 11020.6068783 
+300 -84.4748112442 300 -25342.4433733 2140798.12042 12570.4295178 
+300 -78.9507111904 300 -23685.2133571 1869964.43924 11257.6918623 
+300 -84.3515438093 300 -25305.4631428 2134554.8829 12540.1378359 
+300 -71.9551597185 300 -21586.5479156 1553263.50304 9726.65381729 
+300 -84.7442790131 300 -25423.2837039 2154477.84764 12636.8071456 
+300 -71.8810886358 300 -21564.3265907 1550067.27104 9711.22819043 
+300 -75.6119691793 300 -22683.5907538 1715150.96495 10508.6650559 
+300 -81.5407631838 300 -24462.2289551 1994668.81818 11861.788367 
+300 -72.3986343131 300 -21719.5902939 1572468.67512 9819.35361826 
+300 -82.2579149159 300 -24677.3744748 2029909.36989 12032.6124876 
+300 -71.5646327693 300 -21469.3898308 1536448.99902 9645.51024934 
+300 -84.0163753043 300 -25204.9125913 2117625.39578 12458.0041641 
+300 -71.8377245776 300 -21551.3173733 1548197.60175 9702.20507441 
+300 -76.3058817205 300 -22891.7645161 1746776.27554 10661.5872648 
+300 -78.5626419297 300 -23568.7925789 1851626.61209 11168.913246 
+300 -76.9493493463 300 -23084.8048039 1776360.70945 10804.6834271 
+300 -83.6850379921 300 -25105.5113976 2100955.67512 12377.1405907 
+300 -82.0812810669 300 -24624.3843201 2021201.01048 11990.3954444 
+300 -76.9469371839 300 -23084.0811552 1776249.3426 10804.1446841 
+300 -74.824426195 300 -22447.3278585 1679608.42662 10336.8589367 
+300 -81.7760662802 300 -24532.8198841 2006197.50488 11917.6670273 
+300 -84.6799470046 300 -25403.9841014 2151208.02741 12620.9405345 
+300 -83.5780397537 300 -25073.4119261 2095586.61872 12351.0977954 
+300 -74.6048610342 300 -22381.4583102 1669765.58698 10289.2914771 
+300 -82.4822547083 300 -24744.6764125 2040996.70253 12086.3666023 
+300 -73.2707174921 300 -21981.2152476 1610579.41254 10003.3666815 
+300 -77.9264861292 300 -23377.9458387 1821761.17213 11024.3572147 
+300 -81.1485603126 300 -24344.5680938 1975526.65224 11769.0190589 
+300 -70.9046801346 300 -21271.4040404 1508242.0995 9509.42539648 
+300 -75.3250583936 300 -22597.5175181 1702159.3266 10445.8586951 
+300 -82.7072490352 300 -24812.1747106 2052146.71289 12140.4291967 
+300 -77.7400171985 300 -23322.0051596 1813053.08221 10982.2152821 
+300 -82.2602217357 300 -24678.0665207 2030023.224 12033.164457 
+300 -75.5434086871 300 -22663.0226061 1712041.97882 10493.6343289 
+300 -76.7258972964 300 -23017.7691889 1766058.99478 10754.8507442 
+300 -73.2280245506 300 -21968.4073652 1608703.07388 9994.30518525 
+300 -75.520648502 300 -22656.1945506 1711010.50505 10488.6476615 
+300 -72.7723583728 300 -21831.7075118 1588744.84294 9897.93152691 
+300 -73.4666929368 300 -22040.0078811 1619206.49132 10045.0322596 
+300 -82.0762869217 300 -24622.8860765 2020955.06246 11989.2031604 
+300 -74.7831880027 300 -22434.9564008 1677757.56236 10327.9139018 
+300 -80.8914972896 300 -24267.4491869 1963030.30012 11708.4652709 
+300 -83.2970201712 300 -24989.1060514 2081518.07082 12282.8627028 
+300 -73.4307488191 300 -22029.2246457 1617622.46164 10037.3816921 
+300 -71.1343326004 300 -21340.2997801 1518027.98235 9556.63241724 
+300 -72.842838136 300 -21852.8514408 1591823.72031 9912.79731555 
+300 -81.8683705602 300 -24560.5111681 2010729.02946 11939.6323681 
+300 -77.4909319403 300 -23247.2795821 1801453.35989 10926.0848099 
+300 -73.8045775614 300 -22141.3732684 1634134.70071 10117.1391718 
+300 -75.9379095334 300 -22781.37286 1729969.83129 10580.314835 
+300 -73.0695793425 300 -21920.8738027 1601749.02759 9960.72329287 
+300 -76.7156809458 300 -23014.7042837 1765588.71089 10752.5759474 
+300 -76.0412906645 300 -22812.3871993 1734683.36578 10603.1071489 
+300 -74.4573490025 300 -22337.2047007 1663169.04614 10257.4151132 
+300 -77.519252609 300 -23255.7757827 1802770.35752 10932.457393 
+300 -83.8849320809 300 -25165.4796243 2111004.54906 12425.8857547 
+300 -78.3939302722 300 -23518.1790817 1843682.49106 11130.4579782 
+300 -84.6451403354 300 -25393.5421006 2149439.93472 12612.3611211 
+300 -84.1856013883 300 -25255.6804165 2126164.64433 12499.4312113 
+300 -76.7325431855 300 -23019.7629557 1766364.95511 10756.3307017 
+300 -74.5074287183 300 -22352.2286155 1665407.08026 10268.2296859 
+300 -70.1751990764 300 -21052.5597229 1477367.56962 9360.52385505 
+300 -72.9855896565 300 -21895.6768969 1598068.88925 9942.95252383 
+300 -73.7305838899 300 -22119.175167 1630859.70022 10101.3191219 
+300 -77.255935576 300 -23176.7806728 1790543.87452 10873.2998558 
+300 -72.3531027514 300 -21705.9308254 1570491.44333 9809.808946 
+300 -73.6619165983 300 -22098.5749795 1627823.38708 10086.6525609 
+300 -73.878132651 300 -22163.4397953 1637393.5452 10132.8817311 
+300 -83.2735912353 300 -24982.0773706 2080347.29917 12277.1845616 
+300 -70.9223031678 300 -21276.6909504 1508991.92599 9513.04235619 
+300 -74.4645219347 300 -22339.3565804 1663489.50809 10258.9636259 
+300 -79.7785393045 300 -23933.5617914 1909384.60007 11448.5839556 
+300 -72.0080205339 300 -21602.4061602 1555546.50636 9737.6723778 
+300 -84.7246856002 300 -25417.4056801 2153481.70502 12631.9733831 
+300 -78.0997846054 300 -23429.9353816 1829872.90662 11063.6161486 
+300 -72.3948895445 300 -21718.4668633 1572306.00965 9818.56837665 
+300 -81.1453692744 300 -24343.6107823 1975371.2864 11768.2661625 
+300 -73.3630180543 300 -22008.9054163 1614639.72541 10022.9759916 
+300 -74.5602623737 300 -22368.0787121 1667769.81757 10279.64712 
+300 -73.1862777724 300 -21955.8833317 1606869.37625 9985.44979798 
+300 -79.1456486284 300 -23743.6945885 1879210.10905 11302.4581805 
+300 -79.8114521174 300 -23943.4356352 1910960.36673 11456.2159428 
+300 -82.1437008109 300 -24643.1102433 2024276.27487 12005.3036183 
+300 -72.6453086268 300 -21793.592588 1583202.25964 9871.17148352 
+300 -70.1497239929 300 -21044.9171979 1476295.13289 9355.35273448 
+300 -70.8942092256 300 -21268.2627677 1507796.67052 9507.2767834 
+300 -75.6232574307 300 -22686.9772292 1715663.11933 10511.1411659 
+300 -84.8934817905 300 -25468.0445372 2162070.97515 12673.6537623 
+300 -72.3434311345 300 -21703.0293404 1570071.60849 9807.78230896 
+300 -73.1169515617 300 -21935.0854685 1603826.5817 9970.7557718 
+300 -76.8806983012 300 -23064.2094904 1773192.53138 10789.3574197 
+300 -82.0248709282 300 -24607.4612785 2018423.83523 11976.9326442 
+300 -78.112093748 300 -23433.6281244 1830449.75691 11066.4080814 
+300 -71.2957593178 300 -21388.7277953 1524925.58901 9589.90975018 
+300 -73.6781130649 300 -22103.4339195 1628539.30344 10090.1106692 
+300 -81.414512397 300 -24424.3537191 1988496.84865 11831.8754003 
+300 -73.8153481771 300 -22144.6044531 1634611.68795 10119.4433284 
+300 -74.2314047611 300 -22269.4214283 1653090.43584 10208.7166435 
+300 -70.7669677649 300 -21230.0903295 1502389.11799 9481.19333171 
+300 -83.586524264 300 -25075.9572792 2096012.11156 12353.1616258 
+300 -81.5359733128 300 -24460.7919938 1994434.48322 11860.6526162 
+300 -80.6586425026 300 -24197.5927508 1951744.98311 11653.7850968 
+300 -78.4397060215 300 -23531.9118065 1845836.24422 11140.883426 
+300 -75.3441577112 300 -22603.2473134 1703022.63036 10450.031969 
+300 -75.6888219087 300 -22706.6465726 1718639.32858 10525.5304786 
+300 -79.3390636477 300 -23801.7190943 1888406.10615 11346.9875534 
+300 -72.4703757326 300 -21741.1127198 1575586.60765 9834.40522023 
+300 -75.3413426824 300 -22602.4028047 1702895.37516 10449.4168057 
+300 -84.3515240453 300 -25305.4572136 2134553.88263 12540.1329828 
+300 -84.3298531632 300 -25298.955949 2133457.24036 12534.8123031 
+300 -84.2967834055 300 -25289.0350216 2131784.30775 12526.6956632 
+300 -70.7800541808 300 -21234.0162542 1502944.82095 9483.87369841 
+300 -74.7350795512 300 -22420.5238653 1675599.63466 10317.4850766 
+300 -81.6583338916 300 -24497.5001675 2000425.04818 11889.6877367 
+300 -83.2254692754 300 -24967.6407826 2077943.62083 12265.5270846 
+300 -80.3728465343 300 -24111.8539603 1937938.33801 11586.895341 
+300 -77.4405941599 300 -23232.178248 1799113.68715 10914.7639795 
+300 -81.2628912492 300 -24378.8673748 1981097.24825 11796.0145569 
+300 -70.4284863343 300 -21128.5459003 1488051.5062 9412.04388351 
+300 -74.5536567555 300 -22366.0970267 1667474.32069 10278.2191778 
+300 -76.3421893563 300 -22902.6568069 1748438.96271 10669.6283934 
+300 -81.6647888084 300 -24499.4366425 2000741.31934 11891.2206806 
+300 -80.9118131078 300 -24273.5439323 1964016.45012 11713.2436523 
+300 -73.356566416 300 -22006.9699248 1614355.7509 10021.6045064 
+300 -80.8425985645 300 -24252.7795693 1960657.7228 11696.9691247 
+300 -73.3431707649 300 -22002.9512295 1613766.20936 10018.757266 
+300 -70.4116162752 300 -21123.4848826 1487338.71195 9408.60643767 
+300 -70.6313607717 300 -21189.4082315 1496636.73734 9453.44848091 
+300 -71.317347857 300 -21395.2043571 1525849.23161 9594.36604912 
+300 -75.7684917772 300 -22730.5475332 1722259.30386 10543.032831 
+300 -74.0870128559 300 -22226.1038568 1646665.64217 10177.6756144 
+300 -72.8117858009 300 -21843.5357403 1590466.84546 9906.24583377 
+300 -75.199028039 300 -22559.7084117 1696468.1454 10418.3480167 
+300 -70.9696319095 300 -21290.8895728 1511006.59601 9522.76074073 
+300 -82.7750954809 300 -24832.5286443 2055514.92956 12156.7614317 
+300 -72.2983548935 300 -21689.5064681 1568115.63609 9798.34051876 
+300 -81.9614420893 300 -24588.4326268 2015303.39681 11961.8061684 
+300 -80.9695834665 300 -24290.8750399 1966822.03402 11726.8382941 
+300 -71.632536062 300 -21489.7608186 1539366.0668 9659.58631355 
+300 -70.4289987353 300 -21128.6996206 1488073.15886 9412.14830377 
+300 -71.303927843 300 -21391.1783529 1525275.03775 9591.59572993 
+300 -80.4170014482 300 -24125.1004345 1940068.23657 11597.213672 
+300 -83.9629557538 300 -25188.8867261 2114933.38168 12444.9447402 
+300 -84.7700110176 300 -25431.0033053 2155786.43038 12643.1570693 
+300 -81.8716057786 300 -24561.4817336 2010887.94983 11940.4027058 
+300 -83.89987923 300 -25169.963769 2111756.92044 12429.535508 
+300 -77.5034503124 300 -23251.0350937 1802035.4431 10928.9013382 
+300 -79.1144705393 300 -23734.3411618 1877729.83461 11295.290644 
+300 -76.5935061519 300 -22978.0518456 1759969.55539 10725.3964808 
+300 -77.2775599579 300 -23183.2679874 1791546.38191 10878.1502099 
+300 -79.0783225789 300 -23723.4967737 1876014.33057 11286.9842335 
+300 -79.6890936139 300 -23906.7280842 1905105.4923 11427.8592594 
+300 -72.096433799 300 -21628.9301397 1559368.72996 9756.12039631 
+300 -75.5732610972 300 -22671.9783292 1713395.33786 10500.1772311 
+300 -80.3124556828 300 -24093.7367048 1935027.16134 11572.7923891 
+300 -84.9723910136 300 -25491.7173041 2166092.17037 12693.1679192 
+300 -80.0301030369 300 -24009.0309111 1921445.21763 11507.0003154 
+300 -83.5869386521 300 -25076.0815956 2096032.89397 12353.26243 
+300 -78.5982444794 300 -23579.4733438 1853305.21057 11177.0392193 
+300 -77.561797534 300 -23268.5392602 1804749.73101 10942.0351736 
+300 -74.5937145225 300 -22378.1143568 1669266.67388 10286.8805105 
+300 -73.113937843 300 -21934.1813529 1603694.37207 9970.11732654 
+300 -79.1240965136 300 -23737.2289541 1878186.79473 11297.5032498 
+300 -80.3054612178 300 -24091.6383653 1934690.13042 11571.159693 
+300 -72.1140710111 300 -21634.2213033 1560131.77134 9759.80332411 
+300 -84.0753825519 300 -25222.6147656 2120600.98537 12472.4395577 
+300 -75.9728502605 300 -22791.8550782 1731562.19301 10588.0145881 
+300 -79.561599884 300 -23868.4799652 1899014.45283 11398.360265 
+300 -82.4219849916 300 -24726.5954975 2038015.08299 12071.9105275 
+300 -76.7091856868 300 -23012.7557061 1765289.75062 10751.1298605 
+300 -79.8867953364 300 -23966.0386009 1914570.02074 11473.6991387 
+300 -74.8563564459 300 -22456.9069338 1681042.23011 10343.7884772 
+300 -84.6916884823 300 -25407.5065447 2151804.62939 12623.8354834 
+300 -79.3540808346 300 -23806.2242504 1889121.04353 11350.4496114 
+300 -71.6521996206 300 -21495.6598862 1540211.31314 9663.66506856 
+300 -71.2871381192 300 -21386.1414358 1524556.81837 9588.13055595 
+300 -79.7349091578 300 -23920.4727473 1907296.72152 11438.4717889 
+300 -84.0419712322 300 -25212.5913697 2118915.87858 12464.2646087 
+300 -71.3883595859 300 -21416.5078758 1528889.36531 9609.03412966 
+300 -80.9353595893 300 -24280.6078768 1965159.72955 11718.7834508 
+300 -80.8180477611 300 -24245.4143283 1959467.05317 11691.1999077 
+300 -70.7455792513 300 -21223.6737754 1501481.09508 9476.81363101 
+300 -78.6203254202 300 -23586.0976261 1854346.67075 11182.0809131 
+300 -77.9988030824 300 -23399.6409247 1825143.98469 11040.7289003 
+300 -83.4414247441 300 -25032.4274232 2088741.409 12317.8963594 
+300 -75.4988973201 300 -22649.669196 1710025.04896 10483.8835149 
+300 -80.4848695454 300 -24145.4608636 1943344.26772 11613.084817 
+300 -79.783560639 300 -23935.0681917 1909624.96447 11449.7481176 
+300 -73.1809295884 300 -21954.2788765 1606634.53663 9984.31571122 
+300 -77.8979535688 300 -23369.3860706 1820427.35106 11017.9021035 
+300 -77.9583487121 300 -23387.5046136 1823251.24018 11031.5685855 
+300 -78.5784622672 300 -23573.5386802 1852372.41968 11172.5236314 
+300 -77.3447995999 300 -23203.43988 1794665.40755 10893.2410407 
+300 -71.5202015326 300 -21456.0604598 1534541.76818 9636.3073294 
+300 -78.6233637853 300 -23587.0091356 1854489.99987 11182.774771 
+300 -81.5063696418 300 -24451.9108925 1992986.48765 11853.634666 
+300 -75.4949964566 300 -22648.498937 1709848.34699 10483.0292615 
+300 -71.2843370541 300 -21385.3011162 1524437.01277 9587.55253595 
+300 -70.3071804501 300 -21092.154135 1482929.88685 9387.34558088 
+300 -83.9577051543 300 -25187.3115463 2114668.87644 12443.6615935 
+300 -83.6801837296 300 -25104.0551189 2100711.94471 12375.9583456 
+300 -78.5610761465 300 -23568.322844 1851552.80559 11168.5559568 
+300 -70.3554961664 300 -21106.6488499 1484968.75225 9397.17753999 
+300 -79.1786919864 300 -23753.6075959 1880779.5794 11310.0577071 
+300 -79.8352073132 300 -23950.562194 1912098.09802 11461.7264353 
+300 -82.1825590804 300 -24654.7677241 2026191.9051 12014.5903324 
+300 -75.3552066026 300 -22606.5619808 1703522.14864 10452.4466937 
+300 -70.0422290275 300 -21012.6687083 1471774.15414 9333.55405301 
+300 -81.2329384899 300 -24369.881547 1979637.08871 11788.9384049 
+300 -77.267367397 300 -23180.2102191 1791073.81934 10875.8638412 
+300 -84.6223462942 300 -25386.7038883 2148282.4477 12606.7446413 
+300 -79.2709664603 300 -23781.2899381 1885165.83706 11331.2969369 
+300 -74.0941765474 300 -22228.2529642 1646984.09947 10179.2141733 
+300 -82.7540659984 300 -24826.2197995 2054470.63178 12151.6976639 
+300 -81.6374862142 300 -24491.2458642 1999403.74661 11884.7375864 
+300 -80.2234602397 300 -24067.0380719 1930741.07185 11552.0294075 
+300 -73.6389697618 300 -22091.6909285 1626809.36027 10081.7545282 
+300 -70.6337509758 300 -21190.1252927 1496738.03307 9453.93703304 
+300 -81.0798231191 300 -24323.9469357 1972181.31511 11752.8079021 
+300 -70.3743680784 300 -21112.3104235 1485765.50473 9401.01976307 
+300 -82.620270471 300 -24786.0811413 2047832.72781 12119.5116105 
+300 -73.396959477 300 -22019.0878431 1616134.09814 10030.1932946 
+300 -78.0003747671 300 -23400.1124301 1825217.53914 11041.084885 
+300 -83.413232464 300 -25023.9697392 2087330.20503 12311.0517817 
+300 -71.043487217 300 -21313.0461651 1514153.12279 9537.93945981 
+300 -81.1087697502 300 -24332.6309251 1973589.75912 11759.6330225 
+300 -76.6296091948 300 -22988.8827585 1761629.10161 10733.4234391 
+300 -75.3138292482 300 -22594.1487745 1701651.86281 10443.4055947 
+300 -74.6215548212 300 -22386.4664464 1670512.93318 10292.9030047 
+300 -83.6349015813 300 -25090.4704744 2098439.02876 12364.9333819 
+300 -76.0591180102 300 -22817.7354031 1735496.82975 10607.0407637 
+300 -75.1633200236 300 -22548.9960071 1694857.40309 10410.5621153 
+300 -83.0260571095 300 -24907.8171329 2067997.84775 12217.2938104 
+300 -73.8386587518 300 -22151.5976255 1635644.25788 10124.4313488 
+300 -71.6223509157 300 -21486.7052747 1538928.34521 9657.47409416 
+300 -73.129134398 300 -21938.7403194 1604361.08934 9973.33693872 
+300 -74.1052771215 300 -22231.5831365 1647477.62918 10181.5985675 
+300 -81.4217999185 300 -24426.5399756 1988852.85059 11833.6007536 
+300 -74.855844232 300 -22456.7532696 1681019.22471 10343.6772918 
+300 -81.8388509601 300 -24551.655288 2009279.25794 11932.6049075 
+300 -80.5875113372 300 -24176.2534012 1948304.09506 11637.1141403 
+300 -73.5006715459 300 -22050.2014638 1620704.61531 10052.26804 
+300 -70.9078078676 300 -21272.3423603 1508375.16498 9510.06726588 
+300 -77.0771947589 300 -23123.1584277 1782268.18557 10833.2619672 
+300 -76.963388052 300 -23089.0164156 1777008.93013 10807.8192403 
+300 -73.8916002434 300 -22167.480073 1637990.57596 10135.765878 
+300 -74.7115157707 300 -22413.4547312 1674543.17663 10312.3795148 
+300 -81.0031010597 300 -24300.9303179 1968450.71439 11734.730314 
+300 -80.0382208303 300 -24011.4662491 1921835.03811 11508.8885343 
+300 -79.4666611559 300 -23839.9983468 1894485.07058 11376.4253942 
+300 -72.0209322413 300 -21606.2796724 1556104.40427 9740.36502955 
+300 -77.7627115507 300 -23328.8134652 1814111.79231 10987.3386249 
+300 -75.3116762916 300 -22593.5028875 1701554.57575 10442.9353066 
+300 -70.2631779789 300 -21078.9533937 1481074.25391 9378.39743471 
+300 -81.9577833633 300 -24587.335009 2015123.47615 11960.9340055 
+300 -80.1408966222 300 -24042.2689867 1926768.99342 11532.7882425 
+300 -71.8274366349 300 -21548.2309905 1547754.19606 9700.06520555 
+300 -78.3589577785 300 -23507.6873336 1842037.87924 11122.4972129 
+300 -71.3133570658 300 -21394.0071197 1525678.4688 9593.54216599 
+300 -81.7397873877 300 -24521.9362163 2004417.85265 11909.0408579 
+300 -71.3434116071 300 -21403.0234821 1526964.71392 9599.74798256 
+300 -74.8222341701 300 -22446.670251 1679510.01786 10336.383333 
+300 -84.833319751 300 -25449.9959253 2159007.64199 12658.7883118 
+300 -70.5988303163 300 -21179.6490949 1495258.45261 9446.80103567 
+300 -82.709847374 300 -24812.9542122 2052275.65579 12141.0544236 
+300 -74.4131245889 300 -22323.9373767 1661193.93333 10247.8712322 
+300 -78.7665298354 300 -23629.9589506 1861249.86669 11215.5003597 
+300 -70.4436472806 300 -21133.0941842 1488692.23266 9415.13380868 
+300 -82.7679612787 300 -24830.3883836 2055160.62427 12155.0434118 
+300 -84.6452654497 300 -25393.5796349 2149446.28892 12612.3919537 
+300 -73.3340917681 300 -22000.2275304 1613366.70464 10016.8278349 
+300 -79.1527210312 300 -23745.8163094 1879545.97399 11304.0844622 
+300 -75.15819708 300 -22547.459124 1694626.37649 10409.4454044 
+300 -76.4459619977 300 -22933.7885993 1753195.53172 10692.6329436 
+300 -73.5557359156 300 -22066.7207747 1623133.88583 10064.0014098 
+300 -82.1094821739 300 -24632.8446522 2022590.11886 11997.129478 
+300 -79.3706652599 300 -23811.199578 1889910.75114 11354.2737663 
+300 -83.0050916599 300 -24901.527498 2066953.57244 12212.2296748 
+300 -82.2181629569 300 -24665.4488871 2027947.896 12023.1032578 
+300 -80.9262251946 300 -24277.8675584 1964716.17728 11716.6341974 
+300 -83.5997527052 300 -25079.9258115 2096675.59571 12356.3798333 
+300 -80.6421697817 300 -24192.6509345 1950947.86413 11649.9230473 
+300 -75.1735139233 300 -22552.054177 1695317.15868 10412.784439 
+300 -70.4145295213 300 -21124.3588564 1487461.79031 9409.19998015 
+300 -70.3523257867 300 -21105.697736 1484834.92308 9396.53217201 
+300 -80.2030888344 300 -24060.9266503 1929760.63757 11547.2800216 
+300 -76.6830015603 300 -23004.9004681 1764084.81849 10745.3015807 
+300 -79.4792335904 300 -23843.7700771 1895084.57163 11379.3286062 
+300 -82.8796059293 300 -24863.8817788 2060708.7237 12181.946574 
+300 -75.8193655779 300 -22745.8096734 1724572.85899 10554.2190531 
+300 -74.0664730929 300 -22219.9419279 1645752.73093 10173.2651064 
+300 -72.9398569629 300 -21881.9570889 1596066.82013 9933.28517344 
+300 -74.8849874606 300 -22465.4962382 1682328.40409 10350.0046145 
+300 -73.910189308 300 -22173.0567924 1638814.82507 10139.7477055 
+300 -84.45690156 300 -25337.070468 2139890.46633 12566.02557 
+300 -72.7606642706 300 -21828.1992812 1588234.27953 9895.46641562 
+300 -75.335239196 300 -22600.5717588 1702619.47942 10448.0831031 
+300 -77.3086972855 300 -23192.6091856 1792990.40279 10885.1367843 
+300 -81.2912804493 300 -24387.3841348 1982481.68313 11802.7238123 
+300 -80.1899167318 300 -24056.9750195 1929126.82363 11544.2097427 
+300 -73.7552541431 300 -22126.5762429 1631951.25411 10106.5918645 
+300 -70.9668747849 300 -21290.0624355 1510889.19502 9522.19441422 
+300 -71.1760072378 300 -21352.8021713 1519807.2019 9565.21595519 
+300 -82.2774887225 300 -24683.2466167 2030875.54514 12037.2965603 
+300 -79.0044812225 300 -23701.3443667 1872512.41597 11270.0284707 
+300 -77.0970759914 300 -23129.1227974 1783187.73793 10837.7106197 
+300 -83.6535934242 300 -25096.0780272 2099377.10783 12369.4835885 
+300 -76.8307899786 300 -23049.2369936 1770891.08662 10778.2245083 
+300 -73.057209313 300 -21917.1627939 1601206.74978 9958.10467906 
+300 -71.991802257 300 -21597.5406771 1554845.87767 9734.2908714 
+300 -77.9545645509 300 -23386.3693653 1823074.2403 11030.7119673 
+300 -82.2703050083 300 -24681.0915025 2030520.92585 12035.5773417 
+300 -70.7829225381 300 -21234.8767614 1503066.63691 9484.46126551 
+300 -76.4170950899 300 -22925.128527 1751871.7266 10686.2304198 
+300 -74.15797136 300 -22247.391408 1649821.41487 10192.9222891 
+300 -71.0121417675 300 -21303.6425302 1512817.28352 9531.49535434 
+300 -81.6440768486 300 -24493.2230546 1999726.58534 11886.3023503 
+300 -84.0793667287 300 -25223.8100186 2120801.97285 12473.4146138 
+300 -70.998405425 300 -21299.5216275 1512232.07187 9528.67231865 
+300 -70.9054981633 300 -21271.649449 1508276.90094 9509.59326846 
+300 -74.7970569224 300 -22439.1170767 1678379.91728 10330.9216595 
+300 -82.5419903349 300 -24762.5971005 2043954.05053 12100.7053252 
+300 -82.3673071649 300 -24710.1921495 2035311.98688 12058.8051307 
+300 -70.1232590557 300 -21036.9777167 1475181.43818 9349.98274798 
+300 -72.4510795097 300 -21735.3238529 1574747.67664 9830.35528686 
+300 -75.328418764 300 -22598.5256292 1702311.20204 10446.5928695 
+300 -82.9603038815 300 -24888.0911644 2064723.60603 12201.415751 
+300 -71.4950046967 300 -21448.501409 1533460.70897 9631.09100965 
+300 -82.8658599234 300 -24859.757977 2060025.22226 12178.6321619 
+300 -79.1455346215 300 -23743.6603864 1879204.69516 11302.4319661 
+300 -80.4470781883 300 -24134.1234565 1941519.71671 11604.2454971 
+300 -77.1001455367 300 -23130.043661 1783329.73253 10838.3975711 
+300 -83.8615227093 300 -25158.4568128 2109826.49734 12420.1710664 
+300 -82.9375189379 300 -24881.2556814 2063589.61427 12195.9166793 
+300 -84.4907257268 300 -25347.217718 2141604.82015 12574.3436578 
+300 -83.5369246036 300 -25061.0773811 2093525.33167 12341.0997238 
+300 -75.6862109501 300 -22705.863285 1718520.7584 10524.9572099 
+300 -84.2205503608 300 -25266.1651082 2127930.33092 12507.9975269 
+300 -73.2527232027 300 -21975.8169608 1609788.43698 9999.5467609 
+300 -75.4484987826 300 -22634.5496348 1707742.79057 10472.850212 
+300 -71.0039514728 300 -21301.1854418 1512468.33743 9529.81205108 
+300 -84.1265253336 300 -25237.9576001 2123181.67941 12484.959457 
+300 -82.098626345 300 -24629.5879035 2022055.33432 11994.536974 
+300 -80.9337008591 300 -24280.1102577 1965079.18043 11718.3931457 
+300 -70.2965107462 300 -21088.9532239 1482479.82693 9385.17530404 
+300 -71.2147613693 300 -21364.4284108 1521462.67107 9573.20264507 
+300 -79.8077101893 300 -23942.3130568 1910781.1817 11455.3480821 
+300 -78.4764966921 300 -23542.9490076 1847568.15992 11149.2670744 
+300 -83.2402987999 300 -24972.08964 2078684.20329 12269.1187754 
+300 -76.1999742898 300 -22859.9922869 1741930.82453 10638.1543155 
+300 -70.0043339472 300 -21001.3001842 1470182.03142 9325.87765249 
+300 -78.0893129281 300 -23426.7938784 1829382.23807 11061.2413434 
+300 -81.4480413645 300 -24434.4124093 1990135.03263 11839.8148529 
+300 -82.7389952613 300 -24821.6985784 2053722.40106 12148.0695408 
+300 -73.9153674366 300 -22174.610231 1639044.46299 10140.8570592 
+300 -83.841671804 300 -25152.5015412 2108827.77927 12415.3263578 
+300 -73.1332639527 300 -21939.9791858 1604542.28891 9974.21196492 
+300 -73.6546286681 300 -22096.3886004 1627501.29727 10085.0967713 
+300 -74.1401884444 300 -22242.0565333 1649030.26277 10189.0999005 
+300 -83.7129073849 300 -25113.8722155 2102355.25885 12383.9294889 
+300 -76.7450610727 300 -23023.5183218 1766941.31971 10759.1186405 
+300 -76.9302863911 300 -23079.0859173 1775480.68926 10800.4262984 
+300 -73.4493082752 300 -22034.7924825 1618440.26583 10041.3315171 
+300 -83.4077536072 300 -25022.3260822 2087056.00854 12309.7218906 
+300 -83.8657295095 300 -25159.7188529 2110038.17585 12421.1979079 
+300 -71.351731968 300 -21405.5195904 1527320.89645 9601.4664925 
+300 -80.8344889206 300 -24250.3466762 1960264.37972 11695.0632317 
+300 -82.0635153029 300 -24619.0545909 2020326.16316 11986.154451 
+300 -82.8023219359 300 -24840.6965808 2056867.3554 12163.3193625 
+300 -79.3112184579 300 -23793.3655374 1887080.81198 11340.5699215 
+300 -76.0752875819 300 -22822.5862746 1736234.8142 10610.6094141 
+300 -80.5802105338 300 -24174.0631601 1947951.0989 11635.4039155 
+300 -76.4258463335 300 -22927.7539 1752272.99634 10688.1711342 
+300 -78.4239206836 300 -23527.1762051 1845093.40062 11137.287598 
+300 -76.0004354994 300 -22800.1306498 1732819.85883 10594.0960279 
+300 -77.0589826338 300 -23117.6947901 1781426.04137 10829.1878371 
+300 -82.2126431315 300 -24663.7929394 2027675.6072 12021.7832125 
+300 -77.7768849471 300 -23333.0654841 1814773.14962 10990.539111 
+300 -83.7715860025 300 -25131.4758008 2105303.58641 12398.231037 
+300 -82.7433248884 300 -24822.9974665 2053937.34408 12149.1117837 
+300 -79.8684859196 300 -23960.5457759 1913692.51292 11469.4489202 
+300 -82.7674113563 300 -24830.2234069 2055133.31479 12154.9109888 
+300 -82.844134206 300 -24853.2402618 2058945.1717 12173.394852 
+300 -81.1419663596 300 -24342.5899079 1975205.61141 11767.4633094 
+300 -73.8173683654 300 -22145.2105096 1634701.16172 10119.8755459 
+300 -70.162134643 300 -21048.6403929 1476817.5413 9357.87169667 
+300 -74.5355256511 300 -22360.6576953 1666663.37522 10274.3004337 
+300 -70.1569855285 300 -21047.0956586 1476600.78553 9356.82653621 
+300 -82.6170798954 300 -24785.1239686 2047674.56713 12118.7447364 
+300 -70.6819928422 300 -21204.5978526 1498783.23364 9463.80122189 
+300 -72.2043662411 300 -21661.3098723 1564041.15129 9778.67300962 
+300 -73.0468257636 300 -21914.0477291 1600751.62624 9955.90693798 
+300 -71.6289810732 300 -21488.694322 1539213.27887 9658.84903632 
+300 -77.6943085136 300 -23308.2925541 1810921.67262 10971.9010492 
+300 -72.0904788594 300 -21627.1436578 1559111.14265 9754.87712182 
+300 -84.6879846717 300 -25406.3954015 2151616.42432 12622.9222366 
+300 -80.0794367634 300 -24023.831029 1923814.8577 11518.4785128 
+300 -70.4645183725 300 -21139.3555117 1489574.50484 9419.3886364 
+300 -79.6417058955 300 -23892.5117687 1902840.39538 11416.8891827 
+300 -71.6434647281 300 -21493.0394184 1539835.81148 9661.85307192 
+300 -80.7678463972 300 -24230.3539192 1957033.50349 11679.4086695 
+300 -83.520463327 300 -25056.1389981 2092700.33831 12337.0982166 
+300 -83.2407393604 300 -24972.2218081 2078706.20678 12269.2254887 
+300 -82.0484567702 300 -24614.5370311 2019584.77751 11982.5604618 
+300 -83.8169462846 300 -25145.0838854 2107584.14534 12409.2936296 
+300 -77.5360060513 300 -23260.8018154 1803549.67032 10936.2283062 
+300 -72.3057041458 300 -21691.7112437 1568434.45561 9799.87949693 
+300 -81.8476575299 300 -24554.297259 2009711.71294 11934.7011332 
+300 -71.9439942494 300 -21583.1982748 1552781.49257 9724.32750596 
+300 -83.413116425 300 -25023.9349275 2087324.39752 12311.0236144 
+300 -72.7608831037 300 -21828.2649311 1588243.83301 9895.51254176 
+300 -74.7931989546 300 -22437.9596864 1678206.78296 10330.0849226 
+300 -80.1286522181 300 -24038.5956654 1926180.27188 11529.9364678 
+300 -71.9881204948 300 -21596.4361484 1554686.84771 9733.52333485 
+300 -81.4262377853 300 -24427.8713356 1989069.65996 11834.6515164 
+300 -83.1821171662 300 -24954.6351499 2075779.38488 12255.0310456 
+300 -84.3400530766 300 -25302.015923 2133973.36589 12537.3164314 
+300 -70.7048351384 300 -21211.4505415 1499752.11358 9468.47430439 
+300 -82.351753712 300 -24705.5261136 2034543.40183 12055.0788563 
+300 -75.1879641101 300 -22556.389233 1695968.98411 10415.9351897 
+300 -76.1899944394 300 -22856.9983318 1741474.5758 10635.9479207 
+300 -77.2717223792 300 -23181.5167138 1791275.72384 10876.8407013 
+300 -72.998756756 300 -21899.6270268 1598645.54637 9945.7370562 
+300 -71.9485418081 300 -21584.5625424 1552977.80049 9725.27493891 
+300 -70.2328892614 300 -21069.8667784 1479797.6202 9372.24143155 
+300 -79.4795333948 300 -23843.8600184 1895098.8686 11379.3978425 
+300 -73.246965402 300 -21974.0896206 1609535.38218 9998.32467038 
+300 -72.202419214 300 -21660.7257642 1563956.8021 9778.26586642 
+300 -84.8205917784 300 -25446.1775335 2158359.83689 12655.6447461 
+300 -81.1183367291 300 -24335.5010187 1974055.36611 11761.8893051 
+300 -79.8630451598 300 -23958.9135479 1913431.79466 11468.1861346 
+300 -79.1281015373 300 -23738.4304612 1878376.93587 11298.4239178 
+300 -83.3292024021 300 -24998.7607206 2083126.79189 12290.6649414 
+300 -74.0571271282 300 -22217.1381385 1645337.42354 10171.2586643 
+300 -76.5118240024 300 -22953.5472007 1756217.76365 10707.2501382 
+300 -75.3043131221 300 -22591.2939366 1701221.87244 10441.3270138 
+300 -74.5462572243 300 -22363.8771673 1667143.33984 10276.61977 
+300 -81.6848048364 300 -24505.4414509 2001722.20235 11895.9749755 
+300 -77.9112442407 300 -23373.3732722 1821048.59374 11020.9086369 
+300 -83.0663040895 300 -24919.8912268 2070003.26253 12227.019032 
+300 -81.5842720284 300 -24475.2816085 1996798.03272 11872.1081234 
+300 -73.8482391658 300 -22154.4717497 1636068.72837 10126.4818481 
+300 -80.9408245194 300 -24282.2473558 1965425.12216 11720.0694269 
+300 -74.4354995578 300 -22330.6498674 1662193.07833 10252.699145 
+300 -84.8675074627 300 -25460.2522388 2160748.14688 12667.2344284 
+300 -78.3420487675 300 -23502.6146302 1841242.98153 11118.6495419 
+300 -82.6032684402 300 -24780.980532 2046989.9871 12115.4254222 
+300 -73.7179048857 300 -22115.3714657 1630298.85022 10098.6099645 
+300 -79.2232466222 300 -23766.9739866 1882896.84161 11320.3098584 
+300 -70.7269333278 300 -21218.0799984 1500689.72939 9472.99664698 
+300 -80.730391506 300 -24219.1174518 1955218.83381 11670.6162328 
+300 -80.5358126165 300 -24160.7437849 1945805.13414 11625.0070761 
+300 -82.55014902 300 -24765.044706 2044358.13097 12102.6645372 
+300 -72.490791474 300 -21747.2374422 1576474.45456 9838.69133674 
+300 -84.3163784436 300 -25294.9135331 2132775.50215 12531.5046724 
+300 -78.7285031982 300 -23618.5509595 1859453.16475 11206.8020498 
+300 -76.790811125 300 -23037.2433375 1769048.60197 10769.3119264 
+300 -76.1719965387 300 -22851.5989616 1740651.91701 10631.969611 
+300 -78.7802863102 300 -23634.085893 1861900.05333 11218.6481193 
+300 -84.2473936633 300 -25274.218099 2129287.00172 12514.5795561 
+300 -83.3130936007 300 -24993.9280802 2082321.46959 12286.759146 
+300 -74.2802395888 300 -22284.0718766 1655266.19801 10219.2291931 
+300 -77.3105579445 300 -23193.1673834 1793076.71091 10885.55437 
+300 -80.9116928592 300 -24273.5078578 1964010.6124 11713.2153656 
+300 -72.3177644263 300 -21695.3293279 1568957.71549 9802.40534424 
+300 -72.5610768115 300 -21768.3230435 1579532.96041 9853.45672598 
+300 -71.560113085 300 -21468.0339255 1536254.93542 9644.57382896 
+300 -76.9799200639 300 -23093.9760192 1777772.42791 10811.5127391 
+300 -74.5043755217 300 -22351.3126565 1665270.59156 10267.5701414 
+300 -71.1301500486 300 -21339.0450146 1517849.47378 9555.77124354 
+300 -77.2524736691 300 -23175.7421007 1790383.4064 10872.5234795 
+300 -81.7441124823 300 -24523.2337447 2004629.97765 11910.0690447 
+300 -76.1119836389 300 -22833.5950917 1737910.21603 10618.7112029 
+300 -77.1670240298 300 -23150.1072089 1786424.87929 10853.3717162 
+300 -77.9666132588 300 -23389.9839776 1823637.83491 11033.4395751 
+300 -78.3462877491 300 -23503.8863247 1841442.24122 11119.614048 
+300 -83.2284144533 300 -24968.524336 2078090.69172 12266.2403502 
+300 -83.5123657498 300 -25053.7097249 2092294.56994 12335.1301066 
+300 -76.3081810129 300 -22892.4543039 1746881.54685 10662.0963766 
+300 -76.3454667304 300 -22903.6400191 1748589.08709 10670.354435 
+300 -81.2564472811 300 -24376.9341843 1980783.06742 11794.4919825 
+300 -83.602069512 300 -25080.6208536 2096791.80801 12356.9435187 
+300 -72.4929459747 300 -21747.8837924 1576568.16483 9839.14372932 
+300 -82.0886511792 300 -24626.5953538 2021563.99573 11992.1550948 
+300 -70.9158869936 300 -21274.7660981 1508718.90843 9511.72538968 
+300 -77.5348195029 300 -23260.4458509 1803494.4706 10935.9612068 
+300 -82.7883704575 300 -24836.5111373 2056174.2849 12159.9586461 
+300 -82.0365667266 300 -24610.970018 2018999.48409 11979.72317 
+300 -81.6284347971 300 -24488.5304391 1998960.41023 11882.5887902 
+300 -78.6830194082 300 -23604.9058225 1857305.26296 11196.4036692 
+300 -82.3329098222 300 -24699.8729467 2033612.41194 12050.565236 
+300 -74.0063258336 300 -22201.8977501 1643080.87902 10160.3569513 
+300 -79.5121409148 300 -23853.6422745 1896654.16586 11386.9297724 
+300 -77.4891696183 300 -23246.7508855 1801371.42244 10925.6883401 
+300 -74.2098327445 300 -22262.9498234 1652129.78279 10204.0751684 
+300 -74.9756642642 300 -22492.6992792 1686405.06956 10369.7078658 
+300 -74.1417151599 300 -22242.514548 1649098.17805 10189.4280266 
+300 -82.9494260406 300 -24884.8278122 2064182.18414 12198.7902254 
+300 -73.751068995 300 -22125.3206985 1631766.05337 10105.6972494 
+300 -70.0699099161 300 -21020.9729748 1472937.68269 9339.1640891 
+300 -71.3009062304 300 -21390.2718691 1525145.76878 9590.97204719 
+300 -74.6726445134 300 -22401.793354 1672801.15159 10303.9609241 
+300 -73.4229535979 300 -22026.8860794 1617279.03451 10035.7230206 
+300 -72.5618310387 300 -21768.5493116 1579565.79711 9853.61525274 
+300 -71.9574826126 300 -21587.2447838 1553363.79118 9727.13783631 
+300 -70.3567403608 300 -21107.0221082 1485021.27426 9397.43081858 
+300 -75.1640048229 300 -22549.2014469 1694888.2863 10410.7113953 
+300 -70.8600835276 300 -21258.0250583 1506345.43126 9500.27652985 
+300 -78.877127547 300 -23663.1382641 1866480.37502 11240.8234185 
+300 -81.4753377978 300 -24442.6013393 1991469.20078 11846.2809704 
+300 -77.1474315988 300 -23144.2294797 1785517.86069 10848.9835665 
+300 -78.2638606838 300 -23479.1582051 1837569.56674 11100.8688786 
+300 -70.6099929184 300 -21182.9978755 1495731.32998 9449.08170301 
+300 -76.9877377609 300 -23096.3213283 1778133.52966 10813.2596151 
+300 -82.8984214372 300 -24869.5264312 2061644.48303 12186.4842544 
+300 -79.7048951207 300 -23911.4685362 1905861.09186 11431.5187459 
+300 -83.9360624763 300 -25180.8187429 2113578.77521 12438.3734075 
+300 -81.936109354 300 -24580.8328062 2014057.80482 11955.768204 
+300 -84.857045629 300 -25457.1136887 2160215.45786 12664.6494471 
+300 -70.2841479572 300 -21085.2443872 1481958.43622 9382.66107143 
+300 -84.3492988001 300 -25304.78964 2134441.26242 12539.5865711 
+300 -84.978048537 300 -25493.4145611 2166380.61995 12694.5677357 
+300 -75.5185921421 300 -22655.5776426 1710917.32774 10488.1971976 
+300 -76.4059466128 300 -22921.7839838 1751360.60334 10683.7584171 
+300 -78.3553611947 300 -23506.6083584 1841868.78839 11121.678733 
+300 -81.7134119928 300 -24514.0235978 2003124.50985 11902.7719593 
+300 -73.4591811096 300 -22037.7543329 1618875.38679 10043.4330756 
+300 -75.9992259847 300 -22799.7677954 1732764.70508 10593.8293305 
+300 -70.5161785634 300 -21154.853569 1491759.43176 9429.92581956 
+300 -81.2354133665 300 -24370.6240099 1979757.71545 11789.522977 
+300 -73.9486408768 300 -22184.592263 1640520.44626 10147.9874247 
+300 -81.2417400971 300 -24372.5220291 1980066.1002 11791.0174503 
+300 -83.5126625508 300 -25053.7987652 2092309.4419 12335.2022404 
+300 -71.6917773266 300 -21507.533198 1541913.28087 9671.87807442 
+300 -74.6259570794 300 -22387.7871238 1670710.041 10293.8555269 
+300 -80.4321190331 300 -24129.6357099 1940797.73165 11600.7477655 
+300 -75.4332972113 300 -22629.9891634 1707054.69845 10469.5237632 
+300 -70.9473232224 300 -21284.1969667 1510056.80173 9518.17908448 
+300 -82.3544109649 300 -24706.3232895 2034674.70161 12055.7154258 
+300 -75.0155506549 300 -22504.6651965 1688199.85202 10378.3826302 
+300 -78.9033124344 300 -23670.9937303 1867719.81393 11246.8242264 
+300 -80.2503585662 300 -24075.1075699 1932036.015 11558.3023858 
+300 -81.9511789625 300 -24585.3536887 2014798.72 11959.3597578 
+300 -74.1063948454 300 -22231.9184536 1647527.32709 10181.8386741 
+300 -76.1218346672 300 -22836.5504001 1738360.11393 10620.8868096 
+300 -83.3179922126 300 -24995.3976638 2082566.3479 12287.9467979 
+300 -78.8951811622 300 -23668.5543487 1867334.88319 11244.9605572 
+300 -75.2755413311 300 -22582.6623993 1699922.13681 10435.0441241 
+300 -83.9011304314 300 -25170.3391294 2111819.9063 12429.8410533 
+300 -84.5568420073 300 -25367.0526022 2144957.85907 12590.6129803 
+300 -84.3309746949 300 -25299.2924085 2133513.9879 12535.0876293 
+300 -78.5077771333 300 -23552.33314 1849041.32112 11156.3982771 
+300 -73.1342610401 300 -21940.278312 1604586.04136 9974.42324902 
+300 -81.4531508907 300 -24435.9452672 1990384.73701 11841.0250534 
+300 -81.0072468245 300 -24302.1740474 1968652.21143 11735.706706 
+300 -81.4764379023 300 -24442.9313707 1991522.97998 11846.5416156 
+300 -71.9397211037 300 -21581.9163311 1552597.04174 9723.43730044 
+300 -76.1182030381 300 -22835.4609114 1738194.25012 10620.0847278 
+300 -80.0958546855 300 -24028.7564057 1924603.78134 11522.2999966 
+300 -71.0364053864 300 -21310.9216159 1513851.26706 9536.48329492 
+300 -80.9316341753 300 -24279.4902526 1964978.82308 11717.9068591 
+300 -79.8199366516 300 -23945.9809955 1911366.68612 11458.1839057 
+300 -76.8393918292 300 -23051.8175487 1771287.641 10780.1427663 
+300 -82.7749326256 300 -24832.4797877 2055506.84135 12156.7222121 
+300 -74.4826465434 300 -22344.793963 1664299.39083 10262.8771051 
+300 -80.2191965598 300 -24065.7589679 1930535.84901 11551.0352708 
+300 -78.4580689049 300 -23537.4206715 1846700.57289 11145.0673476 
+300 -80.7713057171 300 -24231.3917151 1957201.14818 11680.220948 
+300 -78.5277400465 300 -23558.3220139 1849981.78704 11160.9508849 
+300 -76.249196885 300 -22874.7590655 1744182.00768 10649.0410618 
+300 -72.8245346994 300 -21847.3604098 1591023.85626 9908.93527104 
+300 -71.3550877198 300 -21406.5263159 1527464.56305 9602.15965734 
+300 -82.8978471643 300 -24869.3541493 2061615.91934 12186.345743 
+300 -77.8101357754 300 -23343.0407326 1816325.16882 10998.0498258 
+300 -75.7805172035 300 -22734.155161 1722806.03629 10545.6763024 
+300 -81.5883630267 300 -24476.508908 1996998.29441 11873.0787494 
+300 -74.57259186 300 -22371.777558 1668321.43701 10282.3127461 
+300 -81.0188096223 300 -24305.6428867 1969214.25379 11738.4301968 
+300 -82.1423401905 300 -24642.7020572 2024209.21559 12004.9785265 
+300 -71.6653608952 300 -21499.6082686 1540777.18567 9666.39572165 
+300 -74.7550180071 300 -22426.5054021 1676493.81517 10321.8064408 
+300 -76.8674273645 300 -23060.2282094 1772580.41689 10786.3963792 
+300 -74.0221017768 300 -22206.630533 1643781.46543 10163.7415638 
+300 -70.1740613356 300 -21052.2184007 1477319.6653 9360.29286648 
+300 -72.654249051 300 -21796.2747153 1583591.97155 9873.05298987 
+300 -83.159165478 300 -24947.7496434 2074634.0409 12249.4764634 
+300 -70.0043454092 300 -21001.3036228 1470182.51285 9325.8799737 
+300 -71.7154768069 300 -21514.6430421 1542932.88409 9676.7983444 
+300 -82.1242181451 300 -24637.2654435 2023316.16178 12000.6491728 
+300 -83.2434951236 300 -24973.0485371 2078843.84412 12269.8930072 
+300 -72.4692935049 300 -21740.7880515 1575539.55033 9834.17805036 
+300 -78.2594856883 300 -23477.8457065 1837364.13006 11099.8745076 
+300 -79.3606126676 300 -23808.1838003 1889432.05289 11351.9556695 
+300 -78.7557437435 300 -23626.7231231 1860740.15178 11213.0326808 
+300 -79.2761573527 300 -23782.8472058 1885412.73738 11332.4925068 
+300 -71.6292198718 300 -21488.7659616 1539223.54183 9658.89856013 
+300 -78.1698110914 300 -23450.9433274 1833155.80982 11079.5054659 
+300 -78.547138215 300 -23564.1414645 1850895.87653 11165.375846 
+300 -76.5248167083 300 -22957.4450125 1756814.27167 10710.135233 
+300 -80.9625556028 300 -24288.7666808 1966480.62292 11725.1839476 
+300 -74.561798948 300 -22368.5396844 1667838.55871 10279.9793014 
+300 -82.6887545611 300 -24806.6263683 2051229.03926 12135.9795371 
+300 -83.9405365628 300 -25182.1609688 2113804.10353 12439.4664935 
+300 -76.9783254524 300 -23093.4976357 1777698.77684 10811.1564433 
+300 -79.7059044195 300 -23911.7713258 1905909.3598 11431.7525158 
+300 -79.6510342294 300 -23895.3102688 1903286.17614 11419.048124 
+300 -78.8917396727 300 -23667.5219018 1867171.97657 11244.1718353 
+300 -76.4711865973 300 -22941.3559792 1754352.71388 10698.2296699 
+300 -80.4488882106 300 -24134.6664632 1941607.08429 11604.6687599 
+300 -73.9461081609 300 -22183.8324483 1640408.07364 10147.444557 
+300 -78.3006894069 300 -23490.2068221 1839299.38848 11109.2417718 
+300 -80.0329979696 300 -24009.8993909 1921584.2292 11507.6736612 
+300 -72.4077771248 300 -21722.3331374 1572865.85645 9821.2709538 
+300 -81.0100113295 300 -24303.0033989 1968786.58068 11736.3578184 
+300 -83.9648911091 300 -25189.4673327 2115030.88169 12445.4177251 
+300 -81.4260528906 300 -24427.8158672 1989060.6268 11834.6077373 
+300 -73.0962914887 300 -21928.8874466 1602920.34882 9966.37955793 
+300 -70.3735112122 300 -21112.0533636 1485729.3241 9400.8452864 
+300 -71.6248493062 300 -21487.4547919 1539035.71144 9657.99218741 
+300 -80.9561860734 300 -24286.855822 1966171.21906 11723.6846998 
+300 -72.0583535626 300 -21617.5060688 1557721.89544 9748.1718255 
+300 -82.0918778049 300 -24627.5633415 2021722.92046 11992.9255188 
+300 -70.6214055282 300 -21186.4216585 1496214.87563 9451.4138367 
+300 -76.2688509341 300 -22880.6552802 1745081.28684 10653.3900522 
+300 -82.7026726537 300 -24810.8017961 2051919.61922 12139.3280512 
+300 -76.4842793986 300 -22945.2838196 1754953.49854 10701.1353972 
+300 -81.1412350471 300 -24342.3705141 1975170.00749 11767.2907746 
+300 -78.1415965603 300 -23442.4789681 1831832.7339 11073.1016953 
+300 -79.5496031137 300 -23864.8809341 1898441.80666 11395.58701 
+300 -82.8720114302 300 -24861.6034291 2060331.08355 12180.115332 
+300 -71.8883333193 300 -21566.4999958 1550379.74023 9712.73620125 
+300 -70.5104399957 300 -21153.1319987 1491516.64451 9428.75492261 
+300 -71.2093090836 300 -21362.7927251 1521229.71005 9572.07873211 
+300 -72.7414943925 300 -21822.4483178 1587397.50194 9891.42630174 
+300 -70.9067321223 300 -21272.0196367 1508329.39808 9509.84649948 
+300 -77.3495302891 300 -23204.8590867 1794884.95078 10894.3032767 
+300 -74.3558150421 300 -22306.7445126 1658636.16917 10235.512233 
+300 -75.5235750832 300 -22657.072525 1711143.11801 10489.2887769 
+300 -77.1576341381 300 -23147.2902414 1785990.15174 10851.2685026 
+300 -79.34296258 300 -23802.888774 1888591.71329 11347.8863471 
+300 -73.6949692455 300 -22108.4907736 1629284.54763 10093.7104688 
+300 -76.5464224638 300 -22963.9267391 1757806.4376 10714.9340195 
+300 -75.0931508627 300 -22527.9452588 1691694.39195 10395.2733283 
+300 -83.0299749094 300 -24908.9924728 2068193.02004 12218.2402884 
+300 -80.8490183169 300 -24254.7054951 1960969.12884 11698.4780068 
+300 -70.1471391381 300 -21044.1417414 1476186.33878 9354.82815035 
+300 -78.7175050178 300 -23615.2515053 1858933.67887 11204.2871067 
+300 -80.2710240289 300 -24081.3072087 1933031.18959 11563.1232678 
+300 -72.8028308748 300 -21840.8492624 1590075.65502 9904.35704352 
+300 -84.0196510225 300 -25205.8953067 2117790.52738 12458.8052542 
+300 -76.6616729302 300 -22998.5018791 1763103.62894 10740.5555977 
+300 -72.2389907808 300 -21671.6972342 1565541.53671 9785.91525269 
+300 -79.1363864903 300 -23740.9159471 1878770.30002 11300.3286014 
+300 -81.6266552159 300 -24487.9965648 1998873.25252 11882.1663485 
+300 -84.3738774349 300 -25312.1632305 2135685.35802 12545.6227093 
+300 -81.4692372123 300 -24440.7711637 1991170.98358 11844.8356388 
+300 -73.4676587438 300 -22040.2976231 1619249.06439 10045.2378814 
+300 -72.5451884561 300 -21763.5565368 1578841.31044 9850.11763878 
+300 -76.2291055583 300 -22868.7316675 1743262.96027 10644.5965096 
+300 -81.8522780212 300 -24555.6834064 2009938.62518 11935.8010407 
+300 -77.0652880281 300 -23119.5864084 1781717.58565 10830.5982681 
+300 -73.4731399342 300 -22041.9419803 1619490.68754 10046.4048882 
+300 -71.8470503673 300 -21554.1151102 1548599.59395 9704.14509198 
+300 -72.3869147781 300 -21716.0744334 1571959.62933 9816.89628581 
+300 -78.3804063276 300 -23514.1218983 1843046.42883 11127.3790967 
+300 -81.9628116863 300 -24588.8435059 2015370.74986 11962.1326616 
+300 -76.1688207364 300 -22850.6462209 1740506.77571 10631.267723 
+300 -73.3589141863 300 -22007.6742559 1614459.08718 10022.1035795 
+300 -77.6637128087 300 -23299.1138426 1809495.68617 10965.0005848 
+300 -72.8230913607 300 -21846.9274082 1590960.7906 9908.63076778 
+300 -83.4458092009 300 -25033.7427603 2088960.92196 12318.9610408 
+300 -71.7154179966 300 -21514.625399 1542930.35353 9676.78613268 
+300 -72.9526009858 300 -21885.7802957 1596624.59718 9935.9784785 
+300 -72.24023493 300 -21672.070479 1565595.46282 9786.17555214 
+300 -76.634764348 300 -22990.4293044 1761866.132 10734.5699274 
+300 -81.3786036453 300 -24413.5810936 1986743.13938 11823.3761696 
+300 -81.5621258145 300 -24468.6377443 1995714.11021 11866.8546075 
+300 -78.5955749381 300 -23578.6724814 1853179.31996 11176.4297877 
+300 -81.245013149 300 -24373.5039447 1980225.64848 11791.7906438 
+300 -73.209647793 300 -21962.8943379 1607895.75899 9990.40643651 
+300 -77.0243175915 300 -23107.2952775 1779823.65013 10821.4358687 
+300 -82.4342122153 300 -24730.2636646 2038619.80307 12074.8424237 
+300 -73.2486780857 300 -21974.6034257 1609610.65239 9998.6881763 
+300 -77.1873812795 300 -23156.2143838 1787367.54864 10857.9323836 
+300 -81.8773693538 300 -24563.2108061 2011171.08369 11941.7751483 
+300 -82.180079712 300 -24654.0239136 2026069.65044 12013.9976544 
+300 -83.6225166646 300 -25086.7549994 2097817.588 12361.919065 
+300 -81.0123901272 300 -24303.7170382 1968902.20624 11736.9181052 
+300 -79.1972408526 300 -23759.1722558 1881660.8876 11314.3251316 
+300 -84.7584752619 300 -25427.5425786 2155199.73862 12640.3101286 
+300 -75.6486847761 300 -22694.6054328 1716817.05251 10516.7201267 
+300 -81.9595646925 300 -24587.8694077 2015211.07337 11961.3586317 
+300 -79.6300554635 300 -23889.016639 1902283.71993 11414.1931837 
+300 -76.9266597516 300 -23077.9979255 1775313.29416 10799.6165227 
+300 -78.5474231346 300 -23564.2269404 1850909.30433 11165.4408481 
+300 -78.0687044425 300 -23420.6113328 1828416.784 11056.5686367 
+300 -78.4682618808 300 -23540.4785642 1847180.43678 11147.3902198 
+300 -83.616447401 300 -25084.9342203 2097513.08279 12360.4420584 
+300 -76.961645564 300 -23088.4936692 1776928.46638 10807.4299902 
+300 -71.1378506855 300 -21341.3552056 1518178.14004 9557.35682008 
+300 -81.013960456 300 -24304.1881368 1968978.53663 11737.2879797 
+300 -74.1405397217 300 -22242.1619165 1649045.88907 10189.1753974 
+300 -82.4540519616 300 -24736.2155885 2039601.20547 12079.6006376 
+300 -78.9372704643 300 -23681.1811393 1869327.8005 11254.609474 
+300 -76.7892498786 300 -23036.7749636 1768976.66908 10768.9639713 
+300 -72.5279632707 300 -21758.3889812 1578091.63686 9846.49845976 
+300 -71.5322052138 300 -21459.6615641 1535056.91482 9638.79303501 
+300 -81.3288033107 300 -24398.6409932 1984312.27438 11811.5953471 
+300 -73.7392538853 300 -22121.7761656 1631243.26907 10103.1719412 
+300 -74.2452776199 300 -22273.583286 1653708.37466 10211.7022911 
+300 -80.8846329473 300 -24265.3898842 1962697.1541 11706.8510234 
+300 -76.8065851958 300 -23041.9755587 1769775.45883 10772.8279052 
+300 -75.2850851251 300 -22585.5255375 1700353.21269 10437.127925 
+300 -76.9817630857 300 -23094.5289257 1777857.55433 10811.9245485 
+300 -71.9181996013 300 -21575.4598804 1551668.23017 9718.95465382 
+300 -79.3875823805 300 -23816.2747142 1890716.47087 11358.1754865 
+300 -73.2309645199 300 -21969.289356 1608832.24935 9994.92901286 
+300 -82.2717417622 300 -24681.5225287 2030591.84778 12035.9211757 
Index: /branches/sc_branches/trunkTest/psLib/test/math/data/polyMD.pro
===================================================================
--- /branches/sc_branches/trunkTest/psLib/test/math/data/polyMD.pro	(revision 29060)
+++ /branches/sc_branches/trunkTest/psLib/test/math/data/polyMD.pro	(revision 29060)
@@ -0,0 +1,64 @@
+
+list times
+0.0
+10.0
+30.0
+100.0
+300.0
+end
+
+macro mkfake
+
+ delete -q exptime
+
+ create n 0 1000
+ for i 0 $times:n
+   set tmp = $times:$i + zero(n)
+   concat tmp exptime
+ end
+
+ set temp = -85 + 15*rnd(exptime); 
+
+ $D0 = 1000.0
+ $D1 = 5.0
+ $D2 = 0.025
+ $D3 = 0.005
+
+ set f = $D0 + $D1*exptime + $D2*exptime*temp + $D3*exptime*temp^2; 
+
+ set f0 = $D0 + $D2*temp + $D3*temp^2; 
+ set f1 = $D0 + $D1*exptime + $D2*exptime*temp
+ set f2 = $D0 + $D1*exptime + $D3*exptime*temp^2; 
+
+ set ord1 = exptime
+ set ord2 = exptime * temp
+ set ord3 = exptime * temp^2
+
+ write polyMD.dat exptime temp ord1 ord2 ord3 f
+end
+
+macro test.fit2d 
+  fit2d exptime temp f 3
+end
+
+macro test.fit3d 
+  fit3d ord1 ord2 ord3 f 1
+end
+
+macro testfit
+ $N = 100
+ create x 0 $N
+ set y = $N*rnd(x)
+ set z = $N*rnd(x)
+ set f = 10 + 2*x - 3*y +5*z
+ fit3d x y z f 1 -v
+end
+
+macro testfit2
+ $N = 100
+ create x 0 $N
+ set y = $N*rnd(x)
+ set z = $N*rnd(x)
+ set f = 10 + 2*x - 0.1*x^2 + 0.3*x*y - 3*y + 5*z - 20*z^2
+ fit3d x y z f 2 -v
+end
Index: /branches/sc_branches/trunkTest/psLib/test/math/tap_psPolynomialMD_sampleDark.c
===================================================================
--- /branches/sc_branches/trunkTest/psLib/test/math/tap_psPolynomialMD_sampleDark.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psLib/test/math/tap_psPolynomialMD_sampleDark.c	(revision 29060)
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include <pslib.h>
+#include "tap.h"
+#include "pstap.h"
+
+#define TOL 1.0e-4
+
+int main(int argc, char *argv[])
+{
+    plan_tests(13);
+    {
+        psMemId id = psMemGetId();
+
+	FILE *f = fopen ("data/polyMD.dat", "r");
+	ok (f, "open datafile");
+	skip_start (!f, 10, "skipping tests using polyMD.dat");
+
+	psVector *exptime = psVectorAllocEmpty (100, PS_TYPE_F32);
+	psVector *temp    = psVectorAllocEmpty (100, PS_TYPE_F32);
+	psVector *ord1    = psVectorAllocEmpty (100, PS_TYPE_F32);
+	psVector *ord2    = psVectorAllocEmpty (100, PS_TYPE_F32);
+	psVector *ord3    = psVectorAllocEmpty (100, PS_TYPE_F32);
+	psVector *flux    = psVectorAllocEmpty (100, PS_TYPE_F32);
+
+	float Exptime, Temp, Ord1, Ord2, Ord3, Flux;
+
+	// load data: exptime temp ord1 ord2 ord3 f
+	for (int i = 0; true; i++) {
+	    int status = fscanf (f, "%f %f %f %f %f %f", &Exptime, &Temp, &Ord1, &Ord2, &Ord3, &Flux);
+	    if (status != 6) break;
+	    psVectorAppend(exptime, Exptime);
+	    psVectorAppend(temp,    Temp);
+	    psVectorAppend(ord1,    Ord1);
+	    psVectorAppend(ord2,    Ord2);
+	    psVectorAppend(ord3,    Ord3);
+	    psVectorAppend(flux,    Flux);
+	    psAssert (i < exptime->nalloc, "error reading data");
+	}
+	ok (exptime->n == 5000, "read %d elements", exptime->n);
+
+	// fit f to ord1, ord2, ord3 (1st order only)
+        {
+	    psArray *ordinates = psArrayAlloc(exptime->n);
+	    psVector *values = psVectorAlloc(exptime->n, PS_TYPE_F32);
+
+	    for (int i = 0; i < exptime->n; i++) {
+		values->data.F32[i] = flux->data.F32[i];
+		psVector *ord = psVectorAlloc(3, PS_TYPE_F32);
+		ord->data.F32[0] = ord1->data.F32[i];
+		ord->data.F32[1] = ord2->data.F32[i];
+		ord->data.F32[2] = ord3->data.F32[i];
+		ordinates->data[i] = ord;
+	    }
+
+	    int XORDER = 1;
+	    int YORDER = 1;
+	    int ZORDER = 1;
+
+	    psVector *orders = psVectorAlloc(3, PS_TYPE_S32);
+	    orders->data.S32[0] = XORDER;
+	    orders->data.S32[1] = YORDER;
+	    orders->data.S32[2] = ZORDER;
+
+            psPolynomialMD *poly = psPolynomialMDAlloc(orders);
+            bool polyOK = psPolynomialMDFit(poly, values, NULL, NULL, 0, ordinates);
+            ok(polyOK, "Fit polynomial");
+            skip_start(!polyOK, 4, "Skipping coefficient checks since fit failed.");
+            is_double_tol(poly->coeff->data.F64[0], 1000.0, TOL, "Coefficient %d", 0);
+	    is_double_tol(poly->coeff->data.F64[1], 5.0,    TOL, "Coefficient %d", 1);
+	    is_double_tol(poly->coeff->data.F64[2], 0.025,  TOL, "Coefficient %d", 2);
+	    is_double_tol(poly->coeff->data.F64[3], 0.005,  TOL, "Coefficient %d", 3);
+            skip_end();
+            psFree(poly);
+	    psFree(orders);
+	    psFree(values);
+	    psFree(ordinates);
+        }
+
+	// fit f to exptime (1st order) and temp (2nd order)
+	// f = D0 + D1*exptime + D2*exptime*temp + D3*exptime*temp^2
+        {
+            psPolynomial2D *poly = psPolynomial2DAlloc(PS_POLYNOMIAL_ORD, 1, 2);
+	    poly->coeffMask[0][1] = 1; // x^0 y^1
+	    poly->coeffMask[0][2] = 1; // x^0 y^2
+	    
+	    bool polyOK = psVectorFitPolynomial2D(poly, NULL, 0, flux, NULL, exptime, temp);
+            ok(polyOK, "Fit polynomial");
+
+            skip_start(!polyOK, 4, "Skipping coefficient checks since fit failed.");
+            is_double_tol(poly->coeff[0][0], 1000.0, TOL, "Coefficient %d %d", 0, 0);
+	    is_double_tol(poly->coeff[1][0], 5.0,    TOL, "Coefficient %d %d", 1, 0);
+	    is_double_tol(poly->coeff[1][1], 0.025,  TOL, "Coefficient %d %d", 1, 1);
+	    is_double_tol(poly->coeff[1][2], 0.005,  TOL, "Coefficient %d %d", 1, 2);
+            skip_end();
+            psFree(poly);
+        }
+	psFree(exptime);
+	psFree(temp);
+	psFree(ord1);
+	psFree(ord2);
+	psFree(ord3);
+	psFree(flux);
+        ok(!psMemCheckLeaks (id, NULL, NULL, false), "no memory leaks");
+	skip_end();
+    }
+    exit(EXIT_SUCCESS);
+}
Index: /branches/sc_branches/trunkTest/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/camera/pmFPAfileIO.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/camera/pmFPAfileIO.c	(revision 29060)
@@ -24,17 +24,26 @@
 #include "pmFPAfileFitsIO.h"
 #include "pmFPAfileFringeIO.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
-#include "pmResiduals.h"
 #include "pmPSF_IO.h"
+
 #include "pmAstrometryModel.h"
 #include "pmAstrometryRefstars.h"
Index: /branches/sc_branches/trunkTest/psModules/src/camera/pmReadoutFake.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/camera/pmReadoutFake.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/camera/pmReadoutFake.c	(revision 29060)
@@ -10,19 +10,26 @@
 #include "pmFPA.h"
 
-#include "pmMoments.h"
+
+#include "pmTrend2D.h"
 #include "pmResiduals.h"
 #include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
-#include "pmModel.h"
-#include "pmModelClass.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmSourceUtils.h"
-#include "pmModelUtils.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceGroups.h"
-
 #include "pmReadoutFake.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/camera/pmReadoutFake.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/camera/pmReadoutFake.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/camera/pmReadoutFake.h	(revision 29060)
@@ -2,14 +2,14 @@
 #define PM_READOUT_FAKE_H
 
-#include <pslib.h>
-#include <pmHDU.h>
-#include <pmFPA.h>
-
-#include <pmMoments.h>
-#include <pmResiduals.h>
-#include <pmGrowthCurve.h>
-#include <pmTrend2D.h>
-#include <pmPSF.h>
-#include <pmSourceMasks.h>
+// #include <pslib.h>
+// #include <pmHDU.h>
+// #include <pmFPA.h>
+// 
+// #include <pmMoments.h>
+// #include <pmResiduals.h>
+// #include <pmGrowthCurve.h>
+// #include <pmTrend2D.h>
+// #include <pmPSF.h>
+// #include <pmSourceMasks.h>
 
 /// Set threading
Index: /branches/sc_branches/trunkTest/psModules/src/config/pmConfig.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/config/pmConfig.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/config/pmConfig.c	(revision 29060)
@@ -32,4 +32,5 @@
 
 #include "pmConfig.h"
+#include "pmVisualUtils.h"
 
 #ifdef HAVE_NEBCLIENT
@@ -638,4 +639,25 @@
         psArgumentVerbosity(argc, argv);
         // XXX: substitute the string for the default log level for "2".
+    }
+
+    // Set the visualization levels
+    // argument format is: -visual (facil) (level)
+    while ((argNum = psArgumentGet(*argc, argv, "-visual"))) {
+        if ( (*argc < argNum + 3) ) {
+            psError(PS_ERR_IO, true, "-visual switch specified without facility and level.");
+            return NULL;
+        }
+        psArgumentRemove(argNum, argc, argv);
+        pmVisualSetLevel(argv[argNum], atoi(argv[argNum+1]));
+        psArgumentRemove(argNum, argc, argv);
+        psArgumentRemove(argNum, argc, argv);
+    }
+    if ((argNum = psArgumentGet(*argc, argv, "-visual-all"))) {
+        pmVisualSetLevel(".", 10);
+        psArgumentRemove(argNum, argc, argv);
+    }
+    if ((argNum = psArgumentGet(*argc, argv, "-visual-levels"))) {
+        pmVisualPrintLevels(stdout);
+        psArgumentRemove(argNum, argc, argv);
     }
 
Index: /branches/sc_branches/trunkTest/psModules/src/detrend/pmMaskStats.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/detrend/pmMaskStats.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/detrend/pmMaskStats.c	(revision 29060)
@@ -7,5 +7,4 @@
 
 #include <pslib.h>
-#include <psmodules.h>
 
 #include "pmHDU.h"
@@ -16,4 +15,5 @@
 #include "pmFPAAstrometry.h"
 
+#include "pmMaskStats.h"
 
 #define ESCAPE { \
Index: /branches/sc_branches/trunkTest/psModules/src/detrend/pmShutterCorrection.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/detrend/pmShutterCorrection.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/detrend/pmShutterCorrection.c	(revision 29060)
@@ -302,5 +302,5 @@
     PS_ASSERT_PTR_NON_NULL(guess, NULL);
 
-    psMinimization *minInfo = psMinimizationAlloc(15, 0.1); // Minimization information
+    psMinimization *minInfo = psMinimizationAlloc(15, 0.1, 1.0); // Minimization information
 
     psVector *params = psVectorAlloc (3, PS_TYPE_F32); // Fitting parameters
Index: /branches/sc_branches/trunkTest/psModules/src/extras/Makefile.am
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/extras/Makefile.am	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/extras/Makefile.am	(revision 29060)
@@ -9,4 +9,5 @@
 	pmKapaPlots.c \
 	pmVisual.c \
+	pmVisualUtils.c \
 	ippStages.c
 
@@ -17,4 +18,5 @@
 	pmKapaPlots.h \
 	pmVisual.h \
+	pmVisualUtils.h \
 	ippDiffMode.h \
 	ippStages.h
Index: /branches/sc_branches/trunkTest/psModules/src/extras/pmVisual.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/extras/pmVisual.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/extras/pmVisual.c	(revision 29060)
@@ -21,16 +21,24 @@
 #include "pmAstrometryObjects.h"
 #include "pmSubtractionStamps.h"
+
 #include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
 #include "pmPSFtry.h"
-#include "pmSource.h"
+
 #include "pmFPAExtent.h"
-
-# if (HAVE_KAPA)
-# include <kapa.h>
-# include "pmVisual.h"
-# include "pmKapaPlots.h"
-# define KAPAX 700
-# define KAPAY 700
 
 #include "pmAstrometryVisual.h"
@@ -38,4 +46,12 @@
 #include "pmStackVisual.h"
 #include "pmSourceVisual.h"
+
+# if (HAVE_KAPA)
+# include <kapa.h>
+#include "pmVisual.h"
+#include "pmKapaPlots.h"
+
+# define KAPAX 700
+# define KAPAY 700
 
 //#define TESTING
@@ -102,5 +118,5 @@
 
     /* Wait up to 1.0 second for a response, then continue */
-    timeout.tv_sec = 2;
+    timeout.tv_sec = 10;
     timeout.tv_usec = 0;
 
Index: /branches/sc_branches/trunkTest/psModules/src/extras/pmVisualUtils.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/extras/pmVisualUtils.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/extras/pmVisualUtils.c	(revision 29060)
@@ -0,0 +1,505 @@
+/** These utility functions manage the visual level information (equivalent to pmVisual levels)
+ *  @author Eugene Magnier, IfA
+ *  @date June 18, 2010
+ */
+
+/* Include Files  */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <strings.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <pslib.h>
+
+#include <pmVisualUtils.h>
+
+#define PM_UNKNOWN_VISUAL_LEVEL -9999   // we don't know this name's level
+#define PM_DEFAULT_VISUAL_LEVEL -1
+#define PM_THE_OTHER_DEFAULT_VISUAL_LEVEL 0 // ???
+#define MAX_COMPONENT_LENGTH 1024
+
+/** Basic structure for the component tree.  A component is a string of the
+    form aaa.bbb.ccc, and may itself contain further subcomponents.  The
+    Component structure doesn't in fact contain it's full name, but only the
+    last part. */
+
+static pmVisualComponent* cRoot = NULL; // The root of the visual component tree
+
+/** static function prototypes **/
+static void componentFree(pmVisualComponent* comp);
+static pmVisualComponent* componentAlloc(const char *name, int level);
+static int getLevel(const char *facil);
+static void initVisualLevels(void);
+static void componentFree(pmVisualComponent* comp);
+static pmVisualComponent* componentAlloc(const char *name, int level);
+static void doGetVisualLevels(psMetadata *out, const pmVisualComponent* comp, psString parent, int defLevel);
+static void doPrintVisualLevels(const pmVisualComponent* comp, FILE *output, psS32 depth, psS32 defLevel);
+static psS32 doGetVisualLevel(const char *aname);
+static bool componentAdd(const char *addNodeName, psS32 level);
+
+/*****************************************************************************
+Set all visual levels at or below the specified node to zero.
+ *****************************************************************************/
+void pmVisualReset(pmVisualComponent* currentNode)
+{
+    psAssert(currentNode, "impossible");
+
+    psS32 i = 0;
+
+    if (NULL == currentNode) {
+        return;
+    }
+
+    currentNode->level = 0;
+    for (i = 0; i < currentNode->n; i++) {
+        if (!currentNode->subcomp[i]) {
+            psLogMsg("pmVisualReset", PS_LOG_WARN, _("Sub-component %d of node %s in visual tree is NULL."), i, currentNode->name);
+        } else {
+            pmVisualReset(currentNode->subcomp[i]);
+        }
+    }
+    return;
+}
+
+/*****************************************************************************
+Free all visual levels
+ *****************************************************************************/
+void pmVisualCleanup()
+{
+    psFree(cRoot);
+    cRoot = NULL;
+}
+
+// psSetVisualLevel(): add the component named "comp" to the component tree,
+int pmVisualSetLevel(const char *comp,   // component of interest
+                    int level)  // desired visual level
+{
+    PS_ASSERT_STRING_NON_EMPTY(comp, 0);
+
+    char *compName = NULL;
+    int prevLevel = -1;
+
+    // If the root component tree does not exist, then initialize it.
+    if (cRoot == NULL) {
+        initVisualLevels();
+    }
+
+    // If the component name has no leading dot, then supply it.
+    if (comp[0] != '.') {
+        compName = (char *) psAlloc(10 + strlen(comp));
+        strcpy(compName, ".");
+        compName = strcat(compName, comp);
+    } else {
+        compName = (char *) comp;
+    }
+    prevLevel = getLevel(compName);
+    // Add the new component to the component tree.
+    if ( !componentAdd(compName, level) ) {
+        psError(PS_ERR_UNKNOWN, false,
+                _("Failed to set visual level (%d) to '%s'."),
+                level,
+                compName);
+
+        if (comp[0] != '.') {
+            psFree(compName);
+        }
+        //        return false;
+        return -1;
+    }
+
+    if (comp[0] != '.') {
+        psFree(compName);
+    }
+
+    //    return true;
+    return prevLevel;
+}
+
+// Append the function name to the facility
+// NB: declares TARGET!
+#define FACILITY(TARGET, FUNC, FACIL) \
+    size_t _facilLength = strlen(FACIL); /* Length of facility name */ \
+    size_t _funcLength = strlen(FUNC);   /* Length of function name */ \
+    char TARGET[_facilLength + _funcLength + 2]; /* facility + the function name */ \
+    strcpy(&TARGET[0], FACIL); \
+    TARGET[_facilLength] = '.'; \
+    strcpy(&TARGET[_facilLength + 1], FUNC);
+
+int p_pmVisualGetLevel(const char *func, const char *name)
+{
+    PS_ASSERT_STRING_NON_EMPTY(name, 0);
+    PS_ASSERT_STRING_NON_EMPTY(func, 0);
+
+    FACILITY(facility, func, name);
+    return getLevel(facility);
+}
+
+/** the main tool in the pmVisual system : check that the specified level matches the desired level **/
+bool p_pmVisualTestLevel(const char *func, const char *name, int level)
+{
+    PS_ASSERT_STRING_NON_EMPTY(name, false);
+    PS_ASSERT_STRING_NON_EMPTY(func, false);
+
+   // return true if level is set to be shown
+    FACILITY(facility, func, name);
+    bool valid = level <= getLevel(facility);
+
+    if (valid) {
+	psLogMsg ("psModules.visual", PS_LOG_DETAIL, "visualization %s (%d)\n", facility, level);
+    }
+
+    return (valid);
+}
+
+// psPrintVisualLevels(): Simply print all the visual levels in the visual level
+void pmVisualPrintLevels(FILE *output)
+{
+    if (cRoot == NULL) {
+        return;
+    }
+
+    doPrintVisualLevels(cRoot, output, 0, PM_THE_OTHER_DEFAULT_VISUAL_LEVEL);
+}
+
+// generate a metadata of the visual levels (is this really needed?)
+psMetadata *pmVisualLevels(void)
+{
+    if (cRoot == NULL) {
+        return psMetadataAlloc();
+    }
+
+    psMetadata *out = psMetadataAlloc();// Output metadata with the levels
+    doGetVisualLevels(out, cRoot, NULL, PM_THE_OTHER_DEFAULT_VISUAL_LEVEL);
+
+    return out;
+}
+
+/****************************** static functions ******************************/
+
+/*****************************************************************************
+componentAdd(): Adds the component named "addNodeName" to the root tree.
+ *****************************************************************************/
+static bool componentAdd(const char *addNodeName, psS32 level)
+{
+    psAssert(addNodeName, "impossible");
+
+    psS32 i = 0;                        // Loop index variable.
+    char name[MAX_COMPONENT_LENGTH]; // buffer for writeable copy.
+    char *firstComponent = NULL;        // first component of name
+    pmVisualComponent* currentNode = cRoot;
+    psS32 nodeExists = 0;
+
+    // XXX: Verify that this is the correct behavior.
+    if (strcmp("", addNodeName) == 0) {
+        psError(PS_ERR_BAD_PARAMETER_NULL,true,
+                _("Failed to add null component to visual tree."));
+        return false;
+    }
+
+    // Is this the root node? If so, simply set level and return.
+    if (strcmp(".", addNodeName) == 0) {
+        cRoot->level = level;
+        return true;
+    }
+
+    if (addNodeName[0] != '.') {
+        psError(PS_ERR_BAD_PARAMETER_VALUE,true,
+                _("Failed to add '%s' to the root component tree; component must start with '.'."),
+                addNodeName);
+        return false;
+    }
+
+    strncpy(name, addNodeName, MAX_COMPONENT_LENGTH);
+    char *pname = name+1;               // Take off the period
+    // Iterate through the components of addNodeName.  Strip off the first
+    // component of the name, find that in the root tree, or add it if it
+    // does not exist, then move to the next component in the name.
+
+    while (pname != NULL) {
+        firstComponent = pname;
+        pname = strchr(firstComponent, '.');
+        if (pname != NULL) {
+            *pname = '\0';
+            pname++;
+        }
+        nodeExists = 0;
+        for (i = 0; i < currentNode->n; i++) {
+            if (strcmp(currentNode->subcomp[i]->name, firstComponent) == 0) {
+                currentNode = currentNode->subcomp[i];
+                nodeExists = 1;
+                if (pname == NULL) {
+                    currentNode->level = level;
+                }
+            }
+        }
+
+        if (nodeExists == 0) {
+            currentNode->subcomp = psRealloc(currentNode->subcomp,
+                                             (currentNode->n + 1) * sizeof(pmVisualComponent* ));
+            psMemSetPersistent(currentNode->subcomp,true);
+
+            currentNode->n = (currentNode->n) + 1;
+
+            if (pname == NULL) {
+                // This is the final component to add.
+                currentNode->subcomp[(currentNode->n) - 1] =
+                    componentAlloc(firstComponent, level);
+            } else {
+                // We are adding an intermediate component.  The visual level is not defined.
+                // An undefined visual level inherits the visual level of it's parent.  However,
+                // we do not set that specifically here since that would result in a static,
+                // one-time, type of behavior.
+
+                currentNode->subcomp[(currentNode->n) - 1] =
+                    componentAlloc(firstComponent, PM_DEFAULT_VISUAL_LEVEL);
+            }
+            currentNode = currentNode->subcomp[(currentNode->n) - 1];
+        }
+    }
+
+    return true;
+}
+
+/*****************************************************************************
+    doGetVisualLevel()
+ This function recursively searches the root component tree for the
+ component named "name", which is supplied by a parameter.  If it
+ finds that component, it returns the level of that component.
+ Otherwise, it returns ???.
+
+    NOTE: We modified this so that the user may omit the leading "," in a
+    component name.  Since the code was already implemented assuming the "."
+    was required, rather than change all that code, in this function, I
+    simply add a leading "." to the component name if there is none.
+
+    Inputs:
+ name:
+    Outputs:
+ none
+    Returns:
+ The visual level of the "name" component.
+ *****************************************************************************/
+static psS32 doGetVisualLevel(const char *aname)
+{
+    psAssert(aname, "impossible");
+    char name[strlen(aname) + 1];       // need a writeable copy: for strsep()
+    char *pname = name;
+    char *firstComponent = NULL;        // first component of name
+    pmVisualComponent* currentNode = cRoot;
+    psS32 i = 0;
+    psS32 defaultLevel = 0;
+
+    if (NULL == currentNode) {
+        return (PM_UNKNOWN_VISUAL_LEVEL);
+    }
+
+    if (strcmp(".", aname) == 0) {
+        return (cRoot->level);
+    }
+
+    if (aname[0] != '.') {
+        return (PM_UNKNOWN_VISUAL_LEVEL);
+    }
+
+    defaultLevel = cRoot->level;
+    strcpy(name, aname);
+    pname = name+1;
+    while (pname != NULL) {
+        firstComponent = pname;
+        pname = strchr(firstComponent, '.');
+        if (pname != NULL) {
+            *pname = '\0';
+            pname++;
+        }
+        for (i = 0; i < currentNode->n; i++) {
+            if (NULL == currentNode->subcomp[i]) {
+                psLogMsg("p_pmVisualReset", PS_LOG_WARN,
+                         _("Sub-component %d of node %s in visual tree is NULL."),
+                         i, currentNode->name);
+            }
+
+            if (strcmp(currentNode->subcomp[i]->name, firstComponent) == 0) {
+                currentNode = currentNode->subcomp[i];
+                // For level inheritance purpose, we save the level of this
+                // component if it is not DEFAULT.
+                if (currentNode->level != PM_DEFAULT_VISUAL_LEVEL) {
+                    defaultLevel = currentNode->level;
+                }
+                // Determine if this is the last component:
+                if (pname == NULL) {
+                    if (currentNode->level != PM_DEFAULT_VISUAL_LEVEL) {
+                        return (currentNode->level);
+                    } else {
+                        return(defaultLevel);
+                    }
+                }
+            }
+        }
+    }
+    return(defaultLevel);
+}
+
+/*****************************************************************************
+    getLevel()
+ Return a visual level of "name" in the root component tree.  If the
+ exact string of components in "name" does not exist in the root
+ tree, we return the deepest level of the match.
+ *****************************************************************************/
+static int getLevel(const char *name)
+{
+    if (cRoot == NULL) {
+        return (PM_UNKNOWN_VISUAL_LEVEL);
+    }
+
+    psS32 visualLevel;
+
+    // If the component name has no leading dot, then supply it.
+    if (name[0] != '.') {
+        char compName[strlen(name) + 2];
+        compName[0] = '.';
+        strcpy(&compName[1], name);
+
+        visualLevel = doGetVisualLevel(compName);
+    } else {
+        // Search the component root tree, determine the visual level.
+        visualLevel = doGetVisualLevel(name);
+    }
+
+    // XXX: The default visual level is currently set at -1, which is not a
+    // valid visual level.  This is convenient in determining whether or not
+    // a component should inherit the visual level from parent nodes.  However,
+    // it's not clear that -1 should ever be returned by this function.
+    // The SDR is unclear on this point and we should probably request IfA
+    // comment.
+    if (visualLevel == PM_DEFAULT_VISUAL_LEVEL) {
+        visualLevel = PM_THE_OTHER_DEFAULT_VISUAL_LEVEL;
+    }
+
+    return(visualLevel);
+}
+
+/*****************************************************************************
+    doPrintVisualLevels()
+ This function recursively searches the component tree supplied by the
+ parameter "comp" and prints the name and level of each component.
+    Inputs:
+ comp: a node in the component tree.
+ level: the level of that node
+    Outputs:
+ none
+    Returns:
+ null
+ *****************************************************************************/
+static void doPrintVisualLevels(const pmVisualComponent* comp,
+				FILE *output,
+				psS32 depth,
+				psS32 defLevel)
+{
+    psAssert(comp, "impossible");
+
+    char line[1024];
+    psS32 i = 0;
+
+    if (comp->name[0] == '\0') {
+        return;
+    } else {
+        if (comp->level == PM_DEFAULT_VISUAL_LEVEL) {
+	    sprintf(line,"%*s%-*s %d\n", depth, "", 20 - depth, comp->name, defLevel);
+	    fwrite (line, 1, strlen(line), output);
+        } else {
+	    sprintf(line, "%*s%-*s %d\n", depth, "", 20 - depth, comp->name, comp->level);
+	    fwrite (line, 1, strlen(line), output);
+        }
+    }
+
+    for (i = 0; i < comp->n; i++) {
+        if (comp->level == PM_DEFAULT_VISUAL_LEVEL) {
+            doPrintVisualLevels(comp->subcomp[i], output, depth + 1, defLevel);
+        } else {
+            doPrintVisualLevels(comp->subcomp[i], output, depth + 1, comp->level);
+        }
+    }
+}
+
+static void doGetVisualLevels(psMetadata *out, // Output metadata with the visual levels
+                             const pmVisualComponent* comp, // Component to add
+                             psString parent, // Name of parent level
+                             int defLevel // Default level
+                            )
+{
+    if (comp->name[0] == '\0') {
+        return;
+    }
+
+    psString name = psStringCopy(parent); // Name of this level
+    if (comp->name[0] == '.') {
+        psStringAppend(&name, "%s", comp->name + 1);
+    } else if (!parent) {
+        psStringAppend(&name, "%s", comp->name);
+    } else {
+        psStringAppend(&name, ".%s", comp->name);
+    }
+
+    int level = (comp->level == PM_DEFAULT_VISUAL_LEVEL) ? defLevel : comp->level; // Level for component
+    if (name) {
+        psMetadataAddS32(out, PS_LIST_TAIL, name, 0, NULL, level);
+    }
+    for (int i = 0; i < comp->n; i++) {
+        doGetVisualLevels(out, comp->subcomp[i], name, level);
+    }
+
+    psFree(name);
+
+    return;
+}
+
+/*****************************************************************************
+componentAlloc(): allocate memory for a new node, and initialize members.
+ *****************************************************************************/
+static pmVisualComponent* componentAlloc(const char *name, int level)
+{
+    psAssert(name, "impossible");
+
+    pmVisualComponent* comp = psAlloc(sizeof(pmVisualComponent));
+    psMemSetDeallocator(comp, (psFreeFunc) componentFree);
+
+    comp->name = psStringCopy(name);
+    comp->level = level;
+    comp->n = 0;
+    comp->specified = false;
+    comp->subcomp = NULL;
+    return comp;
+}
+
+/*****************************************************************************
+componentFree(): free the current node in the root tree, and all children
+nodes as well.
+ *****************************************************************************/
+static void componentFree(pmVisualComponent* comp)
+{
+    if (comp == NULL) {
+        return;
+    }
+
+    if (comp->subcomp != NULL) {
+        for (psS32 i = 0; i < comp->n; i++) {
+            psFree(comp->subcomp[i]);
+        }
+        psFree(comp->subcomp);
+    }
+    psFree(comp->name);
+}
+
+/*****************************************************************************
+initVisualLevels(): simply initialize the component root tree.
+*****************************************************************************/
+static void initVisualLevels(void)
+{
+    if (cRoot == NULL) {
+        cRoot = componentAlloc(".", PM_DEFAULT_VISUAL_LEVEL);
+    }
+}
Index: /branches/sc_branches/trunkTest/psModules/src/extras/pmVisualUtils.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/extras/pmVisualUtils.h	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/extras/pmVisualUtils.h	(revision 29060)
@@ -0,0 +1,33 @@
+/* @file pmVisualUtils.h
+ * @brief functions to create visual diagnostics with the help of 'kapa'
+ * @author Chris Beaumont, IfA
+ *
+ * Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#ifndef PM_VISUAL_UTILS_H
+#define PM_VISUAL_UTILS_H
+
+typedef struct pmVisualComponent
+{
+    const char *name;			///< last part of name of component
+    psS32 level;			///< visual level for this component
+    bool specified;			///< whether the component is specified
+    psS32 n;				///< number of subcomponents
+    struct pmVisualComponent* *subcomp;	///< next level of subcomponents
+}
+pmVisualComponent;
+
+psMetadata *pmVisualLevels(void);
+void pmVisualPrintLevels(FILE *output);
+int pmVisualSetLevel(const char *comp, int level);
+void pmVisualCleanup();
+void pmVisualReset(pmVisualComponent* currentNode);
+
+int p_pmVisualGetLevel(const char *func, const char *name);
+# define pmVisualGetLevel(facil) p_pmVisualGetLevel(__func__, facil)
+
+bool p_pmVisualTestLevel(const char *func, const char *name, int level);
+# define pmVisualTestLevel(facil, level) p_pmVisualTestLevel(__func__, facil, level)
+
+#endif // PM_VISUAL_UTILS_H
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmPSFEnvelope.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmPSFEnvelope.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmPSFEnvelope.c	(revision 29060)
@@ -10,23 +10,26 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
-#include "pmReadoutFake.h"
-
-#include "pmMoments.h"
+
+#include "pmTrend2D.h"
 #include "pmResiduals.h"
 #include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
-#include "pmModel.h"
-#include "pmModelClass.h"
-#include "pmModelUtils.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmSourceUtils.h"
 #include "pmSourceFitModel.h"
+#include "pmPSF.h"
 #include "pmPSFtry.h"
 
-
+#include "pmReadoutFake.h"
 #include "pmPSFEnvelope.h"
 #include "pmStackVisual.h"
@@ -410,5 +413,13 @@
     options->chiFluxTrend = false;      // All sources have similar flux, so fitting a trend often fails
 
-    pmSourceFitModelInit(SOURCE_FIT_ITERATIONS, 0.01, VARIANCE_VAL, true);
+    // options which modify the behavior of the model fitting
+    options->fitOptions                = pmSourceFitOptionsAlloc();
+    options->fitOptions->nIter         = SOURCE_FIT_ITERATIONS;
+    options->fitOptions->minTol        = 0.01;
+    options->fitOptions->maxTol        = 1.00;
+    options->fitOptions->poissonErrors = true;
+    options->fitOptions->weight        = VARIANCE_VAL;
+    options->fitOptions->mode          = PM_SOURCE_FIT_PSF;
+
     pmModelClassSetLimits(PM_MODEL_LIMITS_STRICT); // Important for getting a good stack target PSF
 
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtraction.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtraction.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtraction.c	(revision 29060)
@@ -33,4 +33,9 @@
 #define USE_KERNEL_ERR                  // Use kernel error image?
 #define NUM_COVAR_POS 5                 // Number of positions for covariance calculation
+
+// XXX we need to pass these fwhm values elsewhere.  These should go on one of the structure, but 
+// things are too confusing to do that now.  just save them here.
+static float FWHM1 = NAN;
+static float FWHM2 = NAN;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -752,5 +757,5 @@
 
 
-bool pmSubtractionConvolveStamp(pmSubtractionStamp *stamp, const pmSubtractionKernels *kernels, int footprint)
+bool pmSubtractionConvolveStamp (pmSubtractionStamp *stamp, pmSubtractionKernels *kernels, int footprint)
 {
     PS_ASSERT_PTR_NON_NULL(stamp, false);
@@ -774,4 +779,7 @@
         stamp->convolutions1 = convolveStamp(stamp->convolutions1, stamp->image1, kernels, footprint);
         stamp->convolutions2 = convolveStamp(stamp->convolutions2, stamp->image2, kernels, footprint);
+	if (!pmSubtractionKernelPenaltiesStamp(stamp, kernels)) {
+	    psAbort("failure in penalties");
+	}
         break;
       default:
@@ -1215,4 +1223,5 @@
     bool threaded = pmSubtractionThreaded(); // Running threaded?
 
+    // XXX This is no longer used 
     psImage *convMask = NULL;           // Convolved mask image (common to inputs 1 and 2)
     if (subMask) {
@@ -1413,2 +1422,16 @@
     return true;
 }
+
+bool pmSubtractionGetFWHMs(float *fwhm1, float *fwhm2) {
+
+  *fwhm1 = FWHM1;
+  *fwhm2 = FWHM2;
+  return true;
+}
+
+bool pmSubtractionSetFWHMs(float fwhm1, float fwhm2) {
+
+  FWHM1 = fwhm1;
+  FWHM2 = fwhm2;
+  return true;
+}
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtraction.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtraction.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtraction.h	(revision 29060)
@@ -59,5 +59,5 @@
 /// Convolve the reference stamp with the kernel components
 bool pmSubtractionConvolveStamp(pmSubtractionStamp *stamp, ///< Stamp to convolve
-                                const pmSubtractionKernels *kernels, ///< Kernel parameters
+                                pmSubtractionKernels *kernels, ///< Kernel parameters
                                 int footprint ///< Half-size of region over which to calculate equation
     );
@@ -157,4 +157,7 @@
     );
 
+bool pmSubtractionGetFWHMs(float *fwhm1, float *fwhm2);
+bool pmSubtractionSetFWHMs(float fwhm1, float fwhm2);
+
 /// @}
 #endif
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionEquation.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionEquation.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionEquation.c	(revision 29060)
@@ -38,5 +38,6 @@
                                   const psImage *polyValues, // Spatial polynomial values
                                   int footprint, // (Half-)Size of stamp
-                                  int normWindow, // Window (half-)size for normalisation measurement
+                                  int normWindow1, // Window (half-)size for normalisation measurement
+                                  int normWindow2, // Window (half-)size for normalisation measurement
                                   const pmSubtractionEquationCalculationMode mode
                                   )
@@ -184,6 +185,8 @@
             double one = 1.0;
 
-            if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow)) {
+            if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow1)) {
                 normI1 += ref;
+            }
+            if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow2)) {
                 normI2 += in;
             }
@@ -214,4 +217,6 @@
 
     *norm = normI2 / normI1;
+
+    fprintf (stderr, "normValue: %f %f %f\n", normI1, normI2, *norm);
 
     if (mode & PM_SUBTRACTION_EQUATION_NORM) {
@@ -262,5 +267,6 @@
                                       const psImage *polyValues, // Spatial polynomial values
                                       int footprint, // (Half-)Size of stamp
-                                      int normWindow, // Window (half-)size for normalisation measurement
+                                      int normWindow1, // Window (half-)size for normalisation measurement
+                                      int normWindow2, // Window (half-)size for normalisation measurement
                                       const pmSubtractionEquationCalculationMode mode
                                       )
@@ -492,6 +498,8 @@
             double i1i2 = i1 * i2;
 
-            if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow)) {
+            if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow1)) {
                 normI1 += i1;
+            }
+            if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(normWindow2)) {
                 normI2 += i2;
             }
@@ -522,4 +530,5 @@
 
     *norm = normI2 / normI1;
+    fprintf (stderr, "normValue: %f %f %f\n", normI1, normI2, *norm);
 
     if (mode & PM_SUBTRACTION_EQUATION_NORM) {
@@ -559,8 +568,8 @@
 // Add in penalty term to least-squares vector
 bool calculatePenalty(psImage *matrix,                     // Matrix to which to add in penalty term
-                             psVector *vector,                    // Vector to which to add in penalty term
-                             const pmSubtractionKernels *kernels, // Kernel parameters
-                             float norm                           // Normalisation
-    )
+		      psVector *vector,                    // Vector to which to add in penalty term
+		      const pmSubtractionKernels *kernels, // Kernel parameters
+		      float norm                           // Normalisation
+  )
 {
     if (kernels->penalty == 0.0) {
@@ -568,5 +577,7 @@
     }
 
-    psVector *penalties = kernels->penalties; // Penalties for each kernel component
+    psVector *penalties1 = kernels->penalties1; // Penalties for each kernel component (input)
+    psVector *penalties2 = kernels->penalties2; // Penalties for each kernel component (ref)
+
     int spatialOrder = kernels->spatialOrder; // Order of spatial variations
     int numKernels = kernels->num; // Number of kernel components
@@ -588,8 +599,11 @@
             for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) {
                 // Contribution to chi^2: a_i^2 P_i
-                psAssert(isfinite(penalties->data.F32[i]), "Invalid penalty");
-                matrix->data.F64[index][index] += norm * penalties->data.F32[i];
+                psAssert(isfinite(penalties1->data.F32[i]), "Invalid penalty");
+		fprintf (stderr, "penalty: %f + %f (%f * %f)\n", matrix->data.F64[index][index], norm * penalties1->data.F32[i], norm, penalties1->data.F32[i]);
+                matrix->data.F64[index][index] += norm * penalties1->data.F32[i];
                 if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
-                    matrix->data.F64[index + numParams + 2][index + numParams + 2] += norm * penalties->data.F32[i];
+		    fprintf (stderr, "penalty: (x^%d y^%d fwhm %f) : %f + %f (%f * %f)\n", kernels->u->data.S32[index], kernels->v->data.S32[index], kernels->widths->data.F32[index], 
+			     matrix->data.F64[index + numParams + 2][index + numParams + 2], norm * penalties2->data.F32[i], norm, penalties2->data.F32[i]);
+		    matrix->data.F64[index + numParams + 2][index + numParams + 2] += norm * penalties2->data.F32[i];			     
                     // matrix[i][i] is ~ (k_i * I_1)(k_i * I_1)
                     // penalties scale with second moments
@@ -682,5 +696,5 @@
 
     pmSubtractionStampList *stamps = job->args->data[0]; // List of stamps
-    const pmSubtractionKernels *kernels = job->args->data[1]; // Kernels
+    pmSubtractionKernels *kernels = job->args->data[1]; // Kernels
     int index = PS_SCALAR_VALUE(job->args->data[2], S32); // Stamp index
     pmSubtractionEquationCalculationMode mode  = PS_SCALAR_VALUE(job->args->data[3], S32); // calculation model
@@ -689,5 +703,5 @@
 }
 
-bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels,
+bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels,
                                          int index, const pmSubtractionEquationCalculationMode mode)
 {
@@ -778,10 +792,10 @@
         status = calculateMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, stamp->image2, stamp->image1,
                                        weight, window, stamp->convolutions1, kernels,
-                                       polyValues, footprint, stamps->normWindow, mode);
+                                       polyValues, footprint, stamps->normWindow1, stamps->normWindow2, mode);
         break;
       case PM_SUBTRACTION_MODE_2:
         status = calculateMatrixVector(stamp->matrix, stamp->vector, &stamp->norm, stamp->image1, stamp->image2,
                                        weight, window, stamp->convolutions2, kernels,
-                                       polyValues, footprint, stamps->normWindow, mode);
+                                       polyValues, footprint, stamps->normWindow2, stamps->normWindow1, mode);
         break;
       case PM_SUBTRACTION_MODE_DUAL:
@@ -789,5 +803,5 @@
                                            stamp->image1, stamp->image2,
                                            weight, window, stamp->convolutions1, stamp->convolutions2,
-                                           kernels, polyValues, footprint, stamps->normWindow, mode);
+                                           kernels, polyValues, footprint, stamps->normWindow1, stamps->normWindow2, mode);
         break;
       default:
@@ -830,5 +844,5 @@
 }
 
-bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels,
+bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, pmSubtractionKernels *kernels,
                                     const pmSubtractionEquationCalculationMode mode)
 {
@@ -996,4 +1010,5 @@
             }
 
+            // double normValue = 1.0;
             double normValue = stats->robustMedian;
             // double bgValue = 0.0;
@@ -1023,4 +1038,10 @@
         }
 # endif
+
+#if (1)
+        for (int i = 0; i < solution->n; i++) {
+            fprintf(stderr, "Single solution %d: %lf\n", i, solution->data.F64[i]);
+        }
+#endif
 
         if (!kernels->solution1) {
@@ -1096,5 +1117,5 @@
 
         int normIndex = PM_SUBTRACTION_INDEX_NORM(kernels); // Index for normalisation
-        calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[normIndex][normIndex] / 1000.0);
+        calculatePenalty(sumMatrix, sumVector, kernels, sumMatrix->data.F64[normIndex][normIndex] / 100.0);
 #endif
 
@@ -1177,5 +1198,5 @@
 
 
-#ifdef TESTING
+#if (1)
         for (int i = 0; i < solution->n; i++) {
             fprintf(stderr, "Dual solution %d: %lf\n", i, solution->data.F64[i]);
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionEquation.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionEquation.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionEquation.h	(revision 29060)
@@ -19,5 +19,5 @@
 /// Calculate the least-squares equation to match the image quality for a single stamp
 bool pmSubtractionCalculateEquationStamp(pmSubtractionStampList *stamps, ///< Stamps
-                                         const pmSubtractionKernels *kernels, ///< Kernel parameters
+                                         pmSubtractionKernels *kernels, ///< Kernel parameters
                                          int index, ///< Index of stamp
                                          const pmSubtractionEquationCalculationMode mode
@@ -26,5 +26,5 @@
 /// Calculate the least-squares equation to match the image quality
 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, ///< Stamps
-                                    const pmSubtractionKernels *kernels, ///< Kernel parameters
+                                    pmSubtractionKernels *kernels, ///< Kernel parameters
                                     const pmSubtractionEquationCalculationMode mode
     );
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionKernels.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionKernels.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionKernels.c	(revision 29060)
@@ -26,5 +26,6 @@
     psFree(kernels->vStop);
     psFree(kernels->preCalc);
-    psFree(kernels->penalties);
+    psFree(kernels->penalties1);
+    psFree(kernels->penalties2);
     psFree(kernels->solution1);
     psFree(kernels->solution2);
@@ -140,5 +141,8 @@
     kernels->v = psVectorRealloc(kernels->v, start + numNew);
     kernels->preCalc = psArrayRealloc(kernels->preCalc, start + numNew);
-    kernels->penalties = psVectorRealloc(kernels->penalties, start + numNew);
+
+    kernels->penalties1 = psVectorRealloc(kernels->penalties1, start + numNew);
+    kernels->penalties2 = psVectorRealloc(kernels->penalties2, start + numNew);
+
     kernels->inner = start;
     kernels->num += numNew;
@@ -156,6 +160,12 @@
             kernels->v->data.S32[index] = v;
             kernels->preCalc->data[index] = NULL;
-            kernels->penalties->data.F32[index] = kernels->penalty * PS_SQR(PS_SQR(u) + PS_SQR(v));
-            psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty");
+
+	    // XXX this needs to be changed to use the *convolved* second moment
+            kernels->penalties1->data.F32[index] = kernels->penalty * PS_SQR(PS_SQR(u) + PS_SQR(v));
+            psAssert (isfinite(kernels->penalties1->data.F32[index]), "invalid penalty");
+
+            kernels->penalties2->data.F32[index] = kernels->penalty * PS_SQR(PS_SQR(u) + PS_SQR(v));
+            psAssert (isfinite(kernels->penalties2->data.F32[index]), "invalid penalty");
+
             psTrace("psModules.imcombine", 7, "Kernel %d: %d %d\n", index, u, v);
         }
@@ -166,12 +176,14 @@
     kernels->v->n = start + numNew;
     kernels->preCalc->n = start + numNew;
-    kernels->penalties->n = start + numNew;
+
+    kernels->penalties1->n = start + numNew;
+    kernels->penalties2->n = start + numNew;
 
     return true;
 }
 
-bool pmSubtractionKernelPreCalcNormalize(pmSubtractionKernels *kernels, pmSubtractionKernelPreCalc *preCalc,
-                                         int index, int size, int uOrder, int vOrder, float fwhm,
-                                         bool AlardLuptonStyle, bool forceZeroNull)
+static bool pmSubtractionKernelPreCalcNormalize(pmSubtractionKernels *kernels, pmSubtractionKernelPreCalc *preCalc,
+						int index, int uOrder, int vOrder, float fwhm,
+						bool AlardLuptonStyle, bool forceZeroNull)
 {
     // we have 4 cases here:
@@ -182,14 +194,13 @@
 
     // Calculate moments
-    double penalty = 0.0;                   // Moment, for penalty
     double sum = 0.0, sum2 = 0.0;           // Sum of kernel component
     float min = INFINITY, max = -INFINITY;  // Minimum and maximum kernel value
-    for (int v = -size; v <= size; v++) {
-        for (int u = -size; u <= size; u++) {
+
+    for (int v = preCalc->kernel->yMin; v <= preCalc->kernel->yMax; v++) {
+        for (int u = preCalc->kernel->xMin; u <= preCalc->kernel->xMax; u++) {
             double value = preCalc->kernel->kernel[v][u];
             double value2 = PS_SQR(value);
             sum += value;
             sum2 += value2;
-            penalty += value2 * PS_SQR((PS_SQR(u) + PS_SQR(v)));
             min = PS_MIN(value, min);
             max = PS_MAX(value, max);
@@ -198,5 +209,5 @@
 
 #if 0
-    fprintf(stderr, "%d raw: %lf, null: %f, min: %lf, max: %lf, moment: %lf\n", index, sum, preCalc->kernel->kernel[0][0], min, max, penalty);
+    fprintf(stderr, "%d raw: %lf, null: %f, min: %lf, max: %lf\n", index, sum, preCalc->kernel->kernel[0][0], min, max);
 #endif
 
@@ -207,5 +218,7 @@
         if (uOrder % 2 == 0 && vOrder % 2 == 0) {
             // Even functions: normalise to unit sum and subtract null pixel so that sum is zero
-            scale2D = 1.0 / fabs(sum);
+	    // Re-normalize 
+            // scale2D  = 1.0 / fabs(sum);
+            scale2D  = 1.0 / sqrt(sum2);
             zeroNull = true;
         } else {
@@ -239,22 +252,25 @@
 
     psBinaryOp(preCalc->kernel->image, preCalc->kernel->image, "*", psScalarAlloc(scale2D, PS_TYPE_F32));
-    penalty *= 1.0 / sum2;
 
     if (zeroNull) {
-        preCalc->kernel->kernel[0][0] -= 1.0;
-    }
-
-#if 0
+        // preCalc->kernel->kernel[0][0] -= 1.0;
+        preCalc->kernel->kernel[0][0] -= sum / sqrt (sum2);
+    }
+
+#if 1
     {
-        double sum = 0.0;   // Sum of kernel component
+        double Sum = 0.0;   // Sum of kernel component
+        double Sum2 = 0.0;   // Sum of kernel component
         float min = INFINITY, max = -INFINITY;  // Minimum and maximum kernel value
-        for (int v = -size; v <= size; v++) {
-            for (int u = -size; u <= size; u++) {
-                sum += preCalc->kernel->kernel[v][u];
+	for (int v = preCalc->kernel->yMin; v <= preCalc->kernel->yMax; v++) {
+	    for (int u = preCalc->kernel->xMin; u <= preCalc->kernel->xMax; u++) {
+		double value = preCalc->kernel->kernel[v][u];
+                Sum += value;
+		Sum2 += PS_SQR(value);
                 min = PS_MIN(preCalc->kernel->kernel[v][u], min);
                 max = PS_MAX(preCalc->kernel->kernel[v][u], max);
             }
         }
-        fprintf(stderr, "%d mod: %lf, null: %f, min: %lf, max: %lf, scale: %f\n", index, sum, preCalc->kernel->kernel[0][0], min, max, scale2D);
+        fprintf(stderr, "%d sum: %lf, sum2: %lf, null: %f, min: %lf, max: %lf, scale: %f\n", index, Sum, Sum2, preCalc->kernel->kernel[0][0], min, max, scale2D);
     }
 #endif
@@ -267,7 +283,5 @@
     }
     kernels->preCalc->data[index] = preCalc;
-    kernels->penalties->data.F32[index] = kernels->penalty * penalty;
-    psAssert (isfinite(kernels->penalties->data.F32[index]), "invalid penalty");
-    psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index, fwhm, uOrder, vOrder, penalty);
+    psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d\n", index, fwhm, uOrder, vOrder);
 
     return true;
@@ -321,6 +335,6 @@
 
                 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values
-                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
-                // pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], false, false);
+                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, uOrder, vOrder, fwhms->data.F32[i], true, false);
+                // pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, uOrder, vOrder, fwhms->data.F32[i], false, false);
             }
         }
@@ -379,5 +393,5 @@
             for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
                 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS, uOrder, vOrder, size, sigma); // structure to hold precalculated values
-                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
+                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, uOrder, vOrder, fwhms->data.F32[i], true, false);
             }
         }
@@ -385,5 +399,5 @@
             // XXX modify size for hermitians to account for sqrt(2) in Hermitian definition (relative to ISIS Gaussian)
             pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_ISIS_RADIAL, order, order, size, sigma / sqrt(2.0)); // structure to hold precalculated values
-            pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, order, order, fwhms->data.F32[i], true, true);
+            pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, order, order, fwhms->data.F32[i], true, true);
         }
     }
@@ -437,5 +451,5 @@
             for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
                 pmSubtractionKernelPreCalc *preCalc = pmSubtractionKernelPreCalcAlloc(PM_SUBTRACTION_KERNEL_HERM, uOrder, vOrder, size, sigma); // structure to hold precalculated values
-                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
+                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, uOrder, vOrder, fwhms->data.F32[i], true, false);
             }
         }
@@ -506,5 +520,5 @@
 
                 // XXX do we use Alard-Lupton normalization (last param true) or not?
-                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, size, uOrder, vOrder, fwhms->data.F32[i], true, false);
+                pmSubtractionKernelPreCalcNormalize (kernels, preCalc, index, uOrder, vOrder, fwhms->data.F32[i], true, false);
 
                 // XXXX test demo that deconvolved kernel is valid
@@ -572,5 +586,9 @@
     kernels->preCalc = psArrayAlloc(numBasisFunctions);
     kernels->penalty = penalty;
-    kernels->penalties = psVectorAlloc(numBasisFunctions, PS_TYPE_F32);
+    kernels->penalties1 = psVectorAlloc(numBasisFunctions, PS_TYPE_F32);
+    psVectorInit(kernels->penalties1, NAN);
+    kernels->penalties2 = psVectorAlloc(numBasisFunctions, PS_TYPE_F32);
+    psVectorInit(kernels->penalties2, NAN);
+    kernels->havePenalties = false;
     kernels->size = size;
     kernels->inner = 0;
@@ -771,5 +789,6 @@
 
     psWarning("Kernel penalty for dual-convolution is not configured for SPAM kernels.");
-    psVectorInit(kernels->penalties, 0.0);
+    psVectorInit(kernels->penalties1, 0.0);
+    psVectorInit(kernels->penalties2, 0.0);
 
     return kernels;
@@ -866,5 +885,6 @@
 
     psWarning("Kernel penalty for dual-convolution is not configured for FRIES kernels.");
-    psVectorInit(kernels->penalties, 0.0);
+    psVectorInit(kernels->penalties1, 0.0);
+    psVectorInit(kernels->penalties2, 0.0);
 
     return kernels;
@@ -1040,6 +1060,12 @@
                 kernels->u->data.S32[index] = uOrder;
                 kernels->v->data.S32[index] = vOrder;
-                kernels->penalties->data.F32[index] = kernels->penalty * fabsf(moment);
-                if (!isfinite(kernels->penalties->data.F32[index])) {
+
+		// XXX convert to use the convolved 2nd moment
+                kernels->penalties1->data.F32[index] = kernels->penalty * fabsf(moment);
+                if (!isfinite(kernels->penalties1->data.F32[index])) {
+                    psAbort ("invalid penalty");
+                }
+                kernels->penalties2->data.F32[index] = kernels->penalty * fabsf(moment);
+                if (!isfinite(kernels->penalties2->data.F32[index])) {
                     psAbort ("invalid penalty");
                 }
@@ -1247,5 +1273,6 @@
     out->preCalc = psMemIncrRefCounter(in->preCalc);
     out->penalty = in->penalty;
-    out->penalties = psMemIncrRefCounter(in->penalties);
+    out->penalties1 = psMemIncrRefCounter(in->penalties1);
+    out->penalties2 = psMemIncrRefCounter(in->penalties2);
     out->uStop = psMemIncrRefCounter(in->uStop);
     out->vStop = psMemIncrRefCounter(in->vStop);
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionKernels.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionKernels.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionKernels.h	(revision 29060)
@@ -39,5 +39,7 @@
     psArray *preCalc;                   ///< Array of images containing pre-calculated kernel (for ISIS, HERM or DECONV_HERM)
     float penalty;                      ///< Penalty for wideness
-    psVector *penalties;                ///< Penalty for each kernel component
+    psVector *penalties1;               ///< Penalty for each kernel component
+    psVector *penalties2;               ///< Penalty for each kernel component
+    bool havePenalties;			///< flag to test if we have already calculated the penalties or not.
     int size;                           ///< The half-size of the kernel
     int inner;                          ///< The size of an inner region
@@ -308,4 +310,3 @@
     );
 
-
 #endif
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionMatch.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionMatch.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionMatch.c	(revision 29060)
@@ -1304,4 +1304,7 @@
     float scale = PS_MAX(fwhm1, fwhm2) / scaleRef;      // Scaling factor
 
+    // XXX save these values in a static for later use
+    pmSubtractionSetFWHMs(fwhm1, fwhm2);
+
     if (isfinite(scaleMin) && scale < scaleMin) {
         scale = scaleMin;
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionMatch.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionMatch.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionMatch.h	(revision 29060)
@@ -110,4 +110,3 @@
     );
 
-
 #endif
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionStamps.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionStamps.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionStamps.c	(revision 29060)
@@ -7,18 +7,23 @@
 #include <pslib.h>
 
+#include "pmErrorCodes.h"
+#include "pmHDU.h"
+#include "pmFPA.h"
+
 // All these includes required to get stamps out of an array of pmSources
-#include "pmMoments.h"
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
-#include "pmResiduals.h"
-#include "pmHDU.h"
-#include "pmFPA.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmErrorCodes.h"
 
 #include "pmSubtraction.h"
@@ -46,5 +51,6 @@
     psFree(list->y);
     psFree(list->flux);
-    psFree(list->window);
+    psFree(list->window1);
+    psFree(list->window2);
 }
 
@@ -225,7 +231,9 @@
     list->y = NULL;
     list->flux = NULL;
-    list->window = NULL;
     list->normFrac = normFrac;
-    list->normWindow = 0;
+    list->window1 = NULL;
+    list->window2 = NULL;
+    list->normWindow1 = 0;
+    list->normWindow2 = 0;
     list->footprint = footprint;
     list->sysErr = sysErr;
@@ -248,7 +256,9 @@
     out->y = NULL;
     out->flux = NULL;
-    out->window = psMemIncrRefCounter(in->window);
+    out->window1 = psMemIncrRefCounter(in->window1);
+    out->window2 = psMemIncrRefCounter(in->window2);
     out->footprint = in->footprint;
-    out->normWindow = in->normWindow;
+    out->normWindow1 = in->normWindow1;
+    out->normWindow2 = in->normWindow2;
 
     for (int i = 0; i < num; i++) {
@@ -638,7 +648,11 @@
     int size = stamps->footprint; // Size of postage stamps
 
-    psFree (stamps->window);
-    stamps->window = psKernelAlloc(-size, size, -size, size);
-    psImageInit(stamps->window->image, 0.0);
+    psFree (stamps->window1);
+    stamps->window1 = psKernelAlloc(-size, size, -size, size);
+    psImageInit(stamps->window1->image, 0.0);
+
+    psFree (stamps->window2);
+    stamps->window2 = psKernelAlloc(-size, size, -size, size);
+    psImageInit(stamps->window2->image, 0.0);
 
     // generate normalizations for each stamp
@@ -669,6 +683,8 @@
 
     // generate the window pixels
-    double sum = 0.0;                   // Sum inside the window
-    float maxValue = 0.0;               // Maximum value, for normalisation
+    double sum1 = 0.0;                   // Sum inside the window
+    double sum2 = 0.0;                   // Sum inside the window
+    float maxValue1 = 0.0;               // Maximum value, for normalisation
+    float maxValue2 = 0.0;               // Maximum value, for normalisation
     for (int y = -size; y <= size; y++) {
         for (int x = -size; x <= size; x++) {
@@ -691,4 +707,5 @@
             }
             float f1 = stats->robustMedian;
+
             psStatsInit (stats);
             if (!psVectorStats (stats, flux2, NULL, NULL, 0)) {
@@ -697,34 +714,104 @@
             float f2 = stats->robustMedian;
 
-            stamps->window->kernel[y][x] = f1 + f2;
+            stamps->window1->kernel[y][x] = f1;
             if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(size)) {
-                sum += stamps->window->kernel[y][x];
-            }
-            maxValue = PS_MAX(maxValue, stamps->window->kernel[y][x]);
-        }
-    }
-
-    psTrace("psModules.imcombine", 3, "Window total: %f, threshold: %f\n",
-            sum, (1.0 - stamps->normFrac) * sum);
-    bool done = false;
-    for (int radius = 1; radius <= size && !done; radius++) {
-        double within = 0.0;
+                sum1 += stamps->window1->kernel[y][x];
+            }
+            maxValue1 = PS_MAX(maxValue1, stamps->window1->kernel[y][x]);
+
+            stamps->window2->kernel[y][x] = f2;
+            if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(size)) {
+                sum2 += stamps->window2->kernel[y][x];
+            }
+            maxValue2 = PS_MAX(maxValue2, stamps->window2->kernel[y][x]);
+        }
+    }
+
+    psTrace("psModules.imcombine", 3, "Window total (1): %f, threshold: %f\n", sum1, (1.0 - stamps->normFrac) * sum1);
+    psTrace("psModules.imcombine", 3, "Window total (2): %f, threshold: %f\n", sum2, (1.0 - stamps->normFrac) * sum2);
+
+# if (0)
+    // this block attempts to calculate the radius based on the first radial moment
+    bool done1 = false;
+    bool done2 = false;
+    double prior1 = 0.0;
+    double prior2 = 0.0;
+    for (int y = -size; y <= size; y++) {
+	for (int x = -size; x <= size; x++) {
+	    float r = hypot(x, y);
+	    Sr1 += r * stamps->window1->kernel[y][x];
+	    Sr2 += r * stamps->window2->kernel[y][x];
+	    Sf1 += stamps->window1->kernel[y][x];
+	    Sf2 += stamps->window2->kernel[y][x];
+        }
+    }
+    
+    float R1 = Sr1 / Sf1;
+    float R2 = Sr2 / Sf2;
+
+    stamps->normWindow1 = 2.5*R1;
+    stamps->normWindow1 = 2.5*R2;
+# else
+    // XXX : this block attempts to calculate the radius by looking at the curve of growth (or something vaguely equivalent).
+    // It did not do very well (though a true curve-of-growth analysis might be better...)
+    bool done1 = false;
+    bool done2 = false;
+    double prior1 = 0.0;
+    double prior2 = 0.0;
+    double delta1o = 1.0;
+    double delta2o = 1.0;
+    for (int radius = 1; radius <= size && !(done1 && done2); radius++) {
+        double within1 = 0.0;
+        double within2 = 0.0;
         for (int y = -radius; y <= radius; y++) {
             for (int x = -radius; x <= radius; x++) {
                 if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) {
-                    within += stamps->window->kernel[y][x];
+                    within1 += stamps->window1->kernel[y][x];
                 }
-            }
-        }
-        psTrace("psModules.imcombine", 5, "Radius %d: %f\n", radius, within);
-        if (within > (1.0 - stamps->normFrac) * sum) {
-            stamps->normWindow = radius;
-            done = true;
-        }
-    }
-
-    psTrace("psModules.imcombine", 3, "Normalisation window radius set to %d\n", stamps->normWindow);
-    if (stamps->normWindow == 0 || stamps->normWindow >= size) {
-        psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size.");
+                if (PS_SQR(x) + PS_SQR(y) <= PS_SQR(radius)) {
+                    within2 += stamps->window2->kernel[y][x];
+                }
+            }
+        }
+	double delta1 = (within1 - prior1) / within1;
+        if (!done1 && (fabs(delta1) < stamps->normFrac)) {
+	    // interpolate to the radius at which delta2 is normFrac:
+            stamps->normWindow1 = radius - (stamps->normFrac - delta1) / (delta1o - delta1);
+	    fprintf (stderr, "choosing %f (%d) for 1 (%f : %f)\n", stamps->normWindow1, radius, within1, delta1);
+            done1 = true;
+        }
+	double delta2 = (within2 - prior2) / within2;
+        if (!done2 && (fabs(delta2) < stamps->normFrac)) {
+	    // interpolate to the radius at which delta2 is normFrac:
+            stamps->normWindow2 = radius - (stamps->normFrac - delta2) / (delta2o - delta2);
+	    fprintf (stderr, "choosing %f (%d) for 2 (%f : %f)\n", stamps->normWindow2, radius, within2, delta2);
+            done2 = true;
+        }
+        psTrace("psModules.imcombine", 5, "Radius %d: %f (%f) and %f (%f)\n", radius, within1, delta1, within2, delta2);
+
+	prior1 = within1;
+	prior2 = within2;
+	delta1o = delta1;
+	delta2o = delta2;
+
+        // if (!done1 && (within1 > (1.0 - stamps->normFrac) * sum1)) {
+        //     stamps->normWindow1 = radius;
+        //     done1 = true;
+        // }
+        // if (!done2 && (within2 > (1.0 - stamps->normFrac) * sum2)) {
+        //     stamps->normWindow2 = radius;
+        //     done2 = true;
+        // }
+
+    }
+# endif
+
+    psTrace("psModules.imcombine", 3, "Normalisation window radii set to %f and %f\n", stamps->normWindow1, stamps->normWindow2);
+    if (stamps->normWindow1 == 0 || stamps->normWindow1 >= size) {
+        psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size (1).");
+        return false;
+    }
+    if (stamps->normWindow2 == 0 || stamps->normWindow2 >= size) {
+        psError(PM_ERR_STAMPS, true, "Unable to determine normalisation window size (2).");
         return false;
     }
@@ -733,5 +820,11 @@
     for (int y = -size; y <= size; y++) {
         for (int x = -size; x <= size; x++) {
-            stamps->window->kernel[y][x] /= maxValue;
+            stamps->window1->kernel[y][x] /= maxValue1;
+        }
+    }
+    // re-normalize so chisquare values are sensible
+    for (int y = -size; y <= size; y++) {
+        for (int x = -size; x <= size; x++) {
+            stamps->window2->kernel[y][x] /= maxValue2;
         }
     }
@@ -739,6 +832,10 @@
 #if 0
     {
-        psFits *fits = psFitsOpen ("window.fits", "w");
-        psFitsWriteImage (fits, NULL, stamps->window->image, 0, NULL);
+	psFits *fits = NULL;
+	fits = psFitsOpen ("window1.fits", "w");
+        psFitsWriteImage (fits, NULL, stamps->window1->image, 0, NULL);
+        psFitsClose (fits);
+        fits = psFitsOpen ("window2.fits", "w");
+        psFitsWriteImage (fits, NULL, stamps->window2->image, 0, NULL);
         psFitsClose (fits);
     }
@@ -747,8 +844,108 @@
     psFree (stats);
     psFree (flux1);
-    psFree(flux2);
+    psFree (flux2);
     psFree (norm1);
     psFree (norm2);
     return true;
+}
+
+static pthread_mutex_t getPenaltiesMutex = PTHREAD_MUTEX_INITIALIZER;
+
+// kernels->penalty is an overall scaling factor (user-supplied)
+bool pmSubtractionKernelPenaltiesStamp(pmSubtractionStamp *stamp, pmSubtractionKernels *kernels)
+{
+    // we only need the penalties if we are doing dual convolution
+    if (kernels->mode != PM_SUBTRACTION_MODE_DUAL) return true;
+
+    // we only calculate the penalties once.
+    if (kernels->havePenalties) return true;
+
+    // in a threaded context, only one thread can calculate the penalties.  attempt to grab a
+    // mutex before continuing
+    pthread_mutex_lock(&getPenaltiesMutex);
+
+    // did someone else already get the mutex and do this?
+    if (kernels->havePenalties) {
+	pthread_mutex_unlock(&getPenaltiesMutex);
+	return true;
+    }
+
+    for (int i = 0; i < kernels->num; i++) {
+	pmSubtractionKernelPenalties(stamp, kernels, i);
+    }
+
+    kernels->havePenalties = true;
+    pthread_mutex_unlock(&getPenaltiesMutex);
+    return true;
+}
+
+# define EMPIRICAL 0
+
+// kernels->penalty is an overall scaling factor (user-supplied)
+bool pmSubtractionKernelPenalties(pmSubtractionStamp *stamp, pmSubtractionKernels *kernels, int index)
+{
+    float penalty1, penalty2;
+    float fwhm1, fwhm2;
+
+    // XXX this is annoyingly hack-ish
+    pmSubtractionGetFWHMs(&fwhm1, &fwhm2);
+
+    bool zeroNull = false;
+    int uOrder = kernels->u->data.S32[index];
+    int vOrder = kernels->v->data.S32[index];
+    if (uOrder % 2 == 0 && vOrder % 2 == 0) zeroNull = true;
+
+    if (EMPIRICAL) {
+	psKernel *convolution1 = stamp->convolutions1->data[index];
+	penalty1 = pmSubtractionKernelPenaltySingle(convolution1, zeroNull);
+
+	psKernel *convolution2 = stamp->convolutions2->data[index];
+	penalty2 = pmSubtractionKernelPenaltySingle(convolution2, zeroNull);
+    } else {
+	pmSubtractionKernelPreCalc *kernel = kernels->preCalc->data[index];
+	float M2 = pmSubtractionKernelPenaltySingle(kernel->kernel, zeroNull);
+
+	penalty1 = M2 + PS_SQR(fwhm1 / 2.35); // rescale the unconvolved second-moment by the image second moment 
+	penalty2 = M2 + PS_SQR(fwhm2 / 2.35); // rescale the unconvolved second-moment by the image second moment 
+    }
+    kernels->penalties1->data.F32[index] = kernels->penalty * penalty1;
+    psAssert (isfinite(kernels->penalties1->data.F32[index]), "invalid penalty");
+
+    kernels->penalties2->data.F32[index] = kernels->penalty * penalty2;
+    psAssert (isfinite(kernels->penalties2->data.F32[index]), "invalid penalty");
+
+    fprintf(stderr, "penalty1: %f, penalty2: %f\n", penalty1, penalty2);
+
+    return true;
+}
+
+float pmSubtractionKernelPenaltySingle(psKernel *kernel, bool zeroNull)
+{
+    // Calculate moments
+    double penalty = 0.0;                   // Moment, for penalty
+    double sum = 0.0, sum2 = 0.0;           // Sum of kernel component
+    float min = INFINITY, max = -INFINITY;  // Minimum and maximum kernel value
+    for (int v = kernel->yMin; v <= kernel->yMax; v++) {
+	for (int u = kernel->xMin; u <= kernel->xMax; u++) {
+            double value = kernel->kernel[v][u];
+	    if (false && zeroNull && (u == 0) && (v == 0)) {
+		value += 1.0;
+	    }
+            double value2 = PS_SQR(value);
+            sum += value;
+            sum2 += value2;
+            penalty += value2 * PS_SQR((PS_SQR(u) + PS_SQR(v)));
+            min = PS_MIN(value, min);
+            max = PS_MAX(value, max);
+        }
+    }
+    penalty *= 1.0 / sum2;
+
+    if (1) {
+	fprintf(stderr, "min: %lf, max: %lf, moment: %lf, flux^2: %lf\n", min, max, penalty, sum2);
+	// psTrace("psModules.imcombine", 7, "Kernel %d: %f %d %d %f\n", index, fwhm, uOrder, vOrder, penalty);
+    }
+
+    return penalty;
 }
 
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionStamps.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionStamps.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionStamps.h	(revision 29060)
@@ -24,7 +24,9 @@
     psArray *flux;                      ///< Fluxes for possible stamps (or NULL)
     int footprint;                      ///< Half-size of stamps
-    psKernel *window;                   ///< window function generated from ensemble of stamps
     float normFrac;                     ///< Fraction of flux in window for normalisation window
-    int normWindow;                     ///< Size of window for measuring normalisation
+    psKernel *window1;                  ///< window function generated from ensemble of stamps (input 1)
+    psKernel *window2;                  ///< window function generated from ensemble of stamps (input 2)
+    float normWindow1;                    ///< Size of window for measuring normalisation
+    float normWindow2;                    ///< Size of window for measuring normalisation
     float sysErr;                       ///< Systematic error
     float skyErr;                       ///< increase effective readnoise
@@ -195,3 +197,8 @@
 bool pmSubtractionStampsResetStatus (pmSubtractionStampList *stamps);
 
+
+bool pmSubtractionKernelPenaltiesStamp(pmSubtractionStamp *stamp, pmSubtractionKernels *kernels);
+bool pmSubtractionKernelPenalties(pmSubtractionStamp *stamp, pmSubtractionKernels *kernels, int index);
+float pmSubtractionKernelPenaltySingle(psKernel *kernel, bool zeroNull);
+
 #endif
Index: /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionVisual.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionVisual.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/imcombine/pmSubtractionVisual.c	(revision 29060)
@@ -21,4 +21,5 @@
 
 #include "pmVisual.h"
+#include "pmVisualUtils.h"
 
 #include "pmHDU.h"
@@ -61,5 +62,9 @@
  *    @return true for success */
 bool pmSubtractionVisualPlotConvKernels(psImage *convKernels) {
-    if (!pmVisualIsVisual() || !plotConvKernels) return true;
+
+    if (!pmVisualTestLevel("ppsub.kernels", 1)) return true;
+
+    if (!plotConvKernels) return true;
+
     if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) {
         return false;
@@ -75,5 +80,9 @@
     @return true for success */
 bool pmSubtractionVisualPlotStamps(pmSubtractionStampList *stamps, pmReadout *ro) {
-    if (!pmVisualIsVisual() || !plotStamps) return true;
+
+    if (!pmVisualTestLevel("ppsub.stamps", 1)) return true;
+
+    if (!plotStamps) return true;
+
     if (!pmVisualInitWindow (&kapa1, "ppSub:Images")) {
         return false;
@@ -145,5 +154,8 @@
 bool pmSubtractionVisualPlotLeastSquares (pmSubtractionStampList *stamps, bool dual) {
 
-    if (!pmVisualIsVisual() || !plotLeastSquares) return true;
+    if (!pmVisualTestLevel("ppsub.chisq", 1)) return true;
+
+    if (!plotLeastSquares) return true;
+
     if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) {
         return false;
@@ -204,5 +216,9 @@
 
 bool pmSubtractionVisualShowSubtraction(psImage *image, psImage *ref, psImage *sub) {
-    if (!pmVisualIsVisual() || !plotImage) return true;
+
+    if (!pmVisualTestLevel("ppsub.images.sub", 1)) return true;
+
+    if (!plotImage) return true;
+
     if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) {
         return false;
@@ -218,5 +234,6 @@
 bool pmSubtractionVisualShowKernels(pmSubtractionKernels *kernels) {
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("ppsub.kernels.final", 1)) return true;
+
     if (!pmVisualInitWindow (&kapa1, "PPSub:Images")) {
         return false;
@@ -264,5 +281,6 @@
 bool pmSubtractionVisualShowBasis(pmSubtractionStampList *stamps) {
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("ppsub.basis", 1)) return true;
+
     if (!pmVisualInitWindow (&kapa2, "ppSub:StampMasterImage")) {
         return false;
@@ -425,5 +443,5 @@
 bool pmSubtractionVisualShowFitInit(pmSubtractionStampList *stamps) {
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("ppsub.fit", 1)) return true;
 
     // generate 4 storage images large enough to hold the N stamps:
@@ -462,5 +480,5 @@
 bool pmSubtractionVisualShowFitAddStamp(psKernel *target, psKernel *source, psKernel *convolution, double background, double norm, int index) {
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("ppsub.stamp", 1)) return true;
 
     double sum;
@@ -543,5 +561,6 @@
     }
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("ppsub.fit", 1)) return true;
+
     if (!pmVisualInitWindow(&kapa1, "ppSub:Images")) return false;
     if (!pmVisualInitWindow(&kapa2, "ppSub:Misc")) return false;
@@ -605,5 +624,6 @@
     Graphdata graphdata;
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("ppsub.fit", 1)) return true;
+
     if (!pmVisualInitWindow(&kapa3, "ppSub:plots")) return false;
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/Makefile.am
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/Makefile.am	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/Makefile.am	(revision 29060)
@@ -43,6 +43,8 @@
 	pmSourceIO_CMF_PS1_V1.c \
 	pmSourceIO_CMF_PS1_V2.c \
+	pmSourceIO_CMF_PS1_V3.c \
 	pmSourceIO_CMF_PS1_SV1.c \
 	pmSourceIO_CMF_PS1_DV1.c \
+	pmSourceIO_CMF_PS1_DV2.c \
 	pmSourceIO_MatchedRefs.c \
 	pmSourcePlots.c \
@@ -60,4 +62,7 @@
 	pmPSFtryFitPSF.c \
 	pmPSFtryMetric.c \
+	pmPCMdata.c \
+	pmPCM_MinimizeChisq.c \
+	pmSourceFitPCM.c \
 	pmTrend2D.c \
 	pmGrowthCurveGenerate.c \
@@ -71,5 +76,7 @@
 	models/pmModel_QGAUSS.c \
 	models/pmModel_RGAUSS.c \
-	models/pmModel_SERSIC.c
+	models/pmModel_SERSIC.c \
+	models/pmModel_EXP.c \
+	models/pmModel_DEV.c
 
 pkginclude_HEADERS = \
@@ -80,4 +87,5 @@
 	pmPeaks.h \
 	pmMoments.h \
+	pmModelFuncs.h \
 	pmModel.h \
 	pmModelClass.h \
@@ -101,4 +109,5 @@
 	pmPSF_IO.h \
 	pmPSFtry.h \
+	pmPCMdata.h \
 	pmTrend2D.h \
 	pmGrowthCurve.h \
@@ -111,5 +120,7 @@
 	models/pmModel_QGAUSS.h \
 	models/pmModel_RGAUSS.h \
-	models/pmModel_SERSIC.h
+	models/pmModel_SERSIC.h \
+	models/pmModel_EXP.h \
+	models/pmModel_DEV.h
 
 CLEANFILES = *~
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_DEV.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_DEV.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_DEV.c	(revision 29060)
@@ -0,0 +1,472 @@
+/******************************************************************************
+ * this file defines the DEV 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:
+
+   f = exp(-z^n)
+
+   * 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   - normalized dev parameter
+
+   note that a standard dev model uses exp(-K*(z^(1/2n) - 1).  the additional elements (K,
+   the -1 offset) are absorbed in this model by the normalization, the exponent, and the
+   radial scale.  We fit the elements in this form, then re-normalize them on output.
+   *****************************************************************************/
+
+#include <stdio.h>
+#include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
+#include "pmModel_DEV.h"
+
+# define PM_MODEL_NPARAM          7
+# define PM_MODEL_FUNC            pmModelFunc_DEV
+# define PM_MODEL_FLUX            pmModelFlux_DEV
+# define PM_MODEL_GUESS           pmModelGuess_DEV
+# define PM_MODEL_LIMITS          pmModelLimits_DEV
+# define PM_MODEL_RADIUS          pmModelRadius_DEV
+# define PM_MODEL_FROM_PSF        pmModelFromPSF_DEV
+# define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_DEV
+# define PM_MODEL_FIT_STATUS      pmModelFitStatus_DEV
+# define PM_MODEL_SET_LIMITS      pmModelSetLimits_DEV
+
+// f = exp(-z^0.125) 
+# define ALPHA 0.125 
+// # define ALPHA 0.25 
+
+// 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.001, 0.001, -1.0 };
+static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0 };
+
+// Moderate parameter limits
+static float *paramsMinModerate = paramsMinLax;
+static float *paramsMaxModerate = paramsMaxLax;
+
+// 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,
+                     const psVector *params,
+                     const psVector *pixcoord)
+{
+    psF32 *PAR = params->data.F32;
+
+    float index = 0.5 / ALPHA;
+    float bn = 1.9992*index - 0.3271;
+    float Io = exp(bn);
+
+    psF32 X  = pixcoord->data.F32[0] - PAR[PM_PAR_XPOS];
+    psF32 Y  = pixcoord->data.F32[1] - PAR[PM_PAR_YPOS];
+    psF32 px = X / PAR[PM_PAR_SXX];
+    psF32 py = Y / PAR[PM_PAR_SYY];
+    psF32 z  = (PS_SQR(px) + PS_SQR(py) + PAR[PM_PAR_SXY]*X*Y);
+
+    assert (z >= 0);
+
+    psF32 f2 = bn*pow(z,ALPHA);
+    psF32 f1 = Io*exp(-f2);
+    psF32 z0 = PAR[PM_PAR_I0]*f1;
+    psF32 f0 = PAR[PM_PAR_SKY] + z0;
+
+    assert (isfinite(f2));
+    assert (isfinite(f1));
+    assert (isfinite(z0));
+    assert (isfinite(f0));
+
+    if (deriv != NULL) {
+        psF32 *dPAR = deriv->data.F32;
+
+        // gradient is infinite for z = 0; saturate at z = 0.01
+        psF32 z1 = (z < 0.01) ? z0*bn*ALPHA*pow(0.01,ALPHA - 1.0) : z0*bn*ALPHA*pow(z,ALPHA - 1.0);
+
+        dPAR[PM_PAR_SKY]  = +1.0;
+        dPAR[PM_PAR_I0]   = +2.0*f1;
+
+        assert (isfinite(z1));
+
+        dPAR[PM_PAR_XPOS] = +1.0*z1*(2.0*px/PAR[PM_PAR_SXX] + Y*PAR[PM_PAR_SXY]);
+        dPAR[PM_PAR_YPOS] = +1.0*z1*(2.0*py/PAR[PM_PAR_SYY] + X*PAR[PM_PAR_SXY]);
+        dPAR[PM_PAR_SXX]  = +2.0*z1*px*px/PAR[PM_PAR_SXX];
+        dPAR[PM_PAR_SYY]  = +2.0*z1*py*py/PAR[PM_PAR_SYY];
+        dPAR[PM_PAR_SXY]  = -1.0*z1*X*Y;
+    }
+    return (f0);
+}
+
+// define the parameter limits
+// AR_MAX is the maximum allowed axis ratio
+// AR_RATIO is ((1-R)/(1+R))^2 where R = AR_MAX^(-2)
+# define AR_MAX 20.0
+# define AR_RATIO 0.99
+bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta)
+{
+    if (!limitsApply) {
+        return true;
+    }
+    psAssert(nParam >= 0 && nParam < PM_MODEL_NPARAM, "Parameter index is out of bounds");
+
+    // we need to calculate the limits for SXY specially
+    float q2 = NAN;
+    if (nParam == PM_PAR_SXY) {
+        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*sqrtf(q1);
+    }
+
+    switch (mode) {
+      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");
+    }
+    psAbort("should not reach here");
+    return false;
+}
+
+// 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)
+{
+    pmMoments *moments = source->moments;
+    pmPeak    *peak    = source->peak;
+    psF32     *PAR  = model->params->data.F32;
+
+    psEllipseMoments emoments;
+    emoments.x2 = moments->Mxx;
+    emoments.xy = moments->Mxy;
+    emoments.y2 = moments->Myy;
+
+    // force the axis ratio to be < 20.0
+    psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
+
+    if (!isfinite(axes.major)) return false;
+    if (!isfinite(axes.minor)) return false;
+    if (!isfinite(axes.theta)) return false;
+
+    psEllipseShape shape = psEllipseAxesToShape (axes);
+
+    if (!isfinite(shape.sx))  return false;
+    if (!isfinite(shape.sy))  return false;
+    if (!isfinite(shape.sxy)) return false;
+
+    // the other parameters depend on the guess for PAR_7
+    float index = 0.5 / ALPHA;
+    float bn = 1.9992*index - 0.3271;
+    // float fR = 1.0 / (sqrt(2.0) * pow (bn, index));
+    float Io = exp(0.5*bn);
+
+    float Sxx = PS_MAX(0.5, shape.sx);
+    float Syy = PS_MAX(0.5, shape.sy);
+
+    PAR[PM_PAR_SKY]  = 0.0;
+    PAR[PM_PAR_I0]   = peak->flux / Io;
+    PAR[PM_PAR_XPOS] = peak->xf;
+    PAR[PM_PAR_YPOS] = peak->yf;
+    // PAR[PM_PAR_SXX]  = Sxx * fR;
+    // PAR[PM_PAR_SYY]  = Syy * fR;
+    PAR[PM_PAR_SXX]  = Sxx;
+    PAR[PM_PAR_SYY]  = Syy;
+    PAR[PM_PAR_SXY]  = shape.sxy;
+
+    return(true);
+}
+
+psF64 PM_MODEL_FLUX (const psVector *params)
+{
+    float z, norm;
+    psEllipseShape shape;
+
+    psF32 *PAR = params->data.F32;
+
+    shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
+    shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
+    shape.sxy = PAR[PM_PAR_SXY];
+
+    // Area is equivalent to 2 pi sigma^2
+    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
+    psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
+
+    // the area needs to be multiplied by the integral of f(z)
+    norm = 0.0;
+
+    # define DZ 0.25
+
+    float f0 = 1.0;
+    float f1, f2;
+    for (z = DZ; z < 50; z += DZ) {
+	f1 = exp(-pow(z,ALPHA));
+        z += DZ;
+	f2 = exp(-pow(z,ALPHA));
+        norm += f0 + 4*f1 + f2;
+        f0 = f2;
+    }
+    norm *= DZ / 3.0;
+
+    psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
+
+    return(Flux);
+}
+
+// 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)
+{
+    psEllipseShape shape;
+
+    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);
+
+    shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
+    shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
+    shape.sxy = PAR[PM_PAR_SXY];
+
+    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
+
+    // f = Io exp(-z^n) -> z^n = ln(Io/f)
+    psF64 zn = log(PAR[PM_PAR_I0] / flux);
+    psF64 radius = axes.major * sqrt (2.0) * pow(zn, 0.5 / ALPHA);
+
+    psAssert (isfinite(radius), "fix this code: z should not be nan");
+    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;
+
+    // we require these two parameters to exist
+    assert (psf->params->n > PM_PAR_YPOS);
+    assert (psf->params->n > PM_PAR_XPOS);
+
+    for (int i = 0; i < psf->params->n; i++) {
+        if (psf->params->data[i] == NULL) {
+            out[i] = in[i];
+        } else {
+            pmTrend2D *trend = psf->params->data[i];
+            out[i] = pmTrend2DEval(trend, in[PM_PAR_XPOS], in[PM_PAR_YPOS]);
+        }
+    }
+
+    // the 2D PSF model fits polarization terms (E0,E1,E2)
+    // convert to shape terms (SXX,SYY,SXY)
+    if (!pmPSF_FitToModel (out, 0.1)) {
+        psTrace("psModules.objects", 5, "Failed to fit object at (r,c) = (%.1f,%.1f)", in[PM_PAR_YPOS], in[PM_PAR_XPOS]);
+        return false;
+    }
+
+    // apply the model limits here: this truncates excessive extrapolation
+    // XXX do we need to do this still?  should we put in asserts to test?
+    for (int i = 0; i < psf->params->n; i++) {
+        // apply the limits to all components or just the psf-model parameters?
+        if (psf->params->data[i] == NULL)
+            continue;
+
+        bool status = true;
+        status &= PM_MODEL_LIMITS(PS_MINIMIZE_PARAM_MIN, i, out, NULL);
+        status &= PM_MODEL_LIMITS(PS_MINIMIZE_PARAM_MAX, i, out, NULL);
+        if (!status) {
+            psTrace ("psModules.objects", 5, "Hitting parameter limits at (r,c) = (%.1f, %.1f)",
+                     in[PM_PAR_XPOS], in[PM_PAR_YPOS]);
+            modelPSF->flags |= PM_MODEL_STATUS_LIMITS;
+        }
+    }
+
+    return true;
+}
+
+// construct the PSF model from the FLT model and the psf
+// XXX is this sufficiently general do be a global function, not a pmModelClass function?
+bool PM_MODEL_PARAMS_FROM_PSF (pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io)
+{
+    psF32 *PAR = model->params->data.F32;
+
+    // we require these two parameters to exist
+    assert (psf->params->n > PM_PAR_YPOS);
+    assert (psf->params->n > PM_PAR_XPOS);
+
+    PAR[PM_PAR_SKY]  = 0.0;
+    PAR[PM_PAR_I0]   = Io;
+    PAR[PM_PAR_XPOS] = Xo;
+    PAR[PM_PAR_YPOS] = Yo;
+
+    // supply the model-fitted parameters, or copy from the input
+    for (int i = 0; i < psf->params->n; i++) {
+        if (i == PM_PAR_SKY) continue;
+        if (i == PM_PAR_I0) continue;
+        if (i == PM_PAR_XPOS) continue;
+        if (i == PM_PAR_YPOS) continue;
+        pmTrend2D *trend = psf->params->data[i];
+        PAR[i] = pmTrend2DEval(trend, Xo, Yo);
+    }
+
+    // the 2D PSF model fits polarization terms (E0,E1,E2)
+    // convert to shape terms (SXX,SYY,SXY)
+    // XXX user-defined value for limit?
+    if (!pmPSF_FitToModel (PAR, 0.1)) {
+        psTrace ("psModules.objects", 3, "Failed to fit object at (r,c) = (%.1f,%.1f)", Xo, Yo);
+        return false;
+    }
+
+    // apply the model limits here: this truncates excessive extrapolation
+    // XXX do we need to do this still?  should we put in asserts to test?
+    for (int i = 0; i < psf->params->n; i++) {
+        // apply the limits to all components or just the psf-model parameters?
+        if (psf->params->data[i] == NULL)
+            continue;
+
+        bool status = true;
+        status &= PM_MODEL_LIMITS (PS_MINIMIZE_PARAM_MIN, i, PAR, NULL);
+        status &= PM_MODEL_LIMITS (PS_MINIMIZE_PARAM_MAX, i, PAR, NULL);
+        if (!status) {
+            psTrace ("psModules.objects", 5, "Hitting parameter limits at (r,c) = (%.1f, %.1f)", Xo, Yo);
+            model->flags |= PM_MODEL_STATUS_LIMITS;
+        }
+    }
+    return(true);
+}
+
+bool PM_MODEL_FIT_STATUS (pmModel *model)
+{
+    bool  status;
+
+    psF32 *PAR  = model->params->data.F32;
+    psF32 *dPAR = model->dparams->data.F32;
+
+    status = true;
+    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_MODERATE:
+        paramsMinUse = paramsMinModerate;
+        paramsMaxUse = paramsMaxModerate;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_STRICT:
+        paramsMinUse = paramsMinStrict;
+        paramsMaxUse = paramsMaxStrict;
+        limitsApply = true;
+        break;
+      default:
+        psAbort("Unrecognised model limits type: %x", type);
+    }
+    return;
+}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_DEV.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_DEV.h	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_DEV.h	(revision 29060)
@@ -0,0 +1,15 @@
+#ifndef PM_MODEL_DEV_H
+
+#include "pmModel.h"
+
+psF32 pmModelFunc_DEV(psVector *deriv, const psVector *params, const psVector *pixcoord);
+bool pmModelLimits_DEV(psMinConstraintMode mode, int nParam, float *params, float *beta);
+bool pmModelGuess_DEV(pmModel *model, pmSource *source);
+psF64 pmModelFlux_DEV(const psVector *params);
+psF64 pmModelRadius_DEV(const psVector *params, psF64 flux);
+bool pmModelFromPSF_DEV(pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf);
+bool  pmModelParamsFromPSF_DEV(pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io);
+bool pmModelFitStatus_DEV(pmModel *model);
+void pmModelSetLimits_DEV(pmModelLimitsType type);
+
+#endif
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_EXP.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_EXP.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_EXP.c	(revision 29060)
@@ -0,0 +1,453 @@
+/******************************************************************************
+ * this file defines the Exponential (EXP) 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:
+
+   f = exp(-sqrt(z)) (since z is r^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
+
+   *****************************************************************************/
+
+#include <stdio.h>
+#include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
+#include "pmModel_EXP.h"
+
+# define PM_MODEL_NPARAM          7
+# define PM_MODEL_FUNC            pmModelFunc_EXP
+# define PM_MODEL_FLUX            pmModelFlux_EXP
+# define PM_MODEL_GUESS           pmModelGuess_EXP
+# define PM_MODEL_LIMITS          pmModelLimits_EXP
+# define PM_MODEL_RADIUS          pmModelRadius_EXP
+# define PM_MODEL_FROM_PSF        pmModelFromPSF_EXP
+# define PM_MODEL_PARAMS_FROM_PSF pmModelParamsFromPSF_EXP
+# define PM_MODEL_FIT_STATUS      pmModelFitStatus_EXP
+# define PM_MODEL_SET_LIMITS      pmModelSetLimits_EXP
+
+// 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 };
+static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0 };
+
+// Moderate parameter limits
+static float *paramsMinModerate = paramsMinLax;
+static float *paramsMaxModerate = paramsMaxLax;
+
+// 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,
+                     const psVector *params,
+                     const psVector *pixcoord)
+{
+    psF32 *PAR = params->data.F32;
+
+    psF32 X  = pixcoord->data.F32[0] - PAR[PM_PAR_XPOS];
+    psF32 Y  = pixcoord->data.F32[1] - PAR[PM_PAR_YPOS];
+    psF32 px = X / PAR[PM_PAR_SXX];
+    psF32 py = Y / PAR[PM_PAR_SYY];
+    psF32 z  = PS_SQR(px) + PS_SQR(py) + PAR[PM_PAR_SXY]*X*Y;
+
+    // XXX if the elliptical contour is defined in valid way, this step should not be required.
+    // other models (like PGAUSS) don't use fractional powers, and thus do not have NaN values
+    // for negative values of z
+    // XXX use an assert here to force the elliptical parameters to be correctly determined
+    // if (z < 0) z = 0;
+    assert (z >= 0);
+
+    psF32 f2 = sqrt(z);
+    psF32 f1 = exp(-f2);
+    psF32 z0 = PAR[PM_PAR_I0]*f1;
+    psF32 f0 = PAR[PM_PAR_SKY] + z0;
+
+    assert (isfinite(f2));
+    assert (isfinite(f1));
+    assert (isfinite(z0));
+    assert (isfinite(f0));
+
+    if (deriv != NULL) {
+        psF32 *dPAR = deriv->data.F32;
+
+        dPAR[PM_PAR_SKY]  = +1.0;
+        dPAR[PM_PAR_I0]   = +f1;
+
+        // gradient is infinite for z = 0; saturate at z = 0.01
+	// z1 is -df/dz (the negative sign is canceled by most of dz/dPAR[i]
+        psF32 z1 = (z < 0.01) ? 0.5*z0/sqrt(0.01) : 0.5*z0/sqrt(z);
+
+	// XXX dampen SXX and SYY as in GAUSS?
+        dPAR[PM_PAR_XPOS] = +1.0*z1*(2.0*px/PAR[PM_PAR_SXX] + Y*PAR[PM_PAR_SXY]);
+        dPAR[PM_PAR_YPOS] = +1.0*z1*(2.0*py/PAR[PM_PAR_SYY] + X*PAR[PM_PAR_SXY]);
+        dPAR[PM_PAR_SXX]  = +2.0*z1*px*px/PAR[PM_PAR_SXX];
+        dPAR[PM_PAR_SYY]  = +2.0*z1*py*py/PAR[PM_PAR_SYY];
+        dPAR[PM_PAR_SXY]  = -1.0*z1*X*Y;
+    }
+    return (f0);
+}
+
+// define the parameter limits
+// AR_MAX is the maximum allowed axis ratio
+// AR_RATIO is ((1-R)/(1+R))^2 where R = AR_MAX^(-2)
+# define AR_MAX 20.0
+# define AR_RATIO 0.99
+bool PM_MODEL_LIMITS (psMinConstraintMode mode, int nParam, float *params, float *beta)
+{
+    if (!limitsApply) {
+        return true;
+    }
+    psAssert(nParam >= 0 && nParam < PM_MODEL_NPARAM, "Parameter index is out of bounds");
+
+    // we need to calculate the limits for SXY specially
+    float q2 = NAN;
+    if (nParam == PM_PAR_SXY) {
+        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*sqrtf(q1);
+    }
+
+    switch (mode) {
+      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");
+    }
+    psAbort("should not reach here");
+    return false;
+}
+
+// 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)
+{
+    pmMoments *moments = source->moments;
+    pmPeak    *peak    = source->peak;
+    psF32     *PAR  = model->params->data.F32;
+
+    psEllipseMoments emoments;
+    emoments.x2 = moments->Mxx;
+    emoments.xy = moments->Mxy;
+    emoments.y2 = moments->Myy;
+
+    // force the axis ratio to be < 20.0
+    psEllipseAxes axes = psEllipseMomentsToAxes (emoments, 20.0);
+
+    if (!isfinite(axes.major)) return false;
+    if (!isfinite(axes.minor)) return false;
+    if (!isfinite(axes.theta)) return false;
+
+    psEllipseShape shape = psEllipseAxesToShape (axes);
+
+    if (!isfinite(shape.sx))  return false;
+    if (!isfinite(shape.sy))  return false;
+    if (!isfinite(shape.sxy)) return false;
+
+    PAR[PM_PAR_SKY]  = 0.0;
+    PAR[PM_PAR_I0]   = peak->flux;
+    PAR[PM_PAR_XPOS] = peak->xf;
+    PAR[PM_PAR_YPOS] = peak->yf;
+    PAR[PM_PAR_SXX]  = PS_MAX(0.5, M_SQRT2*shape.sx);
+    PAR[PM_PAR_SYY]  = PS_MAX(0.5, M_SQRT2*shape.sy);
+    PAR[PM_PAR_SXY]  = shape.sxy;
+    return(true);
+}
+
+psF64 PM_MODEL_FLUX (const psVector *params)
+{
+    float z, norm;
+    psEllipseShape shape;
+
+    psF32 *PAR = params->data.F32;
+
+    shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
+    shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
+    shape.sxy = PAR[PM_PAR_SXY];
+
+    // Area is equivalent to 2 pi sigma^2
+    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
+    psF64 Area = 2.0 * M_PI * axes.major * axes.minor;
+
+    // the area needs to be multiplied by the integral of f(z) = exp(-sqrt(z)) [0 to infinity]
+    norm = 0.0;
+
+    # define DZ 0.25
+
+    float f0 = 1.0;
+    float f1, f2;
+    for (z = DZ; z < 50; z += DZ) {
+        f1 = exp(-sqrt(z));
+        z += DZ;
+        f2 = exp(-sqrt(z));
+        norm += f0 + 4*f1 + f2;
+        f0 = f2;
+    }
+    norm *= DZ / 3.0;
+
+    psF64 Flux = PAR[PM_PAR_I0] * Area * norm;
+
+    return(Flux);
+}
+
+// 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)
+{
+    psEllipseShape shape;
+
+    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);
+
+    shape.sx  = PAR[PM_PAR_SXX] / M_SQRT2;
+    shape.sy  = PAR[PM_PAR_SYY] / M_SQRT2;
+    shape.sxy = PAR[PM_PAR_SXY];
+
+    psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
+
+    // f = Io exp(-sqrt(z)) -> sqrt(z) = ln(Io/f)
+    psF64 zn = log(PAR[PM_PAR_I0] / flux);
+    psF64 radius = axes.major * sqrt (2.0) * zn;
+
+    psAssert (isfinite(radius), "fix this code: z should not be nan for %f", PAR[PM_PAR_7]);
+    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;
+
+    // we require these two parameters to exist
+    assert (psf->params->n > PM_PAR_YPOS);
+    assert (psf->params->n > PM_PAR_XPOS);
+
+    for (int i = 0; i < psf->params->n; i++) {
+        if (psf->params->data[i] == NULL) {
+            out[i] = in[i];
+        } else {
+            pmTrend2D *trend = psf->params->data[i];
+            out[i] = pmTrend2DEval(trend, in[PM_PAR_XPOS], in[PM_PAR_YPOS]);
+        }
+    }
+
+    // the 2D PSF model fits polarization terms (E0,E1,E2)
+    // convert to shape terms (SXX,SYY,SXY)
+    if (!pmPSF_FitToModel (out, 0.1)) {
+        psTrace("psModules.objects", 5, "Failed to fit object at (r,c) = (%.1f,%.1f)", in[PM_PAR_YPOS], in[PM_PAR_XPOS]);
+        return false;
+    }
+
+    // apply the model limits here: this truncates excessive extrapolation
+    // XXX do we need to do this still?  should we put in asserts to test?
+    for (int i = 0; i < psf->params->n; i++) {
+        // apply the limits to all components or just the psf-model parameters?
+        if (psf->params->data[i] == NULL)
+            continue;
+
+        bool status = true;
+        status &= PM_MODEL_LIMITS(PS_MINIMIZE_PARAM_MIN, i, out, NULL);
+        status &= PM_MODEL_LIMITS(PS_MINIMIZE_PARAM_MAX, i, out, NULL);
+        if (!status) {
+            psTrace ("psModules.objects", 5, "Hitting parameter limits at (r,c) = (%.1f, %.1f)",
+                     in[PM_PAR_XPOS], in[PM_PAR_YPOS]);
+            modelPSF->flags |= PM_MODEL_STATUS_LIMITS;
+        }
+    }
+
+    return true;
+}
+
+// construct the PSF model from the FLT model and the psf
+// XXX is this sufficiently general do be a global function, not a pmModelClass function?
+bool PM_MODEL_PARAMS_FROM_PSF (pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io)
+{
+    psF32 *PAR = model->params->data.F32;
+
+    // we require these two parameters to exist
+    assert (psf->params->n > PM_PAR_YPOS);
+    assert (psf->params->n > PM_PAR_XPOS);
+
+    PAR[PM_PAR_SKY]  = 0.0;
+    PAR[PM_PAR_I0]   = Io;
+    PAR[PM_PAR_XPOS] = Xo;
+    PAR[PM_PAR_YPOS] = Yo;
+
+    // supply the model-fitted parameters, or copy from the input
+    for (int i = 0; i < psf->params->n; i++) {
+        if (i == PM_PAR_SKY) continue;
+        if (i == PM_PAR_I0) continue;
+        if (i == PM_PAR_XPOS) continue;
+        if (i == PM_PAR_YPOS) continue;
+        pmTrend2D *trend = psf->params->data[i];
+        PAR[i] = pmTrend2DEval(trend, Xo, Yo);
+    }
+
+    // the 2D PSF model fits polarization terms (E0,E1,E2)
+    // convert to shape terms (SXX,SYY,SXY)
+    // XXX user-defined value for limit?
+    if (!pmPSF_FitToModel (PAR, 0.1)) {
+        psTrace ("psModules.objects", 3, "Failed to fit object at (r,c) = (%.1f,%.1f)", Xo, Yo);
+        return false;
+    }
+
+    // apply the model limits here: this truncates excessive extrapolation
+    // XXX do we need to do this still?  should we put in asserts to test?
+    for (int i = 0; i < psf->params->n; i++) {
+        // apply the limits to all components or just the psf-model parameters?
+        if (psf->params->data[i] == NULL)
+            continue;
+
+        bool status = true;
+        status &= PM_MODEL_LIMITS (PS_MINIMIZE_PARAM_MIN, i, PAR, NULL);
+        status &= PM_MODEL_LIMITS (PS_MINIMIZE_PARAM_MAX, i, PAR, NULL);
+        if (!status) {
+            psTrace ("psModules.objects", 5, "Hitting parameter limits at (r,c) = (%.1f, %.1f)", Xo, Yo);
+            model->flags |= PM_MODEL_STATUS_LIMITS;
+        }
+    }
+    return(true);
+}
+
+bool PM_MODEL_FIT_STATUS (pmModel *model)
+{
+    bool  status;
+
+    psF32 *PAR  = model->params->data.F32;
+    psF32 *dPAR = model->dparams->data.F32;
+
+    status = true;
+    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_MODERATE:
+        paramsMinUse = paramsMinModerate;
+        paramsMaxUse = paramsMaxModerate;
+        limitsApply = true;
+        break;
+      case PM_MODEL_LIMITS_STRICT:
+        paramsMinUse = paramsMinStrict;
+        paramsMaxUse = paramsMaxStrict;
+        limitsApply = true;
+        break;
+      default:
+        psAbort("Unrecognised model limits type: %x", type);
+    }
+    return;
+}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_EXP.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_EXP.h	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_EXP.h	(revision 29060)
@@ -0,0 +1,15 @@
+#ifndef PM_MODEL_EXP_H
+
+#include "pmModel.h"
+
+psF32 pmModelFunc_EXP(psVector *deriv, const psVector *params, const psVector *pixcoord);
+bool pmModelLimits_EXP(psMinConstraintMode mode, int nParam, float *params, float *beta);
+bool pmModelGuess_EXP(pmModel *model, pmSource *source);
+psF64 pmModelFlux_EXP(const psVector *params);
+psF64 pmModelRadius_EXP(const psVector *params, psF64 flux);
+bool pmModelFromPSF_EXP(pmModel *modelPSF, pmModel *modelFLT, const pmPSF *psf);
+bool  pmModelParamsFromPSF_EXP(pmModel *model, const pmPSF *psf, float Xo, float Yo, float Io);
+bool pmModelFitStatus_EXP(pmModel *model);
+void pmModelSetLimits_EXP(pmModelLimitsType type);
+
+#endif
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_GAUSS.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_GAUSS.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_GAUSS.c	(revision 29060)
@@ -21,11 +21,31 @@
 #include <stdio.h>
 #include <pslib.h>
-
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmPeaks.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmModel.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmModel_GAUSS.h"
 
+# define PM_MODEL_NPARAM          7
 # define PM_MODEL_FUNC            pmModelFunc_GAUSS
 # define PM_MODEL_FLUX            pmModelFlux_GAUSS
@@ -83,4 +103,5 @@
         dPAR[PM_PAR_XPOS] = q*(2*px/PAR[PM_PAR_SXX] + Y*PAR[PM_PAR_SXY]);
         dPAR[PM_PAR_YPOS] = q*(2*py/PAR[PM_PAR_SYY] + X*PAR[PM_PAR_SXY]);
+
         // the extra factor of 2 below is needed to avoid excessive swings
         dPAR[PM_PAR_SXX]  = +4.0*q*px*px/PAR[PM_PAR_SXX];
@@ -102,5 +123,5 @@
         return true;
     }
-    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
+    psAssert(nParam >= 0 && nParam < PM_MODEL_NPARAM, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
@@ -347,4 +368,5 @@
 // this test is invalid if the parameters are derived
 // from the PSF model
+// XXX how is this used?  it prevents forced photometry from ever being 'successful'
 bool PM_MODEL_FIT_STATUS (pmModel *model)
 {
@@ -394,12 +416,2 @@
     return;
 }
-
-# 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_PARAMS_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
-# undef PM_MODEL_SET_LIMITS
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_PGAUSS.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_PGAUSS.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_PGAUSS.c	(revision 29060)
@@ -21,11 +21,31 @@
 #include <stdio.h>
 #include <pslib.h>
-
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmPeaks.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmModel.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmModel_PGAUSS.h"
 
+# define PM_MODEL_NPARAM          7
 # define PM_MODEL_FUNC            pmModelFunc_PGAUSS
 # define PM_MODEL_FLUX            pmModelFlux_PGAUSS
@@ -103,5 +123,5 @@
         return true;
     }
-    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
+    psAssert(nParam >= 0 && nParam < PM_MODEL_NPARAM, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
@@ -448,12 +468,2 @@
     return;
 }
-
-# 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_PARAMS_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
-# undef PM_MODEL_SET_LIMITS
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_PS1_V1.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_PS1_V1.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_PS1_V1.c	(revision 29060)
@@ -22,11 +22,31 @@
 #include <stdio.h>
 #include <pslib.h>
-
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmPeaks.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmModel.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmModel_PS1_V1.h"
 
+# define PM_MODEL_NPARAM          8
 # define PM_MODEL_FUNC            pmModelFunc_PS1_V1
 # define PM_MODEL_FLUX            pmModelFlux_PS1_V1
@@ -122,5 +142,5 @@
         return true;
     }
-    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
+    psAssert(nParam >= 0 && nParam < PM_MODEL_NPARAM, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
@@ -222,5 +242,5 @@
     PAR[PM_PAR_SYY]  = PS_MAX(0.5, M_SQRT2*shape.sy);
     PAR[PM_PAR_SXY]  = shape.sxy;
-    PAR[PM_PAR_7]    = 1.0;
+    PAR[PM_PAR_7]    = 0.5;
 
     return(true);
@@ -468,14 +488,2 @@
     return;
 }
-
-# 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_PARAMS_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
-# undef PM_MODEL_SET_LIMITS
-# undef ALPHA
-# undef ALPHA_M
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_QGAUSS.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_QGAUSS.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_QGAUSS.c	(revision 29060)
@@ -22,11 +22,31 @@
 #include <stdio.h>
 #include <pslib.h>
-
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmPeaks.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmModel.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmModel_QGAUSS.h"
 
+# define PM_MODEL_NPARAM          8
 # define PM_MODEL_FUNC            pmModelFunc_QGAUSS
 # define PM_MODEL_FLUX            pmModelFlux_QGAUSS
@@ -123,5 +143,5 @@
         return true;
     }
-    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
+    psAssert(nParam >= 0 && nParam < PM_MODEL_NPARAM, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
@@ -469,14 +489,2 @@
     return;
 }
-
-# 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_PARAMS_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
-# undef PM_MODEL_SET_LIMITS
-# undef ALPHA
-# undef ALPHA_M
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_RGAUSS.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_RGAUSS.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_RGAUSS.c	(revision 29060)
@@ -22,11 +22,31 @@
 #include <stdio.h>
 #include <pslib.h>
-
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmPeaks.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmModel.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmModel_RGAUSS.h"
 
+# define PM_MODEL_NPARAM          8
 # define PM_MODEL_FUNC            pmModelFunc_RGAUSS
 # define PM_MODEL_FLUX            pmModelFlux_RGAUSS
@@ -112,5 +132,5 @@
         return true;
     }
-    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
+    psAssert(nParam >= 0 && nParam < PM_MODEL_NPARAM, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
@@ -209,8 +229,8 @@
     PAR[PM_PAR_XPOS] = peak->xf;
     PAR[PM_PAR_YPOS] = peak->yf;
-    PAR[PM_PAR_SXX]  = PS_MAX(0.5, M_SQRT2*shape.sx);
-    PAR[PM_PAR_SYY]  = PS_MAX(0.5, M_SQRT2*shape.sy);
+    PAR[PM_PAR_SXX]  = PS_MAX(0.5, shape.sx);
+    PAR[PM_PAR_SYY]  = PS_MAX(0.5, shape.sy);
     PAR[PM_PAR_SXY]  = shape.sxy;
-    PAR[PM_PAR_7]    = 2.25;
+    PAR[PM_PAR_7]    = 1.5;
 
     return(true);
@@ -463,12 +483,2 @@
     return;
 }
-
-# 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_PARAMS_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
-# undef PM_MODEL_SET_LIMITS
Index: /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_SERSIC.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_SERSIC.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/models/pmModel_SERSIC.c	(revision 29060)
@@ -18,5 +18,5 @@
    * PM_PAR_7   7   - normalized sersic parameter
 
-   note that a standard sersic model uses exp(-K*(z^(1/n) - 1).  the additional elements (K,
+   note that a standard sersic model uses exp(-K*(z^(1/2n) - 1).  the additional elements (K,
    the -1 offset) are absorbed in this model by the normalization, the exponent, and the
    radial scale.  We fit the elements in this form, then re-normalize them on output.
@@ -25,11 +25,31 @@
 #include <stdio.h>
 #include <pslib.h>
-
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmPeaks.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmModel.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmModel_SERSIC.h"
 
+# define PM_MODEL_NPARAM          8
 # define PM_MODEL_FUNC            pmModelFunc_SERSIC
 # define PM_MODEL_FLUX            pmModelFlux_SERSIC
@@ -47,5 +67,5 @@
 
 // Lax parameter limits
-static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.05, 0.05, -1.0, 0.05 };
+static float paramsMinLax[] = { -1.0e3, 1.0e-2, -100, -100, 0.001, 0.001, -1.0, 0.05 };
 static float paramsMaxLax[] = { 1.0e5, 1.0e8, 1.0e4, 1.0e4, 100, 100, 1.0, 4.0 };
 
@@ -84,6 +104,10 @@
     assert (z >= 0);
 
-    psF32 f2 = pow(z,PAR[PM_PAR_7]);
-    psF32 f1 = exp(-f2);
+    float index = 0.5 / PAR[PM_PAR_7];
+    float bn = 1.9992*index - 0.3271;
+    float Io = exp(bn);
+
+    psF32 f2 = bn*pow(z,PAR[PM_PAR_7]);
+    psF32 f1 = Io*exp(-f2);
     psF32 z0 = PAR[PM_PAR_I0]*f1;
     psF32 f0 = PAR[PM_PAR_SKY] + z0;
@@ -98,9 +122,10 @@
 
         // gradient is infinite for z = 0; saturate at z = 0.01
-        psF32 z1 = (z < 0.01) ? z0*PAR[PM_PAR_7]*pow(0.01,PAR[PM_PAR_7] - 1.0) : z0*PAR[PM_PAR_7]*pow(z,PAR[PM_PAR_7] - 1.0);
+        psF32 z1 = (z < 0.01) ? z0*bn*PAR[PM_PAR_7]*pow(0.01,PAR[PM_PAR_7] - 1.0) : z0*bn*PAR[PM_PAR_7]*pow(z,PAR[PM_PAR_7] - 1.0);
 
         dPAR[PM_PAR_SKY]  = +1.0;
         dPAR[PM_PAR_I0]   = +f1;
-        dPAR[PM_PAR_7]    = (z == 0.0) ? 0.0 : -z0*f2*log(z);
+        dPAR[PM_PAR_7]    = (z < 0.01) ? -z0*pow(0.01,PAR[PM_PAR_7])*log(0.01) : -z0*f2*log(z);
+	dPAR[PM_PAR_7]   *= 3.0;
 
         assert (isfinite(z1));
@@ -109,7 +134,6 @@
         dPAR[PM_PAR_XPOS] = +1.0*z1*(2.0*px/PAR[PM_PAR_SXX] + Y*PAR[PM_PAR_SXY]);
         dPAR[PM_PAR_YPOS] = +1.0*z1*(2.0*py/PAR[PM_PAR_SYY] + X*PAR[PM_PAR_SXY]);
-        dPAR[PM_PAR_SXX]  = +2.0*z1*px*px/PAR[PM_PAR_SXX];
+        dPAR[PM_PAR_SXX]  = +2.0*z1*px*px/PAR[PM_PAR_SXX]; // XXX : increase drag?
         dPAR[PM_PAR_SYY]  = +2.0*z1*py*py/PAR[PM_PAR_SYY];
-        dPAR[PM_PAR_SXY]  = -1.0*z1*X*Y;
         dPAR[PM_PAR_SXY]  = -1.0*z1*X*Y;
     }
@@ -127,5 +151,5 @@
         return true;
     }
-    psAssert(nParam >= 0 && nParam <= PM_PAR_7, "Parameter index is out of bounds");
+    psAssert(nParam >= 0 && nParam < PM_MODEL_NPARAM, "Parameter index is out of bounds");
 
     // we need to calculate the limits for SXY specially
@@ -201,4 +225,15 @@
     psF32     *PAR  = model->params->data.F32;
 
+    // the other parameters depend on the guess for PAR_7
+    if (!isfinite(PAR[PM_PAR_7])) {
+	PAR[PM_PAR_7]    = 0.25;
+    }    
+    float index = 0.5 / PAR[PM_PAR_7];
+
+    // the scale-length is a function of the moments and the index:
+    // Rmajor_guess = Rmajor_moments * Scale * Zero
+    float Scale = 0.70 + 0.053 * PAR[PM_PAR_7];
+    float Zero  = 1.16 - 0.615 * PAR[PM_PAR_7];
+
     psEllipseMoments emoments;
     emoments.x2 = moments->Mxx;
@@ -213,4 +248,12 @@
     if (!isfinite(axes.theta)) return false;
 
+    // set a lower limit to avoid absurd solutions..
+    float Rmajor = PS_MAX(1.0, Scale * axes.major + Zero);
+    float Rminor = Rmajor * (axes.minor / axes.major);
+
+    // fprintf (stderr, "guess index: %f : %f, %f -> %f, %f\n", index, axes.major, axes.minor, Rmajor, Rminor);
+
+    axes.major = Rmajor;
+    axes.minor = Rminor;
     psEllipseShape shape = psEllipseAxesToShape (axes);
 
@@ -219,12 +262,22 @@
     if (!isfinite(shape.sxy)) return false;
 
+    float bn = 1.9992*index - 0.3271;
+    // float fR = 1.0 / (sqrt(2.0) * pow (bn, index));
+    float Io = exp(0.5*bn);
+
+    // XXX do we need this factor of sqrt(2)?
+    // float Sxx = PS_MAX(0.5, M_SQRT2*shape.sx);
+    // float Syy = PS_MAX(0.5, M_SQRT2*shape.sy);
+
+    float Sxx = PS_MAX(0.5, shape.sx);
+    float Syy = PS_MAX(0.5, shape.sy);
+
     PAR[PM_PAR_SKY]  = 0.0;
-    PAR[PM_PAR_I0]   = peak->flux;
+    PAR[PM_PAR_I0]   = peak->flux / Io;
     PAR[PM_PAR_XPOS] = peak->xf;
     PAR[PM_PAR_YPOS] = peak->yf;
-    PAR[PM_PAR_SXX]  = PS_MAX(0.5, M_SQRT2*shape.sx);
-    PAR[PM_PAR_SYY]  = PS_MAX(0.5, M_SQRT2*shape.sy);
+    PAR[PM_PAR_SXX]  = Sxx;
+    PAR[PM_PAR_SYY]  = Syy;
     PAR[PM_PAR_SXY]  = shape.sxy;
-    PAR[PM_PAR_7]    = 0.5;
 
     return(true);
@@ -254,7 +307,8 @@
     float f1, f2;
     for (z = DZ; z < 50; z += DZ) {
-        f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, 2.25));
+        // f1 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, 2.25));
+	f1 = exp(-pow(z,PAR[PM_PAR_7]));
         z += DZ;
-        f2 = 1.0 / (1 + PAR[PM_PAR_7]*z + pow(z, 2.25));
+	f2 = exp(-pow(z,PAR[PM_PAR_7]));
         norm += f0 + 4*f1 + f2;
         f0 = f2;
@@ -287,17 +341,12 @@
 
     psEllipseAxes axes = psEllipseShapeToAxes (shape, 20.0);
-    psF64 sigma = axes.major;
-
-    psF64 limit = flux / PAR[PM_PAR_I0];
-
-    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))
-        psAbort("error in code: radius is NaN");
-
+
+    // f = Io exp(-z^n) -> z^n = ln(Io/f)
+    psF64 zn = log(PAR[PM_PAR_I0] / flux);
+    psF64 radius = axes.major * sqrt (2.0) * pow(zn, 0.5 / PAR[PM_PAR_7]);
+
+    // fprintf (stderr, "sersic model %f %f, n %f, radius: %f, zn: %f, f/Io: %f, major: %f\n", PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], PAR[PM_PAR_7], radius, zn, flux/PAR[PM_PAR_I0], axes.major);
+
+    psAssert (isfinite(radius), "fix this code: z should not be nan for %f", PAR[PM_PAR_7]);
     return (radius);
 }
@@ -448,12 +497,2 @@
     return;
 }
-
-# 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_PARAMS_FROM_PSF
-# undef PM_MODEL_FIT_STATUS
-# undef PM_MODEL_SET_LIMITS
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmDetEff.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmDetEff.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmDetEff.c	(revision 29060)
@@ -3,8 +3,30 @@
 #endif
 
+#include <string.h>
 #include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
 #include "pmDetEff.h"
-
 
 static void detEffFree(pmDetEff *de)
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmDetEff.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmDetEff.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmDetEff.h	(revision 29060)
@@ -1,9 +1,4 @@
 #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
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprint.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprint.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprint.c	(revision 29060)
@@ -19,4 +19,5 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprint.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprint.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprint.h	(revision 29060)
@@ -10,8 +10,4 @@
 #ifndef PM_FOOTPRINT_H
 #define PM_FOOTPRINT_H
-
-#include <pslib.h>
-#include "pmSpan.h"
-#include "pmFootprintSpans.h"
 
 typedef struct {
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintArrayGrow.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintArrayGrow.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintArrayGrow.c	(revision 29060)
@@ -18,4 +18,5 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintArraysMerge.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintArraysMerge.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintArraysMerge.c	(revision 29060)
@@ -18,4 +18,5 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintAssignPeaks.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintAssignPeaks.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintAssignPeaks.c	(revision 29060)
@@ -18,4 +18,5 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintCullPeaks.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintCullPeaks.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintCullPeaks.c	(revision 29060)
@@ -19,6 +19,6 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
-#include "pmFootprintSpans.h"
 #include "pmPeaks.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintFind.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintFind.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintFind.c	(revision 29060)
@@ -19,4 +19,5 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintFindAtPoint.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintFindAtPoint.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintFindAtPoint.c	(revision 29060)
@@ -19,7 +19,7 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
-#include "pmFootprintSpans.h"
 
 /************************************************************************************************************/
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintIDs.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintIDs.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintIDs.c	(revision 29060)
@@ -19,4 +19,5 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintSpans.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintSpans.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintSpans.c	(revision 29060)
@@ -19,7 +19,7 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
-#include "pmFootprintSpans.h"
 
 static void pmStartSpanFree(pmStartSpan *sspan) {
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintSpans.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintSpans.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmFootprintSpans.h	(revision 29060)
@@ -10,7 +10,4 @@
 #ifndef PM_FOOTPRINT_SPANS_H
 #define PM_FOOTPRINT_SPANS_H
-
-#include <pslib.h>
-#include "pmSpan.h"
 
 /* We define two helper structures used in building the pmFootprints:
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmGrowthCurve.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmGrowthCurve.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmGrowthCurve.c	(revision 29060)
@@ -20,14 +20,26 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "psVectorBracket.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmGrowthCurveGenerate.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmGrowthCurveGenerate.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmGrowthCurveGenerate.c	(revision 29060)
@@ -24,20 +24,30 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "psVectorBracket.h"
+#include "pmErrorCodes.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
-#include "pmModelUtils.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmSourcePhotometry.h"
-#include "pmFPAMaskWeight.h"
-#include "psVectorBracket.h"
-#include "pmErrorCodes.h"
 
 pmGrowthCurve *pmGrowthCurveForPosition (psImage *image, pmPSF *psf, bool ignore, psImageMaskType maskVal, psImageMaskType markVal, float xc, float yc);
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmModel.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmModel.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmModel.c	(revision 29060)
@@ -23,8 +23,14 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+
+#include "pmTrend2D.h"
 #include "pmResiduals.h"
 #include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
 #include "pmModelClass.h"
@@ -75,6 +81,6 @@
 
     for (psS32 i = 0; i < tmp->params->n; i++) {
-        tmp->params->data.F32[i] = 0.0;
-        tmp->dparams->data.F32[i] = 0.0;
+        tmp->params->data.F32[i] = NAN;
+        tmp->dparams->data.F32[i] = NAN;
     }
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmModel.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmModel.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmModel.h	(revision 29060)
@@ -14,7 +14,4 @@
 # define PM_MODEL_H
 
-#include <pslib.h>
-#include "pmPSF.h"
-
 /// @addtogroup Objects Object Detection / Analysis Functions
 /// @{
@@ -22,68 +19,4 @@
 /* pointers for the functions types below are supplied to each pmModel, and can be used by
    the programmer without needing to know the model class */
-
-typedef enum {
-    PM_MODEL_STATUS_NONE         = 0x00, ///< model fit not yet attempted, no other info
-    PM_MODEL_STATUS_FITTED       = 0x01, ///< model fit completed
-    PM_MODEL_STATUS_NONCONVERGE  = 0x02, ///< model fit did not converge
-    PM_MODEL_STATUS_OFFIMAGE     = 0x04, ///< model fit drove out of range
-    PM_MODEL_STATUS_BADARGS      = 0x08, ///< model fit called with invalid args
-    PM_MODEL_STATUS_LIMITS       = 0x10  ///< model parameters hit limits
-} pmModelStatus;
-
-typedef enum {
-    PM_MODEL_OP_NONE    = 0x00,
-    PM_MODEL_OP_FUNC    = 0x01,
-    PM_MODEL_OP_RES0    = 0x02,
-    PM_MODEL_OP_RES1    = 0x04,
-    PM_MODEL_OP_FULL    = 0x07,
-    PM_MODEL_OP_SKY     = 0x08,
-    PM_MODEL_OP_CENTER  = 0x10,
-    PM_MODEL_OP_NORM    = 0x20,
-    PM_MODEL_OP_NOISE   = 0x40,
-} 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 even bad data
-    PM_MODEL_LIMITS_MODERATE,           ///< Moderate limits: cope with mildly bad data
-    PM_MODEL_LIMITS_STRICT,             ///< Strict limits: insist on good quality data
-} pmModelLimitsType;
-
-typedef struct pmModel pmModel;
-typedef struct pmSource pmSource;
-
-//  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, const pmPSF *psf);
-
-//  This function sets the model parameters based on the PSF for a given coordinate and central
-//  intensity
-typedef bool (*pmModelParamsFromPSF)(pmModel *model, const 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);
-
-//  This function sets the parameter limits for the given model
-typedef bool (*pmModelSetLimitsFunc)(pmModelLimitsType type);
 
 /** pmModel data structure
@@ -122,18 +55,4 @@
     pmModelSetLimitsFunc modelSetLimits;
 };
-
-/** Symbolic names for the elements of [d]params
- * Note: these are #defines not enums as a given element of [d]params
- * may/will correspond to different parameters in different contexts
- */
-#define PM_PAR_SKY 0   ///< Sky
-#define PM_PAR_I0 1   ///< Central intensity
-#define PM_PAR_XPOS 2   ///< X centre of object
-#define PM_PAR_YPOS 3   ///< Y centre of object
-#define PM_PAR_SXX 4   ///< shape X^2 moment
-#define PM_PAR_SYY 5   ///< shape Y^2 moment
-#define PM_PAR_SXY 6   ///< shape XY moment
-#define PM_PAR_7 7   ///< ??? Unknown parameter
-#define PM_PAR_8 8   ///< ??? Unknown parameter
 
 /** pmModelAlloc()
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmModelClass.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmModelClass.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmModelClass.c	(revision 29060)
@@ -23,15 +23,18 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
-#include "pmSource.h"
+#include "pmModelUtils.h"
 #include "pmModelClass.h"
+
 #include "pmErrorCodes.h"
 
@@ -46,4 +49,6 @@
 # include "models/pmModel_RGAUSS.h"
 # include "models/pmModel_SERSIC.h"
+# include "models/pmModel_EXP.h"
+# include "models/pmModel_DEV.h"
 
 static pmModelClass defaultModels[] = {
@@ -53,5 +58,7 @@
     {"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 }
+    {"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 },
+    {"PS_MODEL_EXP",          7, (pmModelFunc)pmModelFunc_EXP,     (pmModelFlux)pmModelFlux_EXP,     (pmModelRadius)pmModelRadius_EXP,     (pmModelLimits)pmModelLimits_EXP,     (pmModelGuessFunc)pmModelGuess_EXP,    (pmModelFromPSFFunc)pmModelFromPSF_EXP,    (pmModelParamsFromPSF)pmModelParamsFromPSF_EXP,    (pmModelFitStatusFunc)pmModelFitStatus_EXP,    (pmModelSetLimitsFunc)pmModelSetLimits_EXP },
+    {"PS_MODEL_DEV",          7, (pmModelFunc)pmModelFunc_DEV,     (pmModelFlux)pmModelFlux_DEV,     (pmModelRadius)pmModelRadius_DEV,     (pmModelLimits)pmModelLimits_DEV,     (pmModelGuessFunc)pmModelGuess_DEV,    (pmModelFromPSFFunc)pmModelFromPSF_DEV,    (pmModelParamsFromPSF)pmModelParamsFromPSF_DEV,    (pmModelFitStatusFunc)pmModelFitStatus_DEV,    (pmModelSetLimitsFunc)pmModelSetLimits_DEV },
 };
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmModelClass.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmModelClass.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmModelClass.h	(revision 29060)
@@ -28,6 +28,4 @@
 # ifndef PM_MODEL_CLASS_H
 # define PM_MODEL_CLASS_H
-
-#include <pmModel.h>
 
 /// @addtogroup Objects Object Detection / Analysis Functions
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmModelFuncs.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmModelFuncs.h	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmModelFuncs.h	(revision 29060)
@@ -0,0 +1,120 @@
+/* @file  pmModelClass.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 These
+ * functions allow the programmer to select the approriate function or property for a
+ * specific object model class.
+ *
+ * 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.4 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-11-27 03:14:57 $
+ * Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ */
+
+# ifndef PM_MODEL_FUNCS_H
+# define PM_MODEL_FUNCS_H
+
+/// @addtogroup Objects Object Detection / Analysis Functions
+/// @{
+
+// type of model carried by the pmModel structure
+typedef int pmModelType;
+
+typedef enum {
+    PM_MODEL_STATUS_NONE         = 0x00, ///< model fit not yet attempted, no other info
+    PM_MODEL_STATUS_FITTED       = 0x01, ///< model fit completed
+    PM_MODEL_STATUS_NONCONVERGE  = 0x02, ///< model fit did not converge
+    PM_MODEL_STATUS_OFFIMAGE     = 0x04, ///< model fit drove out of range
+    PM_MODEL_STATUS_BADARGS      = 0x08, ///< model fit called with invalid args
+    PM_MODEL_STATUS_LIMITS       = 0x10, ///< model parameters hit limits
+    PM_MODEL_STATUS_WEAK_FIT     = 0x20, ///< model fit met loose tolerance, but not tight tolerance
+} pmModelStatus;
+
+typedef enum {
+    PM_MODEL_OP_NONE    = 0x00,
+    PM_MODEL_OP_FUNC    = 0x01,
+    PM_MODEL_OP_RES0    = 0x02,
+    PM_MODEL_OP_RES1    = 0x04,
+    PM_MODEL_OP_FULL    = 0x07,
+    PM_MODEL_OP_SKY     = 0x08,
+    PM_MODEL_OP_CENTER  = 0x10,
+    PM_MODEL_OP_NORM    = 0x20,
+    PM_MODEL_OP_NOISE   = 0x40,
+} 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 even bad data
+    PM_MODEL_LIMITS_MODERATE,           ///< Moderate limits: cope with mildly bad data
+    PM_MODEL_LIMITS_STRICT,             ///< Strict limits: insist on good quality data
+} pmModelLimitsType;
+
+/** Symbolic names for the elements of [d]params
+ * Note: these are #defines not enums as a given element of [d]params
+ * may/will correspond to different parameters in different contexts
+ */
+#define PM_PAR_SKY  0   ///< Sky
+#define PM_PAR_I0   1   ///< Central intensity
+#define PM_PAR_XPOS 2   ///< X center of object
+#define PM_PAR_YPOS 3   ///< Y center of object
+#define PM_PAR_SXX  4   ///< shape X^2 moment
+#define PM_PAR_SYY  5   ///< shape Y^2 moment
+#define PM_PAR_SXY  6   ///< shape XY moment
+#define PM_PAR_7    7   ///< Model-dependent parameter
+#define PM_PAR_8    8   ///< Model-dependent parameter
+
+/*** these prototype classes are used to define elements of the pmModelClass structure below ***/
+ 
+typedef struct pmModel  pmModel;
+typedef struct pmSource pmSource;
+typedef struct pmPSF    pmPSF;
+
+//  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, const pmPSF *psf);
+
+//  This function sets the model parameters based on the PSF for a given coordinate and central
+//  intensity
+typedef bool (*pmModelParamsFromPSF)(pmModel *model, const 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);
+
+//  This function sets the parameter limits for the given model
+typedef bool (*pmModelSetLimitsFunc)(pmModelLimitsType type);
+
+/// @}
+# endif /* PM_MODEL_FUNCS_H */
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmModelUtils.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmModelUtils.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmModelUtils.c	(revision 29060)
@@ -22,11 +22,25 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+
+#include "pmTrend2D.h"
 #include "pmResiduals.h"
 #include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
+
 #include "pmErrorCodes.h"
-#include "pmModelUtils.h"
 
 /*****************************************************************************
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmMoments.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmMoments.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmMoments.c	(revision 29060)
@@ -29,4 +29,13 @@
     psTrace("psModules.objects", 10, "---- %s() begin ----\n", __func__);
     pmMoments *tmp = (pmMoments *) psAlloc(sizeof(pmMoments));
+
+    tmp->Mrf = 0.0;
+    tmp->Mrh = 0.0;
+    tmp->KronFlux = 0.0;
+    tmp->KronFluxErr = 0.0;
+
+    tmp->KronFinner = 0.0;
+    tmp->KronFouter = 0.0;
+
     tmp->Mx = 0.0;
     tmp->My = 0.0;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmMoments.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmMoments.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmMoments.h	(revision 29060)
@@ -24,4 +24,7 @@
 typedef struct
 {
+    float Mrf;    ///< radial first moment
+    float Mrh;    ///< radial half moment
+
     float Mx;     ///< X-coord of centroid.
     float My;     ///< Y-coord of centroid.
@@ -47,4 +50,11 @@
     float SN;     ///< approx signal-to-noise
     int nPixels;  ///< Number of pixels used.
+
+    float KronFlux;    ///< Kron flux (flux in 2.5*Mrf)
+    float KronFluxErr; ///< Kron flux error
+
+    float KronFinner;    ///< Kron flux (flux in 2.5*Mrf)
+    float KronFouter;    ///< Kron flux (flux in 2.5*Mrf)
+
 }
 pmMoments;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPCM_MinimizeChisq.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPCM_MinimizeChisq.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPCM_MinimizeChisq.c	(revision 29060)
@@ -0,0 +1,447 @@
+/* @file  pmPCM_MinimizeChisq.c
+ * structures and functions to support PSF-convolved model fitting
+ *
+ * @author EAM, IfA
+ *
+ * @version $Revision: 1.29 $
+ * @date $Date: 2009-02-16 22:30:50 $
+ * Copyright 2010 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <strings.h>
+#include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPCMdata.h"
+
+# define FACILITY "psModules.objects"
+
+# define USE_FFT 1
+# define PRE_CONVOLVE 1
+
+bool pmPCM_MinimizeChisq (
+    psMinimization *min,
+    psImage *covar,
+    psVector *params,
+    pmSource *source,
+    pmPCMdata *pcm)
+{
+    psTrace(FACILITY, 3, "---- begin ----\n");
+    PS_ASSERT_PTR_NON_NULL(min, false);
+    PS_ASSERT_VECTOR_NON_NULL(params, false);
+    PS_ASSERT_VECTOR_NON_EMPTY(params, false);
+    PS_ASSERT_VECTOR_TYPE(params, PS_TYPE_F32, false);
+    PS_ASSERT_PTR_NON_NULL(source, false);
+    PS_ASSERT_PTR_NON_NULL(pcm, false);
+    PS_ASSERT_VECTOR_TYPE(pcm->constraint->paramMask, PS_TYPE_VECTOR_MASK, false);
+    PS_ASSERT_VECTORS_SIZE_EQUAL(params, pcm->constraint->paramMask, false);
+
+    psVector *paramMask = pcm->constraint->paramMask;
+
+    psMinimizeLMLimitFunc checkLimits = pcm->constraint->checkLimits;
+
+    // this function has test values and current values for several things
+    // the current value is in lower case
+    // the test value is in upper case
+
+    // allocate internal arrays (current vs Guess)
+    psImage *Alpha = NULL;
+    psVector *Beta = NULL;
+
+    // Alpha & Beta only contain elements to represent the unmasked parameters
+    if (!psMinLM_AllocAB (&Alpha, &Beta, params, paramMask)) {
+        psAbort ("programming error: no unmasked parameters to be fit\n");
+    }
+
+    // allocate internal arrays (current vs Guess)
+    psImage *alpha   = psImageAlloc(Alpha->numCols, Alpha->numRows, PS_TYPE_F32);
+    psVector *beta   = psVectorAlloc(Beta->n, PS_TYPE_F32);
+    psVector *Params = psVectorAlloc(params->n, PS_TYPE_F32);
+
+    psF32 Chisq = 0.0;
+    psF32 lambda = 0.001;
+    psF32 dLinear = 0.0;
+
+# if (USE_FFT && PRE_CONVOLVE)
+    if (pcm->psfFFT) {
+	psFree (pcm->psfFFT);
+    }
+    pcm->psfFFT = psImageConvolveKernelInit(pcm->modelFlux, pcm->psf);
+# endif    
+
+    // calculate initial alpha and beta, set chisq (min->value)
+    min->value = pmPCM_SetABX(alpha, beta, params, paramMask, pcm, source);
+    if (isnan(min->value)) {
+        min->iter = min->maxIter;
+        return(false);
+    }
+    // dump some useful info if trace is defined
+    if (psTraceGetLevel(FACILITY) >= 6) {
+        p_psImagePrint(psTraceGetDestination(), alpha, "alpha guess (0)");
+        p_psVectorPrint(psTraceGetDestination(), beta, "beta guess (0)");
+    }
+    if (psTraceGetLevel(FACILITY) >= 5) {
+        p_psVectorPrint(psTraceGetDestination(), params, "params guess (0)");
+    }
+
+    // iterate until the tolerance is reached, or give up
+    bool done = (min->iter >= min->maxIter);
+    while (!done) {
+        psTrace("psModules.objects", 5, "Iteration number %d.  (max iterations is %d).\n", min->iter, min->maxIter);
+        psTrace("psModules.objects", 5, "Last delta is %f.  stop if < %f, accept if < %f\n", min->lastDelta, min->minTol, min->maxTol);
+
+        // set a new guess for Alpha, Beta, Params
+        if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, checkLimits, lambda, &dLinear)) {
+            min->iter ++;
+	    if (min->iter >=  min->maxIter) break;
+            lambda *= 10.0;
+            continue;
+        }
+
+        // dump some useful info if trace is defined
+        if (psTraceGetLevel(FACILITY) >= 6) {
+            p_psImagePrint(psTraceGetDestination(), Alpha, "Alpha guess (1)");
+            p_psVectorPrint(psTraceGetDestination(), Beta, "Beta guess (1)");
+            p_psVectorPrint(psTraceGetDestination(), beta, "beta current (1)");
+        }
+        if (psTraceGetLevel(FACILITY) >= 5) {
+            p_psVectorPrint(psTraceGetDestination(), Params, "params guess (1)");
+        }
+
+        // calculate Chisq for new guess, update Alpha & Beta
+        Chisq = pmPCM_SetABX(Alpha, Beta, Params, paramMask, pcm, source);
+        if (isnan(Chisq)) {
+            min->iter ++;
+	    if (min->iter >=  min->maxIter) break;
+            lambda *= 10.0;
+            continue;
+        }
+
+        // convergence criterion:
+        // compare the delta (min->value - Chisq) with the
+        // expected delta from the linear model (dLinear)
+        // accept new guess if it is an improvement (rho > 0), or else increase lambda
+        psF32 rho = (min->value - Chisq) / dLinear;
+
+        psTrace(FACILITY, 5, "last chisq: %f, new chisq %f, delta: %f, rho: %f\n", min->value, Chisq, min->lastDelta, rho);
+
+        // dump some useful info if trace is defined
+        if (psTraceGetLevel(FACILITY) >= 6) {
+            p_psImagePrint(psTraceGetDestination(), Alpha, "alpha guess (2)");
+            p_psVectorPrint(psTraceGetDestination(), Beta, "beta guess (2)");
+        }
+
+        /* if (Chisq < min->value) {  */
+        if (rho >= -1e-6) {
+            min->lastDelta = (min->value - Chisq) / (source->pixels->numCols*source->pixels->numRows - params->n);
+            min->value = Chisq;
+            alpha  = psImageCopy(alpha, Alpha, PS_TYPE_F32);
+            beta   = psVectorCopy(beta, Beta, PS_TYPE_F32);
+            params = psVectorCopy(params, Params, PS_TYPE_F32);
+            lambda *= 0.25;
+
+            // save the new convolved model image
+            psFree (source->modelFlux);
+            source->modelFlux = pmPCMdataSaveImage(pcm);
+        } else {
+            lambda *= 10.0;
+        }
+        min->iter++;
+
+	done = (min->iter >= min->maxIter);
+	
+	// check for convergence:
+	float chisqDOF = Chisq / pcm->nDOF;
+	if (!isfinite(min->maxChisqDOF) || ((chisqDOF < min->maxChisqDOF) && isfinite(min->lastDelta))) {
+	    done |= (min->lastDelta < min->minTol);
+	}
+    }
+    psTrace(FACILITY, 5, "chisq: %f, last delta: %f, Niter: %d\n", min->value, min->lastDelta, min->iter);
+
+    // construct & return the covariance matrix (if requested)
+    if (covar != NULL) {
+        if (!psMinLM_GuessABP(Alpha, Beta, Params, alpha, beta, params, paramMask, NULL, 0.0, NULL)) {
+            psTrace (FACILITY, 5, "failure to calculate covariance matrix\n");
+        }
+        // set covar values which are not masked
+        psImageInit (covar, 0.0);
+        for (int j = 0, J = 0; j < params->n; j++) {
+            if (paramMask && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[j])) {
+                covar->data.F32[j][j] = 1.0;
+                continue;
+            }
+            for (int k = 0, K = 0; k < params->n; k++) {
+                if (paramMask && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[k])) continue;
+                covar->data.F32[j][k] = Alpha->data.F32[J][K];
+                K++;
+            }
+            J++;
+        }
+    }
+
+    // free the internal temporary data
+    psFree(alpha);
+    psFree(Alpha);
+    psFree(beta);
+    psFree(Beta);
+    psFree(Params);
+
+    // if the last improvement was at least as good as maxTol, accept the fit:
+    if (min->lastDelta <= min->maxTol) {
+	psTrace(FACILITY, 6, "---- end (true) ----\n");
+        return(true);
+    }
+    psTrace(FACILITY, 6, "---- end (false) ----\n");
+    return(false);
+}
+
+psF32 pmPCM_SetABX(
+    psImage  *alpha,
+    psVector *beta,
+    const psVector *params,
+    const psVector *paramMask,
+    pmPCMdata *pcm,
+    const pmSource *source)
+{
+    // XXX: Check vector sizes.
+    PS_ASSERT_IMAGE_NON_NULL(alpha, NAN);
+    PS_ASSERT_VECTOR_NON_NULL(beta, NAN);
+    PS_ASSERT_VECTOR_NON_NULL(params, NAN);
+
+    PS_ASSERT_PTR_NON_NULL(source, NAN);
+    PS_ASSERT_IMAGE_NON_NULL(source->pixels, NAN);
+    PS_ASSERT_IMAGE_NON_NULL(source->variance, NAN);
+    PS_ASSERT_IMAGE_NON_NULL(source->maskObj, NAN);
+
+    PS_ASSERT_VECTOR_TYPE(params, PS_TYPE_F32, false);
+    if (paramMask) {
+        PS_ASSERT_VECTOR_TYPE(paramMask, PS_TYPE_VECTOR_MASK, false);
+    }
+
+    // 1 *** generate the model and derivative images for this parameter set
+
+    // storage for model derivatives
+    psVector *deriv = psVectorAlloc(params->n, PS_TYPE_F32);
+
+    // working vector to store local coordinate
+    psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
+
+    psImageInit (pcm->modelFlux, 0.0);
+    for (int n = 0; n < params->n; n++) {
+        if (!pcm->dmodelsFlux->data[n]) continue;
+        psImageInit (pcm->dmodelsFlux->data[n], 0.0);
+    }
+
+    // fill in the coordinate and value entries
+    for (psS32 i = 0; i < source->pixels->numRows; i++) {
+        for (psS32 j = 0; j < source->pixels->numCols; j++) {
+
+            // XXX can we skip some of the data points where the model
+            // is not going to be fitted??
+
+            // skip masked points
+            // XXX probably should not skipped masked points:
+            // XXX skip if convolution of unmasked pixels will not see this pixel
+            // if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[i][j]) {
+            // continue;
+            // }
+
+            // skip zero-variance points
+            // XXX why is this not masked?
+            // if (source->variance->data.F32[i][j] == 0) {
+            // continue;
+            // }
+            // skip nan value points
+            // XXX why is this not masked?
+            // if (!isfinite(source->pixels->data.F32[i][j])) {
+            // continue;
+            // }
+
+            // Convert i/j to image space:
+            coord->data.F32[0] = (psF32) (j + source->pixels->col0);
+            coord->data.F32[1] = (psF32) (i + source->pixels->row0);
+
+            pcm->modelFlux->data.F32[i][j] = pcm->modelConv->modelFunc (deriv, params, coord);
+
+            for (int n = 0; n < params->n; n++) {
+                if ((paramMask != NULL) && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n])) { continue; }
+                psImage *dmodel = pcm->dmodelsFlux->data[n];
+                dmodel->data.F32[i][j] = deriv->data.F32[n];
+            }
+        }
+    }
+    psFree(coord);
+    psFree(deriv);
+
+    // convolve model and dmodel arrays with PSF
+    // XXX speed this up by saving the FFTed psf (for each source, obviously)
+
+    // XXX save the FFT'ed psf
+    // XXX create an alternative function which takes a pre-FFTed kernel
+
+# if (USE_FFT)
+# if (PRE_CONVOLVE)
+    // convolve model image and derivative images with pre-convolved kernel
+    psImageConvolveKernel (pcm->modelConvFlux, pcm->modelFlux, NULL, 0, pcm->psfFFT);
+    for (int n = 0; n < pcm->dmodelsFlux->n; n++) {
+        if (pcm->dmodelsFlux->data[n] == NULL) continue;
+	if (pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n]) continue;
+        psImage *dmodel = pcm->dmodelsFlux->data[n];
+        psImage *dmodelConv = pcm->dmodelsConvFlux->data[n];
+        psImageConvolveKernel (dmodelConv, dmodel, NULL, 0, pcm->psfFFT);
+    }
+# else
+    // convolve model image and derivative images with psf via FFT
+    psImageConvolveFFT (pcm->modelConvFlux, pcm->modelFlux, NULL, 0, pcm->psf);
+    for (int n = 0; n < pcm->dmodelsFlux->n; n++) {
+        if (pcm->dmodelsFlux->data[n] == NULL) continue;
+	if (pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n]) continue;
+        psImage *dmodel = pcm->dmodelsFlux->data[n];
+        psImage *dmodelConv = pcm->dmodelsConvFlux->data[n];
+        psImageConvolveFFT (dmodelConv, dmodel, NULL, 0, pcm->psf);
+    }
+# endif // PRE-CONVOLVE
+# else
+    // convolve model image and derivative images with psf direct
+    psImageConvolveDirect (pcm->modelConvFlux, pcm->modelFlux, pcm->psf);
+    for (int n = 0; n < pcm->dmodelsFlux->n; n++) {
+        if (pcm->dmodelsFlux->data[n] == NULL) continue;
+	if (pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n]) continue;
+        psImage *dmodel = pcm->dmodelsFlux->data[n];
+        psImage *dmodelConv = pcm->dmodelsConvFlux->data[n];
+        psImageConvolveDirect (dmodelConv, dmodel, pcm->psf);
+    }
+# endif // USE_FFT
+
+    // XXX TEST : SAVE IMAGES
+# if (SAVE_IMAGES)
+    psphotSaveImage (NULL, pcm->psf->image, "psf.fits");
+    psphotSaveImage (NULL, pcm->modelFlux, "model.fits");
+    psphotSaveImage (NULL, pcm->modelConvFlux, "modelConv.fits");
+    psphotSaveImage (NULL, source->pixels, "obj.fits");
+    psphotSaveImage (NULL, source->maskObj, "mask.fits");
+    psphotSaveImage (NULL, source->variance, "variance.fits");
+# endif
+
+    // 2 *** accumulate alpha & beta
+
+    // zero alpha and beta for summing below
+    psImageInit (alpha, 0.0);
+    psVectorInit (beta, 0.0);
+    float chisq = 0.0;
+
+    for (psS32 i = 0; i < source->pixels->numRows; i++) {
+        for (psS32 j = 0; j < source->pixels->numCols; j++) {
+            // XXX are we doing the right thing with the mask?
+            // skip masked points
+            if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[i][j]) {
+                continue;
+            }
+            // skip zero-variance points
+            if (source->variance->data.F32[i][j] == 0) {
+                continue;
+            }
+            // skip nan value points
+            if (!isfinite(source->pixels->data.F32[i][j])) {
+                continue;
+            }
+
+            float ymodel  = pcm->modelConvFlux->data.F32[i][j];
+            float yweight = 1.0 / source->variance->data.F32[i][j];
+            float delta = ymodel - source->pixels->data.F32[i][j];
+
+            chisq += PS_SQR(delta) * yweight;
+
+            if (isnan(delta)) psAbort("nan in delta");
+            if (isnan(chisq)) psAbort("nan in chisq");
+
+            // alpha & beta only contain unmasked elements
+            for (int n1 = 0, N1 = 0; n1 < params->n; n1++) {
+                if ((paramMask != NULL) && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n1])) continue;
+                psImage *dmodel = pcm->dmodelsConvFlux->data[n1];
+                float weight = dmodel->data.F32[i][j] * yweight;
+                for (int n2 = 0, N2 = 0; n2 <= n1; n2++) {
+                    if ((paramMask != NULL) && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n2])) continue;
+                    dmodel = pcm->dmodelsConvFlux->data[n2];
+                    alpha->data.F32[N1][N2] += weight * dmodel->data.F32[i][j];
+                    N2++;
+                }
+                beta->data.F32[N1] += weight * delta;
+                N1++;
+            }
+        }
+    }
+
+    // calculate lower-left half of alpha
+    for (psS32 j = 1; j < alpha->numCols; j++) {
+        for (psS32 k = 0; k < j; k++) {
+            alpha->data.F32[k][j] = alpha->data.F32[j][k];
+        }
+    }
+
+    return(chisq);
+}
+
+
+/*
+ *
+ * we have a function func(param; value)
+
+ * basic LMM:
+
+ - fill in the data (x, y)
+
+ chisq = SetABX (alpha, beta, params, paramMask, x, y, dy, func)
+
+ while () {
+ GuessABP (Alpha, Beta, Params, alpha, beta, params, paramMask, checkLimits, lambda)
+ dLinear = dLinear(Beta, beta, lambda);
+ chisq = SetABX (alpha, beta, params, paramMask, x, y, dy, func)
+ convergence tests...
+ }
+
+
+
+ ** GuessABP:
+
+ f_c = sum_i (kern_i * func (x_i; p_o))
+
+ df_c/dp_o = d/dp_o [sum_i (kern_i * func (x_i; p_o))]
+
+ df_c/dp_o = sum_i (d/dp_o [kern_i * func (x_i; p_o)])
+
+ df_c/dp_o = sum_i (kern_i * d/dp_o [func (x_i; p_o)])
+
+ - generate image arrays for func, dfunc/dp_j (not masked)
+ - convolve each with psf
+ - measure delta = f_conv - data
+ - etc
+*/
+
+
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPCMdata.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPCMdata.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPCMdata.c	(revision 29060)
@@ -0,0 +1,364 @@
+/* @file  pmPCMdata.c
+ * structures and functions to support PSF-convolved model fitting
+ *
+ * @author EAM, IfA
+ *
+ * @version $Revision: 1.29 $
+ * @date $Date: 2009-02-16 22:30:50 $
+ * Copyright 2010 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <strings.h>
+#include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPCMdata.h"
+
+static void pmPCMdataFree (pmPCMdata *pcm) {
+
+    if (pcm == NULL) return;
+
+    psFree (pcm->modelFlux);
+    psFree (pcm->modelConvFlux);
+    psFree (pcm->dmodelsFlux);
+    psFree (pcm->dmodelsConvFlux);
+
+    psFree (pcm->modelConv);
+    psFree (pcm->psf);
+    psFree (pcm->psfFFT);
+    psFree (pcm->constraint);
+    return;
+}
+
+pmPCMdata *pmPCMdataAlloc (
+    const psVector *params,
+    const psVector *paramMask,
+    pmSource *source) {
+
+    pmPCMdata *pcm = (pmPCMdata *) psAlloc(sizeof(pmPCMdata));
+    psMemSetDeallocator(pcm, (psFreeFunc) pmPCMdataFree);
+
+    // Allocate storage images for raw model and derivative images
+    pcm->modelFlux = psImageCopy (NULL, source->pixels, PS_TYPE_F32);
+    pcm->dmodelsFlux = psArrayAlloc (params->n);
+    for (psS32 n = 0; n < params->n; n++) {
+        pcm->dmodelsFlux->data[n] = NULL;
+        if ((paramMask != NULL) && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n])) { continue; }
+        pcm->dmodelsFlux->data[n] = psImageCopy (NULL, source->pixels, PS_TYPE_F32);
+    }
+
+    // Allocate storage images for convolved model and derivative images
+    pcm->modelConvFlux = psImageCopy (NULL, source->pixels, PS_TYPE_F32);
+    pcm->dmodelsConvFlux = psArrayAlloc (params->n);
+    for (psS32 n = 0; n < params->n; n++) {
+        pcm->dmodelsConvFlux->data[n] = NULL;
+        if ((paramMask != NULL) && (paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n])) { continue; }
+        pcm->dmodelsConvFlux->data[n] = psImageCopy (NULL, source->pixels, PS_TYPE_F32);
+    }
+
+    pcm->modelConv = NULL;
+    pcm->psf = NULL;
+    pcm->psfFFT = NULL;
+    pcm->constraint = NULL;
+    pcm->nDOF = 0;
+
+    return pcm;
+}
+
+psImage *pmPCMdataSaveImage (pmPCMdata *pcm) {
+
+    psImage *model = psImageCopy (NULL, pcm->modelConvFlux, PS_TYPE_F32);
+
+    return model;
+}
+
+psKernel *pmPCMkernelFromPSF (pmSource *source, int nPix) {
+
+    assert (source);
+    assert (source->psfImage); // XXX build if needed?
+
+    int x0 = source->peak->xf - source->psfImage->col0;
+    int y0 = source->peak->yf - source->psfImage->row0;
+
+    // need to decide on the size: dynamically? statically?
+    psKernel *psf = psKernelAlloc (-nPix, +nPix, -nPix, +nPix);
+
+    // XXX we should just re-construct a PSF at this location 
+    // psModelAdd (psf->image, NULL, source->modelPSF, PM_MODEL_OP_FULL | PM_MODEL_OP_NORM | PM_MODEL_OP_CENTER);
+  
+    // if the realized PSF for this object does not cover the full kernel, give up for now
+    if (x0 + psf->xMin < 0) goto escape;
+    if (x0 + psf->xMax >= source->psfImage->numCols) goto escape;
+    if (y0 + psf->yMin < 0) goto escape;
+    if (y0 + psf->yMax >= source->psfImage->numRows) goto escape;
+
+    double sum = 0.0;
+    for (int j = psf->yMin; j <= psf->yMax; j++) {
+	for (int i = psf->xMin; i <= psf->xMax; i++) {
+	    double value = source->psfImage->data.F32[y0 + j][x0 + i];
+	    psf->kernel[j][i] = value;
+	    sum += value;
+	}
+    }
+    assert (sum > 0.0);
+
+    // psf must be normalized (integral = 1.0)
+    for (int i = 0; i < psf->image->numRows; i++) {
+	for (int j = 0; j < psf->image->numCols; j++) {
+	    psf->image->data.F32[i][j] /= sum;
+	}
+    }
+
+    return psf;
+
+escape:
+    psFree (psf);
+    return NULL;
+}
+
+pmPCMdata *pmPCMinit(pmSource *source, pmSourceFitOptions *fitOptions, pmModel *model, psImageMaskType maskVal, float psfSize) {
+
+    // make sure we save a cached copy of the psf flux
+    pmSourceCachePSF (source, maskVal);
+
+    // convert the cached cached psf model for this source to a psKernel
+    psKernel *psf = pmPCMkernelFromPSF (source, psfSize);
+    if (!psf) {
+	// NOTE: this only happens if the source is too close to an edge
+        model->flags |= PM_MODEL_STATUS_BADARGS;
+	return NULL;
+    }
+
+# if (USE_DELTA_PSF)
+    psImageInit (psf->image, 0.0);
+    psf->image->data.F32[(int)(0.5*psf->image->numRows)][(int)(0.5*psf->image->numCols)] = 1.0;
+# endif
+
+    // count the number of unmasked pixels:
+    int nPix = 0;
+    for (psS32 i = 0; i < source->pixels->numRows; i++) {
+        for (psS32 j = 0; j < source->pixels->numCols; j++) {
+            // XXX are we doing the right thing with the mask?
+            // skip masked points
+            if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[i][j]) {
+                continue;
+            }
+            // skip zero-variance points
+            if (source->variance->data.F32[i][j] == 0) {
+                continue;
+            }
+            // skip nan value points
+            if (!isfinite(source->pixels->data.F32[i][j])) {
+                continue;
+            }
+	    nPix ++;
+	}
+    }    
+
+    psVector *params  = model->params;
+
+    // create the minimization constraints
+    psMinConstraint *constraint = psMinConstraintAlloc();
+    constraint->paramMask = psVectorAlloc (params->n, PS_TYPE_VECTOR_MASK);
+    constraint->checkLimits = model->modelLimits;
+
+    // set parameter mask based on fitting mode
+    int nParams = 0;
+    switch (fitOptions->mode) {
+      case PM_SOURCE_FIT_NORM:
+        // NORM-only model fits only source normalization (Io)
+        nParams = 1;
+        psVectorInit (constraint->paramMask, 1);
+        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_I0] = 0;
+        break;
+      case PM_SOURCE_FIT_PSF:
+        // PSF model only fits x,y,Io
+        nParams = 3;
+        psVectorInit (constraint->paramMask, 1);
+        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_I0] = 0;
+        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_XPOS] = 0;
+        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_YPOS] = 0;
+        break;
+      case PM_SOURCE_FIT_EXT:
+        // EXT model fits all params (except sky)
+        nParams = params->n - 1;
+        psVectorInit (constraint->paramMask, 0);
+        constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_SKY] = 1;
+        break;
+      case PM_SOURCE_FIT_INDEX:
+        // PSF model only fits Io, index (PAR7) -- only Io for models with < 8 params
+	psVectorInit (constraint->paramMask, 1);
+	constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_I0] = 0;
+        if (params->n == 7) {
+	    nParams = 1;
+	} else {
+	    nParams = 2;
+	    constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_7] = 0;
+	}
+	break;
+      case PM_SOURCE_FIT_NO_INDEX:
+        // PSF model only fits Io, index (PAR7) -- only Io for models with < 8 params
+	psVectorInit (constraint->paramMask, 0);
+	constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_SKY] = 1;
+        if (params->n == 7) {
+	    nParams = params->n - 1;
+	} else {
+	    nParams = params->n - 2;
+	    constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_7] = 1;
+	}
+	break;
+      default:
+	psAbort("invalid fitting mode");
+    }
+
+    if (nPix <  nParams + 1) {
+        psTrace ("psModules.objects", 4, "insufficient valid pixels\n");
+	psFree (psf);
+	psFree (constraint);
+        model->flags |= PM_MODEL_STATUS_BADARGS;
+	return NULL;
+    }
+
+    // generate PCM data storage structure
+    pmPCMdata *pcm = pmPCMdataAlloc (params, constraint->paramMask, source);
+
+    pcm->psf = psf;
+    pcm->modelConv = psMemIncrRefCounter(model);
+    pcm->constraint = constraint;
+
+    pcm->nPix = nPix;
+    pcm->nDOF = nPix - nParams - 1;
+
+    return pcm;
+}
+
+// has the set of fitted terms changed?  has the fitting radius changed?
+bool pmPCMupdate(pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, pmModel *model) {
+
+    bool newWindow = (source->pixels->numRows != pcm->modelFlux->numRows) || (source->pixels->numCols != pcm->modelFlux->numCols);
+
+    // re-count the number of unmasked pixels:
+    if (newWindow) {
+	for (psS32 i = 0; i < source->pixels->numRows; i++) {
+	    for (psS32 j = 0; j < source->pixels->numCols; j++) {
+		// XXX are we doing the right thing with the mask?
+		// skip masked points
+		if (source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[i][j]) {
+		    continue;
+		}
+		// skip zero-variance points
+		if (source->variance->data.F32[i][j] == 0) {
+		    continue;
+		}
+		// skip nan value points
+		if (!isfinite(source->pixels->data.F32[i][j])) {
+		    continue;
+		}
+		pcm->nPix ++;
+	    }
+	}    
+    }
+
+    // if we changed the fit mode, we need to update nDOF
+    int nParams = 0;
+    // set parameter mask based on fitting mode
+    switch (fitOptions->mode) {
+      case PM_SOURCE_FIT_NORM:
+	// NORM-only model fits only source normalization (Io)
+	nParams = 1;
+	psVectorInit (pcm->constraint->paramMask, 1);
+	pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_I0] = 0;
+	break;
+      case PM_SOURCE_FIT_PSF:
+	// PSF model only fits x,y,Io
+	nParams = 3;
+	psVectorInit (pcm->constraint->paramMask, 1);
+	pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_I0] = 0;
+	pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_XPOS] = 0;
+	pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_YPOS] = 0;
+	break;
+      case PM_SOURCE_FIT_EXT:
+	// EXT model fits all params (except sky)
+	nParams = model->params->n - 1;
+	psVectorInit (pcm->constraint->paramMask, 0);
+	pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_SKY] = 1;
+	break;
+      case PM_SOURCE_FIT_INDEX:
+	// PSF model only fits Io, index (PAR7) -- only Io for models with < 8 params
+	psVectorInit (pcm->constraint->paramMask, 1);
+	pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_I0] = 0;
+	if (model->params->n == 7) {
+	    nParams = 1;
+	} else {
+	    nParams = 2;
+	    pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_7] = 0;
+	}
+	break;
+      case PM_SOURCE_FIT_NO_INDEX:
+	// PSF model only fits Io, index (PAR7) -- only Io for models with < 8 params
+	psVectorInit (pcm->constraint->paramMask, 0);
+	pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_SKY] = 1;
+	if (model->params->n == 7) {
+	    nParams = model->params->n - 1;
+	} else {
+	    nParams = model->params->n - 2;
+	    pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_7] = 1;
+	}
+	break;
+      default:
+	psAbort("invalid fitting mode");
+    }
+
+    if (pcm->nPix <  nParams + 1) {
+        psTrace ("psModules.objects", 4, "insufficient valid pixels\n");
+        model->flags |= PM_MODEL_STATUS_BADARGS;
+	return false;
+    }
+    pcm->nDOF = pcm->nPix - nParams - 1;
+
+    // has the source pixel window changed?
+    if (newWindow) {
+
+	// adjust all supporting images:
+	pcm->modelFlux = psImageCopy (pcm->modelFlux, source->pixels, PS_TYPE_F32);
+	for (psS32 n = 0; n < pcm->dmodelsFlux->n; n++) {
+	    if ((pcm->constraint->paramMask != NULL) && (pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n])) { continue; }
+	    pcm->dmodelsFlux->data[n] = psImageCopy (pcm->dmodelsFlux->data[n], source->pixels, PS_TYPE_F32);
+	}
+
+	// adjust images for convolved model and derivative images
+	pcm->modelConvFlux = psImageCopy (pcm->modelConvFlux, source->pixels, PS_TYPE_F32);
+	for (psS32 n = 0; n < pcm->dmodelsConvFlux->n; n++) {
+	    if ((pcm->constraint->paramMask != NULL) && (pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[n])) { continue; }
+	    pcm->dmodelsConvFlux->data[n] = psImageCopy (pcm->dmodelsConvFlux->data[n], source->pixels, PS_TYPE_F32);
+	}
+    }
+
+    return true;
+}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPCMdata.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPCMdata.h	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPCMdata.h	(revision 29060)
@@ -0,0 +1,91 @@
+/* @file  pmPCMdata.h
+ * structures and functions to support PSF-convolved model fitting
+ *
+ * @author EAM, IfA
+ *
+ * @version $Revision: 1.29 $
+ * @date $Date: 2009-02-16 22:30:50 $
+ * Copyright 2010 Institute for Astronomy, University of Hawaii
+ */
+
+# ifndef PM_PCM_DATA_H
+# define PM_PCM_DATA_H
+
+/// @addtogroup Objects Object Detection / Analysis Functions
+/// @{
+
+/** pmPCMdata : PSF Convolved Model data storage structure
+ *
+ * Structure to carry the data needed to generate a PSF-convolve model fit
+ *
+ */
+// 
+typedef struct {
+    psImage *modelFlux;
+    psArray *dmodelsFlux;
+    psImage *modelConvFlux;
+    psArray *dmodelsConvFlux;
+
+    pmModel *modelConv;
+    psKernel *psf;
+    psKernelFFT *psfFFT;
+
+    psMinConstraint *constraint;
+    int nPix;
+    int nDOF;
+} pmPCMdata;
+
+// structures & functions to support psf-convolved model fitting
+
+// psf-convolved model fitting
+bool psphotModelWithPSF_LMM (
+    psMinimization *min,
+    psImage *covar,
+    psVector *params,
+    psMinConstraint *constraint,
+    pmSource *source,
+    const psKernel *psf,
+    psMinimizeLMChi2Func func);
+
+psF32 psphotModelWithPSF_SetABX(
+    psImage  *alpha,
+    psVector *beta,
+    const psVector *params,
+    const psVector *paramMask,
+    pmPCMdata *pcm,
+    const pmSource *source,
+    const psKernel *psf,
+    psMinimizeLMChi2Func func);
+
+pmPCMdata *pmPCMdataAlloc (
+    const psVector *params,
+    const psVector *paramMask,
+    pmSource *source);
+
+pmPCMdata *pmPCMinit(pmSource *source, pmSourceFitOptions *fitOptions, pmModel *model, psImageMaskType maskVal, float psfSize);
+bool pmPCMupdate(pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, pmModel *model);
+
+psImage *pmPCMdataSaveImage (pmPCMdata *pcm);
+
+psF32 pmPCM_SetABX(
+    psImage  *alpha,
+    psVector *beta,
+    const psVector *params,
+    const psVector *paramMask,
+    pmPCMdata *pcm,
+    const pmSource *source);
+
+bool pmPCM_MinimizeChisq (
+    psMinimization *min,
+    psImage *covar,
+    psVector *params,
+    pmSource *source,
+    pmPCMdata *pcm);
+
+bool pmSourceModelGuessPCM (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal);
+
+bool pmSourceFitPCM (pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
+
+
+/// @}
+# endif /* PM_PCM_DATA_H */
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF.c	(revision 29060)
@@ -25,19 +25,28 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+#include "psVectorBracket.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
-#include "pmModelUtils.h"
-#include "pmSourcePhotometry.h"
-#include "pmFPAMaskWeight.h"
-#include "psVectorBracket.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmErrorCodes.h"
 
@@ -54,4 +63,5 @@
 
     psFree (options->stats);
+    psFree (options->fitOptions);
     return;
 }
@@ -65,4 +75,5 @@
 
     options->stats         = NULL;
+    options->fitOptions    = NULL; // XXX this has to be set before calling pmPSF fit functions
 
     options->psfTrendMode  = PM_TREND_NONE;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF.h	(revision 29060)
@@ -14,15 +14,6 @@
 # define PM_PSF_H
 
-#include <pslib.h>
-#include "pmTrend2D.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmFPA.h"
-
 /// @addtogroup Objects Object Detection / Analysis Functions
 /// @{
-
-// type of model carried by the pmModel structure
-typedef int pmModelType;
 
 /** pmPSF data structure
@@ -38,5 +29,5 @@
  *
  */
-typedef struct {
+struct pmPSF {
     pmModelType type;                   ///< PSF Model in use
     psArray *params;                    ///< Model parameters (psPolynomial2D)
@@ -64,5 +55,5 @@
     pmGrowthCurve *growth;              ///< apMag vs Radius
     pmResiduals *residuals;             ///< normalized residual image (no spatial variation)
-} pmPSF;
+};
 
 typedef struct {
@@ -82,4 +73,5 @@
     float         apRadius;
     bool          chiFluxTrend;         // Fit a trend in Chi2 as a function of flux?
+    pmSourceFitOptions *fitOptions;
 } pmPSFOptions;
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF_IO.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF_IO.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSF_IO.c	(revision 29060)
@@ -38,17 +38,26 @@
 #include "pmFPAfileFitsIO.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmPSF_IO.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
-#include "pmModelUtils.h"
 #include "pmSourceIO.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtry.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtry.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtry.c	(revision 29060)
@@ -19,19 +19,26 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.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 "pmDetections.h"
+
 #include "pmSourcePhotometry.h"
 #include "pmSourceVisual.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryFitEXT.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryFitEXT.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryFitEXT.c	(revision 29060)
@@ -19,19 +19,27 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
 #include "pmSourceUtils.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
 #include "pmPSFtry.h"
-#include "pmModelClass.h"
-#include "pmModelUtils.h"
-#include "pmSourceFitModel.h"
+#include "pmDetections.h"
+
 #include "pmSourcePhotometry.h"
 #include "pmSourceVisual.h"
@@ -44,4 +52,7 @@
 
     psTimerStart ("psf.fit");
+
+    // in this segment, we are fitting the full PSF model class (shape unconstrained)
+    options->fitOptions->mode = PM_SOURCE_FIT_EXT;
 
     // maskVal is used to test for rejected pixels, and must include markVal
@@ -73,5 +84,5 @@
 
         // fit model as EXT, not PSF
-        status = pmSourceFitModel (source, source->modelEXT, PM_SOURCE_FIT_EXT, maskVal);
+        status = pmSourceFitModel (source, source->modelEXT, options->fitOptions, maskVal);
 
         // clear object mask to define valid pixels
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryFitPSF.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryFitPSF.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryFitPSF.c	(revision 29060)
@@ -17,19 +17,26 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.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 "pmDetections.h"
+
 #include "pmSourcePhotometry.h"
 #include "pmSourceVisual.h"
@@ -42,4 +49,7 @@
 
     psTimerStart ("psf.fit");
+
+    // in this segment, we are fitting the fitted PSF model class (shape constrained)
+    options->fitOptions->mode = PM_SOURCE_FIT_PSF;
 
     // maskVal is used to test for rejected pixels, and must include markVal
@@ -81,5 +91,5 @@
 
         // fit the PSF model to the source
-        status = pmSourceFitModel (source, source->modelPSF, PM_SOURCE_FIT_NORM, maskVal);
+        status = pmSourceFitModel (source, source->modelPSF, options->fitOptions, maskVal);
 
         // skip poor fits
@@ -98,5 +108,5 @@
 
 	// This function calculates the psf and aperture magnitudes
-        status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal); // raw PSF mag, AP mag
+        status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal, markVal); // raw PSF mag, AP mag
         if (!status || isnan(source->apMag)) {
             psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryMakePSF.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryMakePSF.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryMakePSF.c	(revision 29060)
@@ -18,19 +18,26 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.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 "pmDetections.h"
+
 #include "pmSourcePhotometry.h"
 #include "pmSourceVisual.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryMetric.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryMetric.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryMetric.c	(revision 29060)
@@ -18,19 +18,26 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.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 "pmDetections.h"
+
 #include "pmSourcePhotometry.h"
 #include "pmSourceVisual.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryModel.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryModel.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPSFtryModel.c	(revision 29060)
@@ -19,20 +19,26 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.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 "pmDetections.h"
+
 #include "pmSourceVisual.h"
 
@@ -49,4 +55,6 @@
 pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal)
 {
+    assert (options->fitOptions);
+
     // validate the requested model name
     options->type = pmModelClassGetType (modelName);
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPeaks.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPeaks.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPeaks.c	(revision 29060)
@@ -22,4 +22,5 @@
 #include <pslib.h>
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPeaks.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPeaks.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPeaks.h	(revision 29060)
@@ -17,7 +17,4 @@
 # ifndef PM_PEAKS_H
 # define PM_PEAKS_H
-
-#include <pslib.h>
-#include "pmFootprint.h"
 
 /// @addtogroup Objects Object Detection / Analysis Functions
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPhotObj.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPhotObj.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPhotObj.c	(revision 29060)
@@ -16,6 +16,27 @@
 #include <string.h>
 #include <pslib.h>
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+
 #include "pmPhotObj.h"
-#include "pmSource.h"
+
 
 static void pmPhotObjFree (pmPhotObj *tmp)
@@ -82,2 +103,17 @@
     return (0);
 }
+
+// sort by X (ascending)
+int pmPhotObjSortByX (const void **a, const void **b)
+{
+    pmPhotObj *objA = *(pmPhotObj **)a;
+    pmPhotObj *objB = *(pmPhotObj **)b;
+
+    psF32 fA = objA->x;
+    psF32 fB = objB->x;
+
+    psF32 diff = fA - fB;
+    if (diff > FLT_EPSILON) return (+1);
+    if (diff < FLT_EPSILON) return (-1);
+    return (0);
+}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmPhotObj.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmPhotObj.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmPhotObj.h	(revision 29060)
@@ -10,9 +10,4 @@
 # ifndef PM_PHOT_OBJ_H
 # define PM_PHOT_OBJ_H
-
-#include <pslib.h>
-#include "pmPeaks.h"
-#include "pmModel.h"
-#include "pmMoments.h"
 
 /// @addtogroup Objects Object Detection / Analysis Functions
@@ -47,4 +42,5 @@
 
 int pmPhotObjSortBySN (const void **a, const void **b);
+int pmPhotObjSortByX (const void **a, const void **b);
 
 /// @}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSource.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSource.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSource.c	(revision 29060)
@@ -23,13 +23,20 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
 
@@ -98,5 +105,6 @@
     static int id = 1;
     pmSource *source = (pmSource *) psAlloc(sizeof(pmSource));
-    *(int *)&source->id = id++;
+    P_PM_SOURCE_SET_ID(source, id++);
+
     source->seq = -1;
     source->peak = NULL;
@@ -114,4 +122,5 @@
     source->type = PM_SOURCE_TYPE_UNKNOWN;
     source->mode = PM_SOURCE_MODE_DEFAULT;
+    source->mode2 = PM_SOURCE_MODE_DEFAULT;
     source->tmpFlags = 0;
     source->extpars = NULL;
@@ -131,5 +140,6 @@
     source->sky    = NAN;
     source->skyErr = NAN;
-    source->pixWeight = NAN;
+    source->pixWeightNotBad = NAN;
+    source->pixWeightNotPoor = NAN;
 
     source->psfChisq = NAN;
@@ -142,8 +152,56 @@
 
 /******************************************************************************
-pmSourceCopy(): copy the pmSource structure and contents
-XXX : are we OK with incrementing the ID?
+pmSourceCopy(): copy the pmSource, yielding a copy of the source that can be used without
+affecting the original.  This Copy can be used to allow multiple fit attempts on the same
+object.  The pixels, variance, and mask arrays all point to the same original subarrays.  The
+peak and moments point at the original values.
 *****************************************************************************/
 pmSource *pmSourceCopy(pmSource *in)
+{
+    if (in == NULL) {
+        return(NULL);
+    }
+    pmSource *source = pmSourceAlloc ();
+
+    // keep the original ID so we can find map back to the original
+    P_PM_SOURCE_SET_ID(source, in->id);
+
+    // peak has the same values as the original
+    if (in->peak != NULL) {
+        source->peak = pmPeakAlloc (in->peak->x, in->peak->y, in->peak->value, in->peak->type);
+        source->peak->xf = in->peak->xf;
+        source->peak->yf = in->peak->yf;
+        source->peak->flux = in->peak->flux;
+        source->peak->SN = in->peak->SN;
+    }
+
+    // copy the values in the moments structure
+    if (in->moments != NULL) {
+        source->moments  =  pmMomentsAlloc();
+        *source->moments = *in->moments;
+    }
+
+    // These images are all views to the parent.  We want a new view, but pointing at the same
+    // pixels.  Modifying these pixels (ie, subtracting the model) will affect the pixels seen
+    // by all copies.
+    source->pixels   = psImageCopyView(NULL, in->pixels);
+    source->variance   = psImageCopyView(NULL, in->variance);
+    source->maskView = in->maskView ? psImageCopyView(NULL, in->maskView) : NULL;
+
+    // the maskObj is a unique mask array; create a new mask image
+    source->maskObj = in->maskObj ? psImageCopy (NULL, in->maskObj, PS_TYPE_IMAGE_MASK) : NULL;
+
+    source->type = in->type;
+    source->mode = in->mode;
+    source->imageID = in->imageID;
+
+    return(source);
+}
+
+/******************************************************************************
+pmSourceCopyData(): this creates a new, duplicate source with the same parameters as the
+original (but is actually a new source at the same location)
+*****************************************************************************/
+pmSource *pmSourceCopyData(pmSource *in)
 {
     if (in == NULL) {
@@ -482,5 +540,5 @@
         }
         psfClump.X  = stats->clippedMean;
-        psfClump.dX = stats->clippedStdev;
+        psfClump.dX = hypot(stats->clippedStdev, PSF_CLUMP_GRID_SCALE);
 
         if (!psVectorStats (stats, tmpSy, NULL, NULL, 0)) {
@@ -489,5 +547,5 @@
         }
         psfClump.Y  = stats->clippedMean;
-        psfClump.dY = stats->clippedStdev;
+        psfClump.dY = hypot(stats->clippedStdev, PSF_CLUMP_GRID_SCALE);
 
         psTrace ("psModules.objects", 2, "clump  X,  Y: %f, %f\n", psfClump.X, psfClump.Y);
@@ -910,5 +968,6 @@
     bool addNoise = mode & PM_MODEL_OP_NOISE;
 
-    if (source->modelFlux) {
+    // require the use of pmModelAddWithOffset if we are adding noise (because the model size and norm are rescaled)
+    if (!addNoise && source->modelFlux) {
         // add in the pixels from the modelFlux image
         int dX = source->modelFlux->col0 - source->pixels->col0;
@@ -931,8 +990,4 @@
 
         psF32 **target = source->pixels->data.F32;
-        if (addNoise) {
-	    // when adding noise, we assume the shape and Io have been modified
-            target = source->variance->data.F32;
-        }
 
         for (int iy = 0; iy < source->modelFlux->numRows; iy++) {
@@ -949,10 +1004,8 @@
             }
         }
-	if (!addNoise) {
-	    if (add) {
-		source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
-	    } else {
-		source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
-	    }
+	if (add) {
+	    source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
+	} else {
+	    source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
 	}
         return true;
@@ -973,4 +1026,78 @@
 	}
     }
+
+    return true;
+}
+
+// should we call pmSourceCacheModel if it does not exist?
+bool pmSourceNoiseOp (pmSource *source, pmModelOpMode mode, float FACTOR, float SIZE, bool add, psImageMaskType maskVal, int dx, int dy)
+{
+    assert (mode & PM_MODEL_OP_NOISE);
+    PS_ASSERT_PTR_NON_NULL(source, false);
+    PS_ASSERT_PTR_NON_NULL(source->peak, false);
+
+    if (add) {
+        psTrace ("psphot", 3, "adding noise to object at %f,%f\n", source->peak->xf, source->peak->yf);
+    } else {
+        psTrace ("psphot", 3, "removing noise from object at %f,%f\n", source->peak->xf, source->peak->yf);
+    }
+
+    pmSourceNoiseOpModel (source->modelPSF, source, mode, FACTOR, SIZE, add, maskVal, dx, dy);
+
+    if (source->modelEXT) {
+	pmSourceNoiseOpModel (source->modelEXT, source, mode, FACTOR, SIZE, add, maskVal, dx, dy);
+    }
+
+    return true;
+}
+
+bool pmSourceNoiseOpModel (pmModel *model, pmSource *source, pmModelOpMode mode, float FACTOR, float SIZE, bool add, psImageMaskType maskVal, int dx, int dy) 
+{
+    bool status;
+    psEllipseShape oldshape;
+    psEllipseShape newshape;
+    psEllipseAxes axes;
+
+    if (add) {
+	psTrace ("psphot", 4, "adding noise for object at %f,%f\n", model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS]);
+    } else {
+	psTrace ("psphot", 4, "remove noise for object at %f,%f\n", model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS]);
+    }
+
+    psF32 *PAR = model->params->data.F32;
+
+    // save original values
+    float oldI0  = PAR[PM_PAR_I0];
+    oldshape.sx  = PAR[PM_PAR_SXX];
+    oldshape.sy  = PAR[PM_PAR_SYY];
+    oldshape.sxy = PAR[PM_PAR_SXY];
+
+    // XXX can this be done more intelligently?
+    if (oldI0 == 0.0) return false;
+    if (!isfinite(oldI0)) return false;
+
+    // increase size and height of source
+    axes = psEllipseShapeToAxes (oldshape, 20.0);
+    axes.major *= SIZE;
+    axes.minor *= SIZE;
+    newshape = psEllipseAxesToShape (axes);
+    PAR[PM_PAR_I0]  = FACTOR*oldI0;
+    PAR[PM_PAR_SXX] = newshape.sx;
+    PAR[PM_PAR_SYY] = newshape.sy;
+    PAR[PM_PAR_SXY] = newshape.sxy;
+
+    psImage *target = source->variance;
+
+    if (add) {
+	status = pmModelAddWithOffset (target, source->maskObj, model, mode, maskVal, dx, dy);
+    } else {
+	status = pmModelSubWithOffset (target, source->maskObj, model, mode, maskVal, dx, dy);
+    }
+
+    // restore original values
+    PAR[PM_PAR_I0]  = oldI0;
+    PAR[PM_PAR_SXX] = oldshape.sx;
+    PAR[PM_PAR_SYY] = oldshape.sy;
+    PAR[PM_PAR_SXY] = oldshape.sxy;
 
     return true;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSource.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSource.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSource.h	(revision 29060)
@@ -11,15 +11,6 @@
 # define PM_SOURCE_H
 
-#include <pslib.h>
-#include "pmPeaks.h"
-#include "pmModel.h"
-#include "pmMoments.h"
-#include "pmSourceExtendedPars.h"
-#include "pmSourceDiffStats.h"
-
 /// @addtogroup Objects Object Detection / Analysis Functions
 /// @{
-
-#include <pmSourceMasks.h>
 
 /** pmSourceType enumeration
@@ -74,4 +65,5 @@
     pmSourceType type;                  ///< Best identification of object.
     pmSourceMode mode;                  ///< analysis flags set for object.
+    pmSourceMode2 mode2;                ///< analysis flags set for object.
     pmSourceTmpF tmpFlags;              ///< internal-only flags
     psArray *blends;                    ///< collection of sources thought to be confused with object
@@ -82,10 +74,14 @@
     float errMag;                       ///< error in psfMag OR extMag (depending on type)
     float apMag;                        ///< apMag corresponding to psfMag or extMag (depending on type)
-    float pixWeight;                    ///< model-weighted coverage of valid pixels
+    float apMagRaw;                     ///< raw mag in given aperture
+    float apRadius;			///< radius for aperture magnitude
+
+    float pixWeightNotBad;              ///< PSF-weighted coverage of unmasked (not BAD) pixels
+    float pixWeightNotPoor;             ///< PSF-weighted coverage of unmasked (not POOR) pixels
+
     float psfChisq;                     ///< probability of PSF
     float crNsigma;                     ///< Nsigma deviation from PSF to CR
     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
@@ -113,4 +109,6 @@
 pmPSFClump;
 
+// private macro to set the source ID (a const)
+#define P_PM_SOURCE_SET_ID(S,V) { *(int *)&(S)->id = (V); }
 
 /** pmSourceAlloc()
@@ -126,4 +124,5 @@
 
 pmSource  *pmSourceCopy(pmSource *source);
+pmSource *pmSourceCopyData(pmSource *in);
 
 // free just the pixels for a source, keeping derived data
@@ -242,4 +241,7 @@
 bool pmSourceSubWithOffset (pmSource *source, pmModelOpMode mode, psImageMaskType maskVal, int dx, int dy);
 
+bool pmSourceNoiseOpModel (pmModel *model, pmSource *source, pmModelOpMode mode, float FACTOR, float SIZE, bool add, psImageMaskType maskVal, int dx, int dy);
+bool pmSourceNoiseOp (pmSource *source, pmModelOpMode mode, float FACTOR, float SIZE, bool add, psImageMaskType maskVal, int dx, int dy);
+
 bool pmSourceOp (pmSource *source, pmModelOpMode mode, bool add, psImageMaskType maskVal, int dx, int dy);
 bool pmSourceCacheModel (pmSource *source, psImageMaskType maskVal);
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceContour.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceContour.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceContour.c	(revision 29060)
@@ -23,14 +23,22 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
+
 #include "pmSourceContour.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceDiffStats.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceDiffStats.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceDiffStats.c	(revision 29060)
@@ -29,4 +29,9 @@
     diffStats->nRatioAll = NAN;
     diffStats->nGood = 0;
+
+    diffStats->SNp = NAN;
+    diffStats->SNm = NAN;
+    diffStats->Rp = NAN;
+    diffStats->Rm = NAN;
 }
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceDiffStats.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceDiffStats.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceDiffStats.h	(revision 29060)
@@ -29,4 +29,8 @@
     float nRatioAll;			// = nGood / (nGood + nMask + nBad)
     int   nGood;			// nGood as defined above
+    float SNp;				// S/N of matched source in positive image
+    float SNm;				// S/N of matched source in negative image
+    float Rp;				// radius of matched source in positive image
+    float Rm;				// radius of matched source in negative image
 } pmSourceDiffStats;
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitModel.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitModel.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitModel.c	(revision 29060)
@@ -23,37 +23,47 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmModelClass.h"
 #include "pmSourceFitModel.h"
 
-// save as static values so they may be set externally
-static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15;
-static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1;
-static psF32 PM_SOURCE_FIT_MODEL_WEIGHT = 1.0;
-static bool  PM_SOURCE_FIT_MODEL_PIX_WEIGHTS = true;
-
-bool pmSourceFitModelInit (float nIter, float tol, float weight, bool poissonErrors)
+void pmSourceFitOptionsFree(pmSourceFitOptions *opt)
 {
-
-    PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = nIter;
-    PM_SOURCE_FIT_MODEL_TOLERANCE = tol;
-    PM_SOURCE_FIT_MODEL_WEIGHT = weight;
-    PM_SOURCE_FIT_MODEL_PIX_WEIGHTS = poissonErrors;
-
-    return true;
+    return;
+}
+
+pmSourceFitOptions *pmSourceFitOptionsAlloc(void) {
+
+    pmSourceFitOptions *opt = (pmSourceFitOptions *) psAlloc(sizeof(pmSourceFitOptions));
+    psMemSetDeallocator(opt, (psFreeFunc) pmSourceFitOptionsFree);
+
+    opt->mode = PM_SOURCE_FIT_PSF;
+    opt->nIter  = 15;
+    opt->minTol = 0.01;
+    opt->maxTol = 1.00;
+    opt->weight = 1.00;
+    opt->maxChisqDOF = NAN;
+    opt->poissonErrors = true;
+
+    return opt;
 }
 
 bool pmSourceFitModel (pmSource *source,
                        pmModel *model,
-                       pmSourceFitMode mode,
+                       pmSourceFitOptions *options,
                        psImageMaskType maskVal)
 {
@@ -76,4 +86,9 @@
     psVector *yErr = psVectorAllocEmpty(nPix, PS_TYPE_F32);
 
+    // XXX for a test, skip the central pixel in the sersic fit
+    bool skipCenter = false && (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
+    float Xo = model->params->data.F32[PM_PAR_XPOS];
+    float Yo = model->params->data.F32[PM_PAR_YPOS];
+
     // fill in the coordinate and value entries
     nPix = 0;
@@ -95,14 +110,24 @@
             // skip nan values in image
             if (!isfinite(source->variance->data.F32[i][j])) {
-	      fprintf (stderr, "impossible! %x vs %x\n", source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[i][j], maskVal);
-	      continue;
-            }
-
-            psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
+		fprintf (stderr, "impossible! %x vs %x\n", source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[i][j], maskVal);
+		continue;
+            }
 
             // Convert i/j to image space:
 	    // 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);
+            float Xv = (psF32) (j + 0.5 + source->pixels->col0);
+            float Yv = (psF32) (i + 0.5 + source->pixels->row0);
+
+	    // XXX possible skip of center pixel:
+	    if (skipCenter) {
+		float r = hypot(Xv - Xo, Yv - Yo);
+		if (r < 0.75) {
+		    continue;
+		}
+	    }
+
+            psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
+            coord->data.F32[0] = Xv;
+            coord->data.F32[1] = Yv;
             x->data[nPix] = (psPtr *) coord;
             y->data.F32[nPix] = source->pixels->data.F32[i][j];
@@ -111,8 +136,8 @@
             // as variance to avoid the bias from systematic errors here we would just use the
             // source sky variance
-            if (PM_SOURCE_FIT_MODEL_PIX_WEIGHTS) {
+            if (options->poissonErrors) {
                 yErr->data.F32[nPix] = 1.0 / source->variance->data.F32[i][j];
             } else {
-                yErr->data.F32[nPix] = 1.0 / PM_SOURCE_FIT_MODEL_WEIGHT;
+                yErr->data.F32[nPix] = 1.0 / options->weight;
             }
             nPix++;
@@ -133,6 +158,6 @@
     // set parameter mask based on fitting mode
     int nParams = 0;
-    switch (mode) {
-    case PM_SOURCE_FIT_NORM:
+    switch (options->mode) {
+      case PM_SOURCE_FIT_NORM:
         // NORM-only model fits only source normalization (Io)
         nParams = 1;
@@ -140,5 +165,5 @@
         constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_I0] = 0;
         break;
-    case PM_SOURCE_FIT_PSF:
+      case PM_SOURCE_FIT_PSF:
         // PSF model only fits x,y,Io
         nParams = 3;
@@ -148,5 +173,5 @@
         constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_YPOS] = 0;
         break;
-    case PM_SOURCE_FIT_EXT:
+      case PM_SOURCE_FIT_EXT:
         // EXT model fits all params (except sky)
         nParams = params->n - 1;
@@ -154,11 +179,33 @@
         constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_SKY] = 1;
         break;
-    default:
-        psAbort("invalid fitting mode");
+      case PM_SOURCE_FIT_INDEX:
+        // PSF model only fits Io, index (PAR7) -- only Io for models with < 8 params
+	psVectorInit (constraint->paramMask, 1);
+	constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_I0] = 0;
+        if (params->n == 7) {
+	    nParams = 1;
+	} else {
+	    nParams = 2;
+	    constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_7] = 0;
+	}
+	break;
+      case PM_SOURCE_FIT_NO_INDEX:
+        // PSF model only fits Io, index (PAR7) -- only Io for models with < 8 params
+	psVectorInit (constraint->paramMask, 0);
+	constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_SKY] = 1;
+        if (params->n == 7) {
+	    nParams = params->n - 1;
+	} else {
+	    nParams = params->n - 2;
+	    constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[PM_PAR_7] = 1;
+	}
+	break;
+      default:
+	psAbort("invalid fitting mode");
     }
     // force the floating parameters to fall within the contraint ranges
     for (int i = 0; i < params->n; i++) {
-        model->modelLimits (PS_MINIMIZE_PARAM_MIN, i, params->data.F32, NULL);
-        model->modelLimits (PS_MINIMIZE_PARAM_MAX, i, params->data.F32, NULL);
+	model->modelLimits (PS_MINIMIZE_PARAM_MIN, i, params->data.F32, NULL);
+	model->modelLimits (PS_MINIMIZE_PARAM_MAX, i, params->data.F32, NULL);
     }
 
@@ -173,5 +220,5 @@
     }
 
-    psMinimization *myMin = psMinimizationAlloc (PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, PM_SOURCE_FIT_MODEL_TOLERANCE);
+    psMinimization *myMin = psMinimizationAlloc (options->nIter, options->minTol, options->maxTol);
 
     psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
@@ -194,4 +241,5 @@
     model->flags |= PM_MODEL_STATUS_FITTED;
     if (!fitStatus) model->flags |= PM_MODEL_STATUS_NONCONVERGE;
+    if (myMin->lastDelta > myMin->minTol) model->flags |= PM_MODEL_STATUS_WEAK_FIT;
 
     // get the Gauss-Newton distance for fixed model parameters
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitModel.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitModel.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitModel.h	(revision 29060)
@@ -19,13 +19,29 @@
     PM_SOURCE_FIT_EXT,
     PM_SOURCE_FIT_PSF_AND_SKY,
-    PM_SOURCE_FIT_EXT_AND_SKY
+    PM_SOURCE_FIT_EXT_AND_SKY,
+    PM_SOURCE_FIT_INDEX,
+    PM_SOURCE_FIT_NO_INDEX,
 } pmSourceFitMode;
 
-bool pmSourceFitModelInit(
-    float nIter,   ///< max number of allowed iterations
-    float tol,      ///< convergence criterion
-    float weight,      ///< use this weight for constant-weight fits
-    bool poissonErrors   // use poisson errors for fits?
-);
+typedef struct {
+    pmSourceFitMode mode;		///< optionally fit all or a subset of parameters
+    float nIter;			///< max number of allowed iterations
+    float minTol;			///< convergence criterion
+    float maxTol;			///< convergence criterion
+    float maxChisqDOF;			///< convergence criterion
+    float weight;			///< use this weight for constant-weight fits
+    bool poissonErrors;			///< use poisson errors for fits?
+} pmSourceFitOptions;
+
+// the pmSourceFitOptions structure is used to control details of the fitting process
+pmSourceFitOptions *pmSourceFitOptionsAlloc(void);
+
+// bool pmSourceFitModelInit(
+//     pmSourceFitMode mode,		///< what parameter set should be fitted?
+//     float nIter,			///< max number of allowed iterations
+//     float tol,				///< convergence criterion
+//     float weight,			///< use this weight for constant-weight fits
+//     bool poissonErrors			///< use poisson errors for fits?
+// );
 
 /** pmSourceFitModel()
@@ -38,40 +54,39 @@
  */
 bool pmSourceFitModel(
-    pmSource *source,   ///< The input pmSource
-    pmModel *model,   ///< model to be fitted
-    pmSourceFitMode mode,  ///< define parameters to be fitted
+    pmSource *source,			///< The input pmSource
+    pmModel *model,			///< model to be fitted
+    pmSourceFitOptions *options,	///< define parameters to be fitted
     psImageMaskType maskVal		///< Value to mask
 );
 
-
-// initialize data for a group of object models
-bool pmSourceFitSetInit (pmModelType type);
-
-// clear data for a group of object models
-void pmSourceFitSetClear (void);
-
-// function used to set limits for a group of models
-bool pmSourceFitSet_CheckLimits (psMinConstraintMode mode, int nParam, float *params, float *betas);
-
-// function used to fit a group of object models
-psF32 pmSourceFitSet_Function(psVector *deriv,
-                              const psVector *params,
-                              const psVector *x);
-
-/** pmSourceFitSet()
- *
- * Fit the requested model to the specified source. The starting guess for the model is given
- * by the input source.model parameter values. The pixels of interest are specified by the
- * source.pixels and source.mask entries. This function calls psMinimizeLMChi2() on the image
- * data. The function returns TRUE on success or FALSE on failure.
- *
- */
-bool pmSourceFitSet(
-    pmSource *source,   ///< The input pmSource
-    psArray *modelSet,   ///< model to be fitted
-    pmSourceFitMode mode,  ///< define parameters to be fitted
-    psImageMaskType maskVal		///< Vale to mask
-
-);
+// // initialize data for a group of object models
+// bool pmSourceFitSetInit (pmModelType type);
+// 
+// // clear data for a group of object models
+// void pmSourceFitSetClear (void);
+// 
+// // function used to set limits for a group of models
+// bool pmSourceFitSet_CheckLimits (psMinConstraintMode mode, int nParam, float *params, float *betas);
+// 
+// // function used to fit a group of object models
+// psF32 pmSourceFitSet_Function(psVector *deriv,
+//                               const psVector *params,
+//                               const psVector *x);
+// 
+// /** pmSourceFitSet()
+//  *
+//  * Fit the requested model to the specified source. The starting guess for the model is given
+//  * by the input source.model parameter values. The pixels of interest are specified by the
+//  * source.pixels and source.mask entries. This function calls psMinimizeLMChi2() on the image
+//  * data. The function returns TRUE on success or FALSE on failure.
+//  *
+//  */
+// bool pmSourceFitSet(
+//     pmSource *source,   ///< The input pmSource
+//     psArray *modelSet,   ///< model to be fitted
+//     pmSourceFitMode mode,  ///< define parameters to be fitted
+//     psImageMaskType maskVal		///< Vale to mask
+// 
+// );
 
 /// @}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitPCM.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitPCM.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitPCM.c	(revision 29060)
@@ -0,0 +1,160 @@
+/* @file  pmSourceFitPCM.c
+ * structures and functions to support PSF-convolved model fitting
+ *
+ * @author EAM, IfA
+ *
+ * @version $Revision: 1.29 $
+ * @date $Date: 2009-02-16 22:30:50 $
+ * Copyright 2010 Institute for Astronomy, University of Hawaii
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <strings.h>
+#include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPCMdata.h"
+
+# define FACILITY "psModules.objects"
+
+// input source has both modelPSF and modelEXT.  on successful exit, we set the
+// modelConv to contain the fitted parameters, and the modelFlux to contain the 
+// convolved model image.
+
+bool pmSourceFitPCM (pmPCMdata *pcm, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
+    
+    psVector *params  = pcm->modelConv->params;
+    psVector *dparams  = pcm->modelConv->dparams;
+
+    // force the floating parameters to fall within the contraint ranges
+    for (int i = 0; i < params->n; i++) {
+	pcm->modelConv->modelLimits (PS_MINIMIZE_PARAM_MIN, i, params->data.F32, NULL);
+	pcm->modelConv->modelLimits (PS_MINIMIZE_PARAM_MAX, i, params->data.F32, NULL);
+    }
+
+    // set up the minimization process
+    psMinimization *myMin = psMinimizationAlloc (fitOptions->nIter, fitOptions->minTol, fitOptions->maxTol);
+
+    psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
+
+    bool fitStatus = pmPCM_MinimizeChisq (myMin, covar, params, source, pcm);
+    for (int i = 0; i < dparams->n; i++) {
+        if ((pcm->constraint->paramMask != NULL) && pcm->constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i])
+            continue;
+        dparams->data.F32[i] = sqrt(covar->data.F32[i][i]);
+        psTrace ("psModules.objects", 4, "%f +/- %f", params->data.F32[i], dparams->data.F32[i]);
+    }
+    psTrace ("psphot", 4, "niter: %d, chisq: %f", myMin->iter, myMin->value);
+
+    // renormalize output model image (generated by fitting process)
+    float Io = params->data.F32[PM_PAR_I0];
+    for (int iy = 0; iy < source->modelFlux->numRows; iy++) {
+	for (int ix = 0; ix < source->modelFlux->numCols; ix++) {
+	    source->modelFlux->data.F32[iy][ix] /= Io;
+	}
+    }
+
+    // save the resulting chisq, nDOF, nIter
+    pcm->modelConv->chisq = myMin->value;
+    pcm->modelConv->nIter = myMin->iter;
+    pcm->modelConv->nPix = pcm->nPix;
+    pcm->modelConv->nDOF = pcm->nDOF;
+    pcm->modelConv->chisqNorm = pcm->modelConv->chisq / pcm->modelConv->nDOF;
+    pcm->modelConv->flags |= PM_MODEL_STATUS_FITTED;
+    if (!fitStatus) pcm->modelConv->flags |= PM_MODEL_STATUS_NONCONVERGE;
+
+    // models can go insane: reject these
+    bool onPic = true;
+    onPic &= (params->data.F32[PM_PAR_XPOS] >= source->pixels->col0);
+    onPic &= (params->data.F32[PM_PAR_XPOS] <  source->pixels->col0 + source->pixels->numCols);
+    onPic &= (params->data.F32[PM_PAR_YPOS] >= source->pixels->row0);
+    onPic &= (params->data.F32[PM_PAR_YPOS] <  source->pixels->row0 + source->pixels->numRows);
+    if (!onPic) pcm->modelConv->flags |= PM_MODEL_STATUS_OFFIMAGE;
+
+    source->mode |= PM_SOURCE_MODE_FITTED; // XXX is this needed?
+
+    psFree(myMin);
+    psFree(covar);
+
+    return true;
+}
+
+bool pmSourceModelGuessPCM (pmPCMdata *pcm, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal) {
+
+    if (!pcm->modelConv->modelGuess(pcm->modelConv, source)) {
+	return false;
+    }
+    return true;
+
+    // generate copy of the model
+    // XXX we could modify the parameter values or even the model 
+    // here based on the observed seeing (some lookup table...)
+
+    // XXX test : modify the Io, SXX, SYY terms based on the psf SXX, SYY terms:
+    // SXX,SYY in model parameters are sqrt(2) * shape.Sxx,Syy
+    psEllipseShape psfShape;
+    psfShape.sx  = source->modelPSF->params->data.F32[PM_PAR_SXX] / M_SQRT2;
+    psfShape.sxy = source->modelPSF->params->data.F32[PM_PAR_SXY];
+    psfShape.sy  = source->modelPSF->params->data.F32[PM_PAR_SYY] / M_SQRT2;
+
+    psEllipseAxes psfAxes = psEllipseShapeToAxes (psfShape, 20.0);
+    if (!isfinite(psfAxes.major)) return false;
+    if (!isfinite(psfAxes.minor)) return false;
+    if (!isfinite(psfAxes.theta)) return false;
+
+    // XXX test : modify the Io, SXX, SYY terms based on the psf SXX, SYY terms:
+    psEllipseShape extShape;
+    extShape.sx  = pcm->modelConv->params->data.F32[PM_PAR_SXX] / M_SQRT2;
+    extShape.sxy = pcm->modelConv->params->data.F32[PM_PAR_SXY];
+    extShape.sy  = pcm->modelConv->params->data.F32[PM_PAR_SYY] / M_SQRT2;
+
+    psEllipseAxes extAxes = psEllipseShapeToAxes (extShape, 20.0);
+    if (!isfinite(extAxes.major)) return false;
+    if (!isfinite(extAxes.minor)) return false;
+    if (!isfinite(extAxes.theta)) return false;
+
+    // decrease the initial guess ellipse by psf_minor axis:
+    psEllipseAxes extAxesMod;
+    extAxesMod.major = sqrt (PS_MAX (0.25, PS_SQR(extAxes.major) - PS_SQR(psfAxes.minor)));
+    extAxesMod.minor = sqrt (PS_MAX (0.25, PS_SQR(extAxes.minor) - PS_SQR(psfAxes.minor)));
+    extAxesMod.theta = extAxes.theta;
+
+    psEllipseShape extShapeMod = psEllipseAxesToShape (extAxesMod);
+    if (!isfinite(extShapeMod.sx))  return false;
+    if (!isfinite(extShapeMod.sy))  return false;
+    if (!isfinite(extShapeMod.sxy)) return false;
+
+    pcm->modelConv->params->data.F32[PM_PAR_SXX] = extShapeMod.sx * M_SQRT2;
+    pcm->modelConv->params->data.F32[PM_PAR_SXY] = extShapeMod.sxy;
+    pcm->modelConv->params->data.F32[PM_PAR_SYY] = extShapeMod.sy * M_SQRT2;
+
+    // increase the initial guess central intensity by 2pi r^2:
+    pcm->modelConv->params->data.F32[PM_PAR_I0] *= (1.0 + PS_SQR(psfAxes.minor) / PS_SQR(extAxesMod.minor));
+
+    return true;
+}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitSet.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitSet.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitSet.c	(revision 29060)
@@ -22,23 +22,30 @@
 #include "pmHDU.h"
 #include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
-#include "pmModelClass.h"
+
 #include "pmSourceFitModel.h"
 #include "pmSourceFitSet.h"
 
 // save as static values so they may be set externally
-static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15;
-static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1;
-static psF32 PM_SOURCE_FIT_MODEL_WEIGHT = 1.0;
-static bool  PM_SOURCE_FIT_MODEL_PIX_WEIGHTS = true;
+// static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15;
+// static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1;
+// static psF32 PM_SOURCE_FIT_MODEL_WEIGHT = 1.0;
+// static bool  PM_SOURCE_FIT_MODEL_PIX_WEIGHTS = true;
 
 /********************* Source Model Set Functions ***************************/
@@ -429,5 +436,5 @@
 bool pmSourceFitSet (pmSource *source,
                      psArray *modelSet,
-                     pmSourceFitMode mode,
+		     pmSourceFitOptions *options,
                      psImageMaskType maskVal)
 {
@@ -478,11 +485,11 @@
             // as variance to avoid the bias from systematic errors here we would just use the
             // source sky variance
-            if (PM_SOURCE_FIT_MODEL_PIX_WEIGHTS) {
-                yErr->data.F32[nPix] = 1.0 / source->variance->data.F32[i][j];
-            } else {
-                yErr->data.F32[nPix] = 1.0 / PM_SOURCE_FIT_MODEL_WEIGHT;
-            }
-            nPix++;
-        }
+            if (options->poissonErrors) {
+		yErr->data.F32[nPix] = 1.0 / source->variance->data.F32[i][j];
+	    } else {
+		yErr->data.F32[nPix] = 1.0 / options->weight;
+	    }
+	    nPix++;
+	}
     }
     x->n = nPix;
@@ -490,49 +497,49 @@
     yErr->n = nPix;
 
-    // create the FitSet for this thread and set the initial parameter guesses
+// create the FitSet for this thread and set the initial parameter guesses
     pmSourceFitSetData *thisSet = pmSourceFitSetDataSet(modelSet);
 
-    // define param and deriv vectors for complete set of parameters
+// define param and deriv vectors for complete set of parameters
     psVector *params = psVectorAlloc (thisSet->nParamSet, PS_TYPE_F32);
 
-    // set the param and deriv vectors based on the curent values
+// set the param and deriv vectors based on the curent values
     pmSourceFitSetJoin (NULL, params, thisSet);
 
-    // create the minimization constraints
+// create the minimization constraints
     psMinConstraint *constraint = psMinConstraintAlloc();
     constraint->paramMask = psVectorAlloc (thisSet->nParamSet, PS_TYPE_VECTOR_MASK);
     constraint->checkLimits = pmSourceFitSetCheckLimits;
 
-    pmSourceFitSetMasks (constraint, thisSet, mode);
-
-    // force the floating parameters to fall within the contraint ranges
+    pmSourceFitSetMasks (constraint, thisSet, options->mode);
+
+// force the floating parameters to fall within the contraint ranges
     for (int i = 0; i < params->n; i++) {
-        pmSourceFitSetCheckLimits (PS_MINIMIZE_PARAM_MIN, i, params->data.F32, NULL);
-        pmSourceFitSetCheckLimits (PS_MINIMIZE_PARAM_MAX, i, params->data.F32, NULL);
+	pmSourceFitSetCheckLimits (PS_MINIMIZE_PARAM_MIN, i, params->data.F32, NULL);
+	pmSourceFitSetCheckLimits (PS_MINIMIZE_PARAM_MAX, i, params->data.F32, NULL);
     }
 
     if (psTraceGetLevel("psModules.objects") >= 5) {
-        for (int i = 0; i < params->n; i++) {
-            fprintf (stderr, "%d %f %d\n", i, params->data.F32[i], constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
-        }
+	for (int i = 0; i < params->n; i++) {
+	    fprintf (stderr, "%d %f %d\n", i, params->data.F32[i], constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i]);
+	}
     }
 
     if (nPix <  thisSet->nParamSet + 1) {
-        psTrace (__func__, 4, "insufficient valid pixels\n");
-        psTrace("psModules.objects", 10, "---- %s() end : fail pixels ----\n", __func__);
-        for (int i = 0; i < modelSet->n; i++) {
-            pmModel *model = modelSet->data[i];
-            model->flags |= PM_MODEL_STATUS_BADARGS;
-        }
-        psFree (x);
-        psFree (y);
-        psFree (yErr);
-        psFree (params);
-        psFree(constraint);
-        pmSourceFitSetDataClear(); // frees thisSet and removes if from the array of fitSets
-        return(false);
-    }
-
-    psMinimization *myMin = psMinimizationAlloc (PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, PM_SOURCE_FIT_MODEL_TOLERANCE);
+	psTrace (__func__, 4, "insufficient valid pixels\n");
+	psTrace("psModules.objects", 10, "---- %s() end : fail pixels ----\n", __func__);
+	for (int i = 0; i < modelSet->n; i++) {
+	    pmModel *model = modelSet->data[i];
+	    model->flags |= PM_MODEL_STATUS_BADARGS;
+	}
+	psFree (x);
+	psFree (y);
+	psFree (yErr);
+	psFree (params);
+	psFree(constraint);
+	pmSourceFitSetDataClear(); // frees thisSet and removes if from the array of fitSets
+	return(false);
+    }
+
+    psMinimization *myMin = psMinimizationAlloc (options->nIter, options->minTol, options->maxTol);
 
     psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
@@ -540,35 +547,35 @@
     fitStatus = psMinimizeLMChi2(myMin, covar, params, constraint, x, y, yErr, pmSourceFitSetFunction);
     if (!fitStatus) {
-        psTrace("psModules.objects", 4, "Failed to fit model (%ld components)\n", modelSet->n);
-    }
-
-    // parameter errors from the covariance matrix
+	psTrace("psModules.objects", 4, "Failed to fit model (%ld components)\n", modelSet->n);
+    }
+
+// parameter errors from the covariance matrix
     psVector *dparams = psVectorAlloc (thisSet->nParamSet, PS_TYPE_F32);
     for (int i = 0; i < dparams->n; i++) {
-        if ((constraint->paramMask != NULL) && constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i])
-            continue;
-        dparams->data.F32[i] = sqrt(covar->data.F32[i][i]);
-    }
-
-    // get the Gauss-Newton distance for fixed model parameters
+	if ((constraint->paramMask != NULL) && constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i])
+	    continue;
+	dparams->data.F32[i] = sqrt(covar->data.F32[i][i]);
+    }
+
+// get the Gauss-Newton distance for fixed model parameters
     if (constraint->paramMask != NULL) {
-        psVector *delta = psVectorAlloc (params->n, PS_TYPE_F32);
-        psVector *altmask = psVectorAlloc (params->n, PS_TYPE_VECTOR_MASK);
-        altmask->data.PS_TYPE_VECTOR_MASK_DATA[0] = 1;
-        for (int i = 1; i < dparams->n; i++) {
-            altmask->data.PS_TYPE_VECTOR_MASK_DATA[i] = (constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) ? 0 : 1;
-        }
-        psMinimizeGaussNewtonDelta(delta, params, altmask, x, y, yErr, pmSourceFitSetFunction);
-
-        for (int i = 0; i < dparams->n; i++) {
-            if (!constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i])
-                continue;
-            // note that delta is the value *subtracted* from the parameter
-            // to get the new guess.  for dparams to represent the direction
-            // of motion, we need to take -delta
-            dparams->data.F32[i] = -delta->data.F32[i];
-        }
-        psFree (delta);
-        psFree (altmask);
+	psVector *delta = psVectorAlloc (params->n, PS_TYPE_F32);
+	psVector *altmask = psVectorAlloc (params->n, PS_TYPE_VECTOR_MASK);
+	altmask->data.PS_TYPE_VECTOR_MASK_DATA[0] = 1;
+	for (int i = 1; i < dparams->n; i++) {
+	    altmask->data.PS_TYPE_VECTOR_MASK_DATA[i] = (constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i]) ? 0 : 1;
+	}
+	psMinimizeGaussNewtonDelta(delta, params, altmask, x, y, yErr, pmSourceFitSetFunction);
+
+	for (int i = 0; i < dparams->n; i++) {
+	    if (!constraint->paramMask->data.PS_TYPE_VECTOR_MASK_DATA[i])
+		continue;
+	    // note that delta is the value *subtracted* from the parameter
+	    // to get the new guess.  for dparams to represent the direction
+	    // of motion, we need to take -delta
+	    dparams->data.F32[i] = -delta->data.F32[i];
+	}
+	psFree (delta);
+	psFree (altmask);
     }
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitSet.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitSet.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceFitSet.h	(revision 29060)
@@ -56,5 +56,5 @@
     pmSource *source,                   ///< The input pmSource
     psArray *modelSet,                  ///< model to be fitted
-    pmSourceFitMode mode,               ///< define parameters to be fitted
+    pmSourceFitOptions *options,	///< define options for fitting process
     psImageMaskType maskVal             ///< Vale to mask
 
Index: anches/sc_branches/trunkTest/psModules/src/objects/pmSourceGroup.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceGroup.h	(revision 29059)
+++ 	(revision )
@@ -1,44 +1,0 @@
-/* @file  pmSourceGroup.h
- *
- * @author EAM, IfA
- *
- * @version $Revision: $
- * @date $Date: 2009-02-16 22:30:50 $
- * Copyright 2009 Institute for Astronomy, University of Hawaii
- */
-
-# ifndef PM_SOURCE_GROUP_H
-# define PM_SOURCE_GROUP_H
-
-#include <pslib.h>
-#include "pmPeaks.h"
-#include "pmModel.h"
-#include "pmMoments.h"
-#include "pmSourceExtendedPars.h"
-
-/// @addtogroup Objects Object Detection / Analysis Functions
-/// @{
-
-#include <pmSourceMasks.h>
-
-/** pmSourceGroup data structure
- *
- *  A source group is a connected set of source measurements with a
- *  common connection.  Each source in the group represents the
- *  detection of some astronomical object on a single each.  The group
- *  represents the related collection of measurements.  The fits are
- *  coupled in some way.  For example, they may all have the same
- *  position, but independent fluxes.  Or, they may have a common set
- *  of positions and shape parameters.  Or the position in each image
- *  may be related by a function.
- *
- *  XXX is thre any info that is neaded for each source group beyond that carried by the sources (besides ID)?
- */
-struct pmSource {
-  int seq;                            ///< ID for output (generated on write OR set on read)
-  psArray *sources;
-} pmSourceGroup;
-
-
-/// @}
-# endif /* PM_SOURCE_GROUP_H */
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceGroups.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceGroups.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceGroups.c	(revision 29060)
@@ -6,6 +6,28 @@
 #include <pslib.h>
 
+#include "pmHDU.h"
 #include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmSourceGroups.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceGroups.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceGroups.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceGroups.h	(revision 29060)
@@ -1,8 +1,4 @@
 #ifndef PM_SOURCE_GROUPS_H
 #define PM_SOURCE_GROUPS_H
-
-#include <pslib.h>
-
-#include "pmFPA.h"
 
 /// Groups of sources
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO.c	(revision 29060)
@@ -31,16 +31,25 @@
 #include "pmConceptsRead.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
+#include "pmPSFtry.h"
+
 #include "pmDetections.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
 #include "pmDetEff.h"
 #include "pmSourceIO.h"
@@ -326,4 +335,15 @@
 }
 
+# define PM_SOURCES_WRITE(NAME,TYPE)					\
+    if (!strcmp (exttype, NAME)) {					\
+	status &= pmSourcesWrite_##TYPE(file->fits, readout, sources, file->header, outhead, dataname, recipe); \
+	if (xsrcname) {							\
+	    status &= pmSourcesWrite_##TYPE##_XSRC(file->fits, readout, sources, file->header, xsrcname, recipe); \
+	}								\
+	if (xfitname) {							\
+	    status &= pmSourcesWrite_##TYPE##_XFIT (file->fits, readout, sources, file->header, xfitname); \
+	}								\
+    }
+
 // write out all readout-level Objects files for this cell
 bool pmReadoutWriteObjects (pmReadout *readout, const pmFPAview *view, pmFPAfile *file, const pmConfig *config)
@@ -360,4 +380,5 @@
     }
 
+    // the older types (RAW, OBJ, SX, CMP) are for backwards compatibility -- deprecate eventually?
     switch (file->type) {
       case PM_FPA_FILE_RAW:
@@ -518,72 +539,19 @@
 		psMetadataAddStr (outhead, PS_LIST_TAIL, "XFITNAME", PS_META_REPLACE, "name of XFIT table extension", xfitname);
             }
-
-            // XXX these are case-sensitive since the EXTYPE is case-sensitive
+    
+
+            // these are case-sensitive since the EXTYPE is case-sensitive
             status = true;
-            if (!strcmp (exttype, "SMPDATA")) {
-                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);
-            }
-            if (!strcmp (exttype, "PS1_DEV_1")) {
-                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);
-            }
-            if (!strcmp (exttype, "PS1_V1")) {
-                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);
-            }
-            if (!strcmp (exttype, "PS1_SV1")) {
-                status &= pmSourcesWrite_CMF_PS1_SV1 (file->fits, readout, sources, file->header, outhead, dataname, recipe);
-            }
-            if (!strcmp (exttype, "PS1_DV1")) {
-                status &= pmSourcesWrite_CMF_PS1_DV1 (file->fits, readout, sources, file->header, outhead, dataname);
-            }
-
-            if (xsrcname) {
-		if (!strcmp (exttype, "PS1_DEV_1")) {
-		    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);
-		}
-		if (!strcmp (exttype, "PS1_V1")) {
-		    status &= pmSourcesWrite_CMF_PS1_V1_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe);
-		}
-		if (!strcmp (exttype, "PS1_V2")) {
-		    status &= pmSourcesWrite_CMF_PS1_V2_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe);
-		}
-		if (!strcmp (exttype, "PS1_SV1")) {
-		    status &= pmSourcesWrite_CMF_PS1_SV1_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe);
-		}
-		if (!strcmp (exttype, "PS1_DV1")) {
-		    status &= pmSourcesWrite_CMF_PS1_DV1_XSRC (file->fits, readout, sources, file->header, xsrcname, recipe);
-		}
-            }
-            if (xfitname) {
-		if (!strcmp (exttype, "PS1_DEV_1")) {
-		    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);
-		}
-		if (!strcmp (exttype, "PS1_V1")) {
-		    status &= pmSourcesWrite_CMF_PS1_V1_XFIT (file->fits, readout, sources, xfitname);
-		}
-		if (!strcmp (exttype, "PS1_V2")) {
-		    status &= pmSourcesWrite_CMF_PS1_V2_XFIT (file->fits, readout, sources, xfitname);
-		}
-		if (!strcmp (exttype, "PS1_SV1")) {
-		    status &= pmSourcesWrite_CMF_PS1_SV1_XFIT (file->fits, readout, sources, xfitname);
-		}
-		if (!strcmp (exttype, "PS1_DV1")) {
-		    status &= pmSourcesWrite_CMF_PS1_DV1_XFIT (file->fits, readout, sources, xfitname);
-		}
-            }
+	    PM_SOURCES_WRITE("SMPDATA",   SMPDATA);
+	    PM_SOURCES_WRITE("PS1_DEV_0", PS1_DEV_0);
+	    PM_SOURCES_WRITE("PS1_DEV_1", PS1_DEV_1);
+	    PM_SOURCES_WRITE("PS1_CAL_0", PS1_CAL_0);
+	    PM_SOURCES_WRITE("PS1_V1",    CMF_PS1_V1);
+	    PM_SOURCES_WRITE("PS1_V2",    CMF_PS1_V2);
+	    PM_SOURCES_WRITE("PS1_V3",    CMF_PS1_V3);
+	    PM_SOURCES_WRITE("PS1_SV1",   CMF_PS1_SV1);
+	    PM_SOURCES_WRITE("PS1_DV1",   CMF_PS1_DV1);
+	    PM_SOURCES_WRITE("PS1_DV2",   CMF_PS1_DV2);
+
 	    psFree (outhead);
 	    psFree (exttype);
@@ -1039,4 +1007,7 @@
                 sources = pmSourcesRead_CMF_PS1_DV1 (file->fits, hdu->header);
             }
+            if (!strcmp (exttype, "PS1_DV2")) {
+                sources = pmSourcesRead_CMF_PS1_DV2 (file->fits, hdu->header);
+            }
 
             if (!pmReadoutReadDetEff(file->fits, readout, deteffname)) {
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO.h	(revision 29060)
@@ -24,32 +24,46 @@
 bool pmSourcesWriteCMP (psArray *sources, char *filename, psMetadata *header);
 
-bool pmSourcesWrite_SMPDATA (psFits *fits, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname);
-bool pmSourcesWrite_PS1_DEV_0 (psFits *fits, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname);
+bool pmSource_CMF_WritePHU (const pmFPAview *view, pmFPAfile *file, pmConfig *config);
 
-bool pmSourcesWrite_PS1_DEV_1 (psFits *fits, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname);
-bool pmSourcesWrite_PS1_DEV_1_XSRC (psFits *fits, psArray *sources, char *extname, psMetadata *recipe);
-bool pmSourcesWrite_PS1_DEV_1_XFIT (psFits *fits, psArray *sources, char *extname);
+// All of these functions need to use the same API, even if not all elements are used in a specific case
+bool pmSourcesWrite_SMPDATA(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_SMPDATA_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_SMPDATA_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
 
-bool pmSourcesWrite_PS1_CAL_0 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname);
-bool pmSourcesWrite_PS1_CAL_0_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
-bool pmSourcesWrite_PS1_CAL_0_XFIT (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+bool pmSourcesWrite_PS1_DEV_0(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_PS1_DEV_0_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_PS1_DEV_0_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
 
-bool pmSourcesWrite_CMF_PS1_V1 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname);
-bool pmSourcesWrite_CMF_PS1_V1_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
-bool pmSourcesWrite_CMF_PS1_V1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname);
+bool pmSourcesWrite_PS1_DEV_1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_PS1_DEV_1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_PS1_DEV_1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
 
-bool pmSourcesWrite_CMF_PS1_V2 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname);
-bool pmSourcesWrite_CMF_PS1_V2_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
-bool pmSourcesWrite_CMF_PS1_V2_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname);
+bool pmSourcesWrite_PS1_CAL_0(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_PS1_CAL_0_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_PS1_CAL_0_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
 
-bool pmSourcesWrite_CMF_PS1_SV1 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
-bool pmSourcesWrite_CMF_PS1_SV1_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
-bool pmSourcesWrite_CMF_PS1_SV1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname);
+bool pmSourcesWrite_CMF_PS1_V1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_V1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_V1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
 
-bool pmSourcesWrite_CMF_PS1_DV1 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname);
-bool pmSourcesWrite_CMF_PS1_DV1_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
-bool pmSourcesWrite_CMF_PS1_DV1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname);
+bool pmSourcesWrite_CMF_PS1_V2(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_V2_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_V2_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
 
-bool pmSource_CMF_WritePHU (const pmFPAview *view, pmFPAfile *file, pmConfig *config);
+bool pmSourcesWrite_CMF_PS1_V3(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_V3_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_V3_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+
+bool pmSourcesWrite_CMF_PS1_SV1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_SV1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_SV1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+
+bool pmSourcesWrite_CMF_PS1_DV1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_DV1_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_DV1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
+
+bool pmSourcesWrite_CMF_PS1_DV2(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_DV2_XSRC(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe);
+bool pmSourcesWrite_CMF_PS1_DV2_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname);
 
 psArray *pmSourcesReadCMP (char *filename, psMetadata *header);
@@ -63,4 +77,5 @@
 psArray *pmSourcesRead_CMF_PS1_SV1 (psFits *fits, psMetadata *header);
 psArray *pmSourcesRead_CMF_PS1_DV1 (psFits *fits, psMetadata *header);
+psArray *pmSourcesRead_CMF_PS1_DV2 (psFits *fits, psMetadata *header);
 
 bool pmSourcesWritePSFs (psArray *sources, char *filename);
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_DV1.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -47,6 +56,5 @@
 // This version has elements intended for difference images & forced photometry:
 // diffStats entries (good for dipoles); flux + flux error (for insignificant detections)
-bool pmSourcesWrite_CMF_PS1_DV1 (psFits *fits, pmReadout *readout, psArray *sources,
-                                psMetadata *imageHeader, psMetadata *tableHeader, char *extname)
+bool pmSourcesWrite_CMF_PS1_DV1 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -194,5 +202,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeight);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
@@ -324,9 +332,15 @@
         source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
         source->peak->flux = peakFlux;
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
         source->peak->dx   = dPAR[PM_PAR_XPOS];
         source->peak->dy   = dPAR[PM_PAR_YPOS];
-        source->peak->SN   = sqrt(source->peak->flux); // XXX a proxy: various functions sort by peak S/N
-
-        source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF");
+        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
+          source->peak->SN = 1.0 / source->errMag;
+        } else {
+          source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
+        }
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
         source->crNsigma  = psMetadataLookupF32 (&status, row, "CR_NSIGMA");
         source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA");
@@ -536,5 +550,5 @@
 
 // XXX this layout is still the same as PS1_DEV_1
-bool pmSourcesWrite_CMF_PS1_DV1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname)
+bool pmSourcesWrite_CMF_PS1_DV1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
 {
 
@@ -585,4 +599,7 @@
             assert (model);
 
+	    // skip models which were not actually fitted
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
+
             PAR = model->params->data.F32;
             dPAR = model->dparams->data.F32;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_DV2.c	(revision 29060)
@@ -0,0 +1,691 @@
+/** @file  pmSourceIO.c
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-18 02:44:19 $
+ *
+ *  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 "pmConfig.h"
+#include "pmDetrendDB.h"
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPALevel.h"
+#include "pmFPAview.h"
+#include "pmFPAfile.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+
+#include "pmSourceIO.h"
+
+// panstarrs-style FITS table output (header + table in 1st extension)
+// this format consists of a header derived from the image header
+// followed by a zero-size matrix, followed by the table data
+
+// This version has elements intended for difference images & forced photometry:
+// diffStats entries (good for dipoles); flux + flux error (for insignificant detections)
+bool pmSourcesWrite_CMF_PS1_DV2 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
+{
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    PS_ASSERT_PTR_NON_NULL(sources, false);
+    PS_ASSERT_PTR_NON_NULL(extname, false);
+
+    int i;
+    psArray *table;
+    psMetadata *row;
+    psF32 *PAR, *dPAR;
+    psEllipseAxes axes;
+    psF32 xPos, yPos;
+    psF32 xErr, yErr;
+    psF32 errMag, chisq, apRadius;
+    psS32 nPix, nDOF;
+
+    pmChip *chip = readout->parent->parent;
+    pmFPA  *fpa  = chip->parent;
+
+    bool status1 = false;
+    bool status2 = false;
+    float magOffset = NAN;
+    float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
+    float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
+    if (!isfinite(zeropt)) {
+        zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
+    }
+    if (status1 && status2 && (exptime > 0.0)) {
+        magOffset = zeropt + 2.5*log10(exptime);
+    }
+    float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
+
+    // if the sequence is defined, write these in seq order; otherwise
+    // write them in S/N order:
+    if (sources->n > 0) {
+        pmSource *source = (pmSource *) sources->data[0];
+        if (source->seq == -1) {
+          // let's write these out in S/N order
+          sources = psArraySort (sources, pmSourceSortBySN);
+        } else {
+          sources = psArraySort (sources, pmSourceSortBySeq);
+        }
+    }
+
+    table = psArrayAllocEmpty (sources->n);
+
+    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
+    // by the time we call this function, all values should be assigned.  let's use asserts to be sure in some cases.
+    for (i = 0; i < sources->n; i++) {
+        pmSource *source = (pmSource *) sources->data[i];
+
+        // If source->seq is -1, source was generated in this analysis.  If source->seq is
+        // not -1, source was read from elsewhere: in the latter case, preserve the source
+        // ID.  source.seq is used instead of source.id since the latter is a const
+        // generated on Alloc, and would thus be wrong for read in sources.
+        if (source->seq == -1) {
+          source->seq = i;
+        }
+
+        // no difference between PSF and non-PSF model
+        pmModel *model = source->modelPSF;
+
+        if (model != NULL) {
+            PAR = model->params->data.F32;
+            dPAR = model->dparams->data.F32;
+            xPos = PAR[PM_PAR_XPOS];
+            yPos = PAR[PM_PAR_YPOS];
+            if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
+              xErr = dPAR[PM_PAR_XPOS];
+              yErr = dPAR[PM_PAR_YPOS];
+            } else {
+              // in linear-fit mode, there is no error on the centroid
+              xErr = source->peak->dx;
+              yErr = source->peak->dy;
+            }
+            if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
+                axes = pmPSF_ModelToAxes (PAR, 20.0);
+            } else {
+                axes.major = NAN;
+                axes.minor = NAN;
+                axes.theta = NAN;
+            }
+            chisq = model->chisq;
+            nDOF = model->nDOF;
+            nPix = model->nPix;
+            apRadius = source->apRadius;
+            errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
+        } else {
+            xPos = source->peak->xf;
+            yPos = source->peak->yf;
+            xErr = source->peak->dx;
+            yErr = source->peak->dy;
+            axes.major = NAN;
+            axes.minor = NAN;
+            axes.theta = NAN;
+            chisq = NAN;
+            nDOF = 0;
+            nPix = 0;
+            apRadius = NAN;
+            errMag = NAN;
+        }
+
+        float calMag = isfinite(magOffset) ? source->psfMag + magOffset : NAN;
+        float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
+        psS16 nImageOverlap = 1;
+
+        psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
+        float posAngle = 0.0;
+        float pltScale = 0.0;
+        pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);
+
+	pmSourceDiffStats diffStats;
+	pmSourceDiffStatsInit(&diffStats);
+	if (source->diffStats) {
+	    diffStats = *source->diffStats;
+	}
+
+        row = psMetadataAlloc ();
+        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
+        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           xPos);
+        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           yPos);
+        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  xErr); // XXX this is only measured for non-linear fits
+        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr); // XXX this is only measured for non-linear fits
+        psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         posAngle*PS_DEG_RAD);
+        psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       pltScale*PS_DEG_RAD*3600.0);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfFlux);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental magnitude",        source->psfFluxErr);
+        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
+        psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   calMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);
+        psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                ptSky.r*PS_DEG_RAD);
+        psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               ptSky.d*PS_DEG_RAD);
+        psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
+        psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",                         source->skyErr);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           chisq);
+        psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA",        PS_DATA_F32, "Nsigma deviations from PSF to CF",           source->crNsigma);
+        psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA",       PS_DATA_F32, "Nsigma deviations from PSF to EXT",          source->extNsigma);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     axes.major);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor (bad)",          source->pixWeightNotBad);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT",   PS_DATA_F32, "PSF coverage/quality factor (poor)",         source->pixWeightNotPoor);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
+
+        // distinguish moments measure from window vs S/N > XX ??
+        float mxx = source->moments ? source->moments->Mxx : NAN;
+        float mxy = source->moments ? source->moments->Mxy : NAN;
+        float myy = source->moments ? source->moments->Myy : NAN;
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      mxx);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      mxy);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      myy);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NPOS",        PS_DATA_S32, "nPos (n pix > 3 sigma)",                    diffStats.nGood);
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_FRATIO",      PS_DATA_F32, "fPos / (fPos + fNeg)",                      diffStats.fRatio);
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_BAD",  PS_DATA_F32, "nPos / (nPos + nNeg)",                      diffStats.nRatioBad);
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_MASK", PS_DATA_F32, "nPos / (nPos + nMask)",                     diffStats.nRatioMask);
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_NRATIO_ALL",  PS_DATA_F32, "nPos / (nGood + nMask + nBad)",             diffStats.nRatioAll);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_P",         PS_DATA_F32, "distance to positive match source",          diffStats.Rp);
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_P",        PS_DATA_F32, "signal-to-noise of pos match src",           diffStats.SNp);
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_R_M",         PS_DATA_F32, "distance to negative match source",          diffStats.Rm);
+        psMetadataAdd (row, PS_LIST_TAIL, "DIFF_SN_M",        PS_DATA_F32, "signal-to-noise of neg match src",           diffStats.SNm);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                      source->mode);
+        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags (group 2)",            source->mode2);
+
+        // XXX not sure how to get this : need to load Nimages with weight?
+        psMetadataAdd (row, PS_LIST_TAIL, "N_FRAMES",         PS_DATA_U16, "Number of frames overlapping source center", nImageOverlap);
+        psMetadataAdd (row, PS_LIST_TAIL, "PADDING",          PS_DATA_S16, "padding", 0);
+
+        psArrayAdd (table, 100, row);
+        psFree (row);
+
+        // EXT_NSIGMA will be NAN if: 1) contour ellipse is imaginary; 2) source is not
+        // subtracted
+
+        // CR_NSIGMA will be NAN if: 1) source is not subtracted; 2) source is on the image
+        // edge; 3) any pixels in the 3x3 peak region are masked;
+    }
+
+    psMetadata *header = psMetadataCopy(NULL, tableHeader);
+    pmSourceMasksHeader(header);
+
+    if (table->n == 0) {
+        psFitsWriteBlank(fits, header, extname);
+        psFree(table);
+        psFree(header);
+        return true;
+    }
+
+    psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname);
+    if (!psFitsWriteTable(fits, header, table, extname)) {
+        psError(PS_ERR_IO, false, "writing ext data %s\n", extname);
+        psFree(table);
+        psFree(header);
+        return false;
+    }
+    psFree(table);
+    psFree(header);
+
+    return true;
+}
+
+// read in a readout from the fits file
+psArray *pmSourcesRead_CMF_PS1_DV2 (psFits *fits, psMetadata *header)
+{
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    PS_ASSERT_PTR_NON_NULL(header, false);
+
+    bool status;
+    psF32 *PAR, *dPAR;
+    psEllipseAxes axes;
+
+    // define PSF model type
+    // XXX need to carry the extra model parameters
+    int modelType = pmModelClassGetType ("PS_MODEL_GAUSS");
+
+    char *PSF_NAME = psMetadataLookupStr (&status, header, "PSF_NAME");
+    if (PSF_NAME != NULL) {
+        modelType = pmModelClassGetType (PSF_NAME);
+    }
+    assert (modelType > -1);
+
+    // We get the size of the table, and allocate the array of sources first because the table
+    // is large and ephemeral --- when the table gets blown away, whatever is allocated after
+    // the table is read blocks the free.  In fact, it's better to read the table row by row.
+    long numSources = psFitsTableSize(fits); // Number of sources in table
+    psArray *sources = psArrayAlloc(numSources); // Array of sources, to return
+
+    // convert the table to the pmSource entriesa
+    for (int i = 0; i < numSources; i++) {
+        psMetadata *row = psFitsReadTableRow(fits, i); // Table row
+
+        pmSource *source = pmSourceAlloc ();
+        pmModel *model = pmModelAlloc (modelType);
+        source->modelPSF  = model;
+        source->type = PM_SOURCE_TYPE_STAR; // XXX this should be added to the flags
+
+        // NOTE: A SEGV here because "model" is NULL is probably caused by not initialising the models.
+        PAR = model->params->data.F32;
+        dPAR = model->dparams->data.F32;
+
+        source->seq       = psMetadataLookupU32 (&status, row, "IPP_IDET");
+        PAR[PM_PAR_XPOS]  = psMetadataLookupF32 (&status, row, "X_PSF");
+        PAR[PM_PAR_YPOS]  = psMetadataLookupF32 (&status, row, "Y_PSF");
+        dPAR[PM_PAR_XPOS] = psMetadataLookupF32 (&status, row, "X_PSF_SIG");
+        dPAR[PM_PAR_YPOS] = psMetadataLookupF32 (&status, row, "Y_PSF_SIG");
+        axes.major        = psMetadataLookupF32 (&status, row, "PSF_MAJOR");
+        axes.minor        = psMetadataLookupF32 (&status, row, "PSF_MINOR");
+        axes.theta        = psMetadataLookupF32 (&status, row, "PSF_THETA");
+
+        PAR[PM_PAR_SKY]   = psMetadataLookupF32 (&status, row, "SKY");
+        dPAR[PM_PAR_SKY]  = psMetadataLookupF32 (&status, row, "SKY_SIGMA");
+        source->sky       = PAR[PM_PAR_SKY];
+        source->skyErr    = dPAR[PM_PAR_SKY];
+
+        // XXX use these to determine PAR[PM_PAR_I0]?
+        source->psfFlux    = psMetadataLookupF32 (&status, row, "PSF_INST_FLUX");
+        source->psfFluxErr = psMetadataLookupF32 (&status, row, "PSF_INST_FLUX_SIG");
+
+        source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
+        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
+
+        // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
+        PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
+        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+
+        pmPSF_AxesToModel (PAR, axes);
+
+        float peakMag     = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
+        float peakFlux    = (isfinite(peakMag)) ? pow(10.0, -0.4*peakMag) : NAN;
+
+        // recreate the peak to match (xPos, yPos) +/- (xErr, yErr)
+        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
+        source->peak->flux = peakFlux;
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
+        source->peak->dx   = dPAR[PM_PAR_XPOS];
+        source->peak->dy   = dPAR[PM_PAR_YPOS];
+        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
+          source->peak->SN = 1.0 / source->errMag;
+        } else {
+          source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
+        }
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
+        source->pixWeightNotPoor = psMetadataLookupF32 (&status, row, "PSF_QF_PERFECT");
+        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.
+        model->chisq      = psMetadataLookupF32 (&status, row, "PSF_CHISQ");
+        model->nDOF       = psMetadataLookupS32 (&status, row, "PSF_NDOF");
+        model->nPix       = psMetadataLookupS32 (&status, row, "PSF_NPIX");
+
+        source->moments = pmMomentsAlloc ();
+        source->moments->Mxx = psMetadataLookupF32 (&status, row, "MOMENTS_XX");
+        source->moments->Mxy = psMetadataLookupF32 (&status, row, "MOMENTS_XY");
+        source->moments->Myy = psMetadataLookupF32 (&status, row, "MOMENTS_YY");
+
+        source->mode = psMetadataLookupU32 (&status, row, "FLAGS");
+        source->mode2 = psMetadataLookupU32 (&status, row, "FLAGS2");
+        assert (status);
+
+	int nPos = psMetadataLookupS32 (&status, row, "DIFF_NPOS");
+	if (nPos) {
+	    source->diffStats = pmSourceDiffStatsAlloc();
+	    source->diffStats->nGood      = nPos;
+	    source->diffStats->fRatio     = psMetadataLookupF32 (&status, row, "DIFF_FRATIO");
+	    source->diffStats->nRatioBad  = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_BAD");
+	    source->diffStats->nRatioMask = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_MASK");
+	    source->diffStats->nRatioAll  = psMetadataLookupF32 (&status, row, "DIFF_NRATIO_ALL");
+
+	    source->diffStats->Rp         = psMetadataLookupF32 (&status, row, "DIFF_R_P");
+	    source->diffStats->SNp        = psMetadataLookupF32 (&status, row, "DIFF_SN_P");
+	    source->diffStats->Rm         = psMetadataLookupF32 (&status, row, "DIFF_R_M");
+	    source->diffStats->SNm        = psMetadataLookupF32 (&status, row, "DIFF_SN_M");
+	}
+
+        sources->data[i] = source;
+        psFree(row);
+    }
+
+    return sources;
+}
+
+// XXX this layout is still the same as PS1_DEV_1
+bool pmSourcesWrite_CMF_PS1_DV2_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+
+    bool status;
+    psArray *table;
+    psMetadata *row;
+    psF32 *PAR, *dPAR;
+    psF32 xPos, yPos;
+    psF32 xErr, yErr;
+
+    // create a header to hold the output data
+    psMetadata *outhead = psMetadataAlloc ();
+
+    // write the links to the image header
+    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTNAME", PS_META_REPLACE, "xsrc table extension", extname);
+
+    // let's write these out in S/N order
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    table = psArrayAllocEmpty (sources->n);
+
+    // 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");
+
+    psVector *radialBinsLower = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
+    psVector *radialBinsUpper = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
+    assert (radialBinsLower->n == radialBinsUpper->n);
+
+    // we write out all sources, regardless of quality.  the source flags tell us the state
+    for (int i = 0; i < sources->n; i++) {
+        // skip source if it is not a ext sourc
+        // XXX we have two places that extended source parameters are measured:
+        // psphotExtendedSources, which measures the aperture-like parameters and (potentially) the psf-convolved extended source models,
+        // psphotFitEXT, which does the simple extended source model fit (not psf-convolved)
+        // should we require both?
+
+        pmSource *source = sources->data[i];
+
+        // skip sources without measurements
+        if (source->extpars == NULL) continue;
+
+        // we require a PSF model fit (ignore the real crud)
+        pmModel *model = source->modelPSF;
+        if (model == NULL) continue;
+
+        // XXX I need to split the extended models from the extended aperture measurements
+        PAR = model->params->data.F32;
+        dPAR = model->dparams->data.F32;
+        xPos = PAR[PM_PAR_XPOS];
+        yPos = PAR[PM_PAR_YPOS];
+        xErr = dPAR[PM_PAR_XPOS];
+        yErr = dPAR[PM_PAR_YPOS];
+
+        row = psMetadataAlloc ();
+
+        // XXX we are not writing out the mode (flags) or the type (psf, ext, etc)
+        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
+        psMetadataAdd (row, PS_LIST_TAIL, "X_EXT",            PS_DATA_F32, "EXT model x coordinate",                     xPos);
+        psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT",            PS_DATA_F32, "EXT model y coordinate",                     yPos);
+        psMetadataAdd (row, PS_LIST_TAIL, "X_EXT_SIG",        PS_DATA_F32, "Sigma in EXT x coordinate",                  xErr);
+        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
+        if (doPetrosian) {
+            pmSourcePetrosianValues *petrosian = source->extpars->petrosian;
+            if (petrosian) {
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG",        PS_DATA_F32, "Petrosian Magnitude",       petrosian->mag);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR",    PS_DATA_F32, "Petrosian Magnitude Error", petrosian->magErr);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS",     PS_DATA_F32, "Petrosian Radius",          petrosian->rad);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error",    petrosian->radErr);
+            } else {
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG",        PS_DATA_F32, "Petrosian Magnitude",       NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR",    PS_DATA_F32, "Petrosian Magnitude Error", NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS",     PS_DATA_F32, "Petrosian Radius",          NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error",    NAN);
+            }
+        }
+
+        // Kron measurements
+        if (doKron) {
+            pmSourceKronValues *kron = source->extpars->kron;
+            if (kron) {
+                psMetadataAdd (row, PS_LIST_TAIL, "KRON_MAG",        PS_DATA_F32, "Kron Magnitude",       kron->mag);
+                psMetadataAdd (row, PS_LIST_TAIL, "KRON_MAG_ERR",    PS_DATA_F32, "Kron Magnitude Error", kron->magErr);
+                psMetadataAdd (row, PS_LIST_TAIL, "KRON_RADIUS",     PS_DATA_F32, "Kron Radius",          kron->rad);
+                psMetadataAdd (row, PS_LIST_TAIL, "KRON_RADIUS_ERR", PS_DATA_F32, "Kron Radius Error",    kron->radErr);
+            } else {
+                psMetadataAdd (row, PS_LIST_TAIL, "KRON_MAG",        PS_DATA_F32, "Kron Magnitude",       NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "KRON_MAG_ERR",    PS_DATA_F32, "Kron Magnitude Error", NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "KRON_RADIUS",     PS_DATA_F32, "Kron Radius",          NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "KRON_RADIUS_ERR", PS_DATA_F32, "Kron Radius Error",    NAN);
+            }
+        }
+
+        // Isophot measurements
+        // XXX insert header data: isophotal level
+        if (doIsophotal) {
+            pmSourceIsophotalValues *isophot = source->extpars->isophot;
+            if (isophot) {
+                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_MAG",        PS_DATA_F32, "Isophot Magnitude",       isophot->mag);
+                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_MAG_ERR",    PS_DATA_F32, "Isophot Magnitude Error", isophot->magErr);
+                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_RADIUS",     PS_DATA_F32, "Isophot Radius",          isophot->rad);
+                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_RADIUS_ERR", PS_DATA_F32, "Isophot Radius Error",    isophot->radErr);
+            } else {
+                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_MAG",        PS_DATA_F32, "Isophot Magnitude",       NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_MAG_ERR",    PS_DATA_F32, "Isophot Magnitude Error", NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_RADIUS",     PS_DATA_F32, "Isophot Radius",          NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_RADIUS_ERR", PS_DATA_F32, "Isophot Radius Error",    NAN);
+            }
+        }
+
+        // Flux Annuli
+        if (doAnnuli) {
+            pmSourceAnnuli *annuli = source->extpars->annuli;
+            if (annuli) {
+                psVector *fluxVal = annuli->flux;
+                psVector *fluxErr = annuli->fluxErr;
+                psVector *fluxVar = annuli->fluxVar;
+
+                for (int j = 0; j < fluxVal->n; j++) {
+                    char name[32];
+                    sprintf (name, "FLUX_VAL_R_%02d", j);
+                    psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux value in annulus", fluxVal->data.F32[j]);
+                    sprintf (name, "FLUX_ERR_R_%02d", j);
+                    psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux error in annulus", fluxErr->data.F32[j]);
+                    sprintf (name, "FLUX_VAR_R_%02d", j);
+                    psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux stdev in annulus", fluxVar->data.F32[j]);
+                }
+            } else {
+                for (int j = 0; j < radialBinsLower->n; j++) {
+                    char name[32];
+                    sprintf (name, "FLUX_VAL_R_%02d", j);
+                    psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux value in annulus", NAN);
+                    sprintf (name, "FLUX_ERR_R_%02d", j);
+                    psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux error in annulus", NAN);
+                    sprintf (name, "FLUX_VAR_R_%02d", j);
+                    psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "flux stdev in annulus", NAN);
+                }
+            }
+        }
+
+# endif
+        psArrayAdd (table, 100, row);
+        psFree (row);
+    }
+
+    if (table->n == 0) {
+        psFitsWriteBlank (fits, outhead, extname);
+        psFree (outhead);
+        psFree (table);
+        return true;
+    }
+
+    psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname);
+    if (!psFitsWriteTable (fits, outhead, table, extname)) {
+        psError(PS_ERR_IO, false, "writing ext data %s\n", extname);
+        psFree (outhead);
+        psFree(table);
+        return false;
+    }
+    psFree (outhead);
+    psFree (table);
+
+    return true;
+}
+
+// XXX this layout is still the same as PS1_DEV_1
+bool pmSourcesWrite_CMF_PS1_DV2_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
+{
+
+    psArray *table;
+    psMetadata *row;
+    psF32 *PAR, *dPAR;
+    psEllipseAxes axes;
+    psF32 xPos, yPos;
+    psF32 xErr, yErr;
+    char name[64];
+
+    // create a header to hold the output data
+    psMetadata *outhead = psMetadataAlloc ();
+
+    // write the links to the image header
+    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTNAME", PS_META_REPLACE, "xsrc table extension", extname);
+
+    // let's write these out in S/N order
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
+    int nParamMax = 0;
+    for (int i = 0; i < sources->n; i++) {
+        pmSource *source = sources->data[i];
+        if (source->modelFits == NULL) continue;
+        for (int j = 0; j < source->modelFits->n; j++) {
+            pmModel *model = source->modelFits->data[j];
+            assert (model);
+            nParamMax = PS_MAX (nParamMax, model->params->n);
+        }
+    }
+
+    table = psArrayAllocEmpty (sources->n);
+
+    // we write out all sources, regardless of quality.  the source flags tell us the state
+    for (int i = 0; i < sources->n; i++) {
+
+        pmSource *source = sources->data[i];
+
+        // XXX if no model fits are saved, write out modelEXT?
+        if (source->modelFits == NULL) continue;
+
+        // We have multiple sources : need to flag the one used to subtract the light (the 'best' model)
+        for (int j = 0; j < source->modelFits->n; j++) {
+
+            // choose the convolved EXT model, if available, otherwise the simple one
+            pmModel *model = source->modelFits->data[j];
+            assert (model);
+
+	    // skip models which were not actually fitted
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
+
+            PAR = model->params->data.F32;
+            dPAR = model->dparams->data.F32;
+            xPos = PAR[PM_PAR_XPOS];
+            yPos = PAR[PM_PAR_YPOS];
+            xErr = dPAR[PM_PAR_XPOS];
+            yErr = dPAR[PM_PAR_YPOS];
+
+            axes = pmPSF_ModelToAxes (PAR, 20.0);
+
+            row = psMetadataAlloc ();
+
+            // XXX we are not writing out the mode (flags) or the type (psf, ext, etc)
+            psMetadataAddU32 (row, PS_LIST_TAIL, "IPP_IDET",         0, "IPP detection identifier index",             source->seq);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "X_EXT",            0, "EXT model x coordinate",                     xPos);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "Y_EXT",            0, "EXT model y coordinate",                     yPos);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "X_EXT_SIG",        0, "Sigma in EXT x coordinate",                  xErr);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "Y_EXT_SIG",        0, "Sigma in EXT y coordinate",                  yErr);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_MAG",     0, "EXT fit instrumental magnitude",             model->mag);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_MAG_SIG", 0, "Sigma of PSF instrumental magnitude",        model->magErr);
+
+            psMetadataAddF32 (row, PS_LIST_TAIL, "NPARAMS",          0, "number of model parameters",                 model->params->n);
+            psMetadataAddStr (row, PS_LIST_TAIL, "MODEL_TYPE",       0, "name of model",                              pmModelClassGetName (model->type));
+
+            // XXX these should be major and minor, not 'x' and 'y'
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ",    0, "EXT width in x coordinate",                  axes.major);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN",    0, "EXT width in y coordinate",                  axes.minor);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA",        0, "EXT orientation angle",                      axes.theta);
+
+            // write out the other generic parameters
+            for (int k = 0; k < nParamMax; k++) {
+                if (k == PM_PAR_I0) continue;
+                if (k == PM_PAR_SKY) continue;
+                if (k == PM_PAR_XPOS) continue;
+                if (k == PM_PAR_YPOS) continue;
+                if (k == PM_PAR_SXX) continue;
+                if (k == PM_PAR_SXY) continue;
+                if (k == PM_PAR_SYY) continue;
+
+                snprintf (name, 64, "EXT_PAR_%02d", k);
+
+                if (k < model->params->n) {
+                    psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "", model->params->data.F32[k]);
+                } else {
+                    psMetadataAddF32 (row, PS_LIST_TAIL, name, PS_DATA_F32, "", NAN);
+                }
+            }
+
+            // XXX other parameters which may be set.
+            // XXX flag / value to define the model
+            // XXX write out the model type, fit status flags
+
+            psArrayAdd (table, 100, row);
+            psFree (row);
+        }
+    }
+
+    if (table->n == 0) {
+        psFitsWriteBlank (fits, outhead, extname);
+        psFree (outhead);
+        psFree (table);
+        return true;
+    }
+
+    psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname);
+    if (!psFitsWriteTable (fits, outhead, table, extname)) {
+        psError(PS_ERR_IO, false, "writing ext data %s\n", extname);
+        psFree (outhead);
+        psFree(table);
+        return false;
+    }
+    psFree (outhead);
+    psFree (table);
+    return true;
+}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_SV1.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -46,5 +55,5 @@
 
 // NOTE: this output function is intended for psphotStack analysis: it includes per-psf radial fluxes 
-// XXX currently in the 'read' function is NOT consistent with the 'write' function (does not read radial fluxes)
+// XXX currently, the 'read' function is NOT consistent with the 'write' function (does not read radial fluxes)
 
 bool pmSourcesWrite_CMF_PS1_SV1 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
@@ -62,4 +71,5 @@
     psF32 errMag, chisq, apRadius;
     psS32 nPix, nDOF;
+    char keyword1[80], keyword2[80];
 
     pmChip *chip = readout->parent->parent;
@@ -95,7 +105,18 @@
     // we use this just to define the output vectors (which must be present for all objects)
     bool status = false;
+    psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
     psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
     psAssert (radMax, "this must have been defined and tested earlier!");
     psAssert (radMax->n, "this must have been defined and tested earlier!");
+    psAssert (radMin->n == radMax->n, "inconsistent annular bins");
+
+    // write the radial profile apertures to header
+    for (int i = 0; i < radMax->n; i++) {
+      sprintf (keyword1, "RMIN_%02d", i);
+      sprintf (keyword2, "RMAX_%02d", i);
+      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);
+      psMetadataAddF32 (imageHeader, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
+    }
+
 
     // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
@@ -177,4 +198,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental flux",             source->psfFluxErr);
         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW",       PS_DATA_F32, "magnitude in reported aperture",             source->apMagRaw);
         psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
         psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
@@ -193,17 +215,46 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeight);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor (bad)",          source->pixWeightNotBad);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT",   PS_DATA_F32, "PSF coverage/quality factor (poor)",         source->pixWeightNotPoor);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
 
         // distinguish moments measure from window vs S/N > XX ??
-        float mxx = source->moments ? source->moments->Mxx : NAN;
-        float mxy = source->moments ? source->moments->Mxy : NAN;
-        float myy = source->moments ? source->moments->Myy : NAN;
-        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      mxx);
-        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      mxy);
-        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      myy);
-
-        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                      source->mode);
+        float Mxx = source->moments ? source->moments->Mxx : NAN;
+        float Mxy = source->moments ? source->moments->Mxy : NAN;
+        float Myy = source->moments ? source->moments->Myy : NAN;
+
+        float Mrf  = source->moments ? source->moments->Mrf : NAN;
+        float Mrh  = source->moments ? source->moments->Mrh : NAN;
+        float Krf  = source->moments ? source->moments->KronFlux : NAN;
+        float dKrf = source->moments ? source->moments->KronFluxErr : NAN;
+
+        float Kinner = source->moments ? source->moments->KronFinner : NAN;
+        float Kouter = source->moments ? source->moments->KronFouter : NAN;
+
+        float M_c3 = source->moments ? 1.0*source->moments->Mxxx - 3.0*source->moments->Mxyy : NAN;
+        float M_s3 = source->moments ? 3.0*source->moments->Mxxy - 1.0*source->moments->Myyy : NAN;
+        float M_c4 = source->moments ? 1.0*source->moments->Mxxxx - 6.0*source->moments->Mxxyy + 1.0*source->moments->Myyyy : NAN;
+        float M_s4 = source->moments ? 4.0*source->moments->Mxxxy - 4.0*source->moments->Mxyyy : NAN;
+
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      Mxx);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      Mxy);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      Myy);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3C",      PS_DATA_F32, "third momemt cos theta",                    M_c3);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3S",      PS_DATA_F32, "third momemt sin theta",                    M_s3);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4C",      PS_DATA_F32, "fourth momemt cos theta",                   M_c4);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4S",      PS_DATA_F32, "fourth momemt sin theta",                   M_s4);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",                       Mrf);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",                        Mrh);
+        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Krf);
+        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",                          dKrf);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Kinner);
+        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Kouter);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                     source->mode);
+        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                     source->mode2);
 
 	psVector *radFlux    = psVectorAlloc(radMax->n, PS_TYPE_F32);
@@ -352,9 +403,16 @@
         source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
         source->peak->flux = peakFlux;
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
         source->peak->dx   = dPAR[PM_PAR_XPOS];
         source->peak->dy   = dPAR[PM_PAR_YPOS];
-        source->peak->SN   = sqrt(source->peak->flux); // XXX a proxy: various functions sort by peak S/N
-
-        source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF");
+        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
+          source->peak->SN = 1.0 / source->errMag;
+        } else {
+          source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
+        }
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
+        source->pixWeightNotPoor = psMetadataLookupF32 (&status, row, "PSF_QF_PERFECT");
         source->crNsigma  = psMetadataLookupF32 (&status, row, "CR_NSIGMA");
         source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA");
@@ -371,5 +429,27 @@
         source->moments->Myy = psMetadataLookupF32 (&status, row, "MOMENTS_YY");
 
+        source->moments->Mrf         = psMetadataLookupF32 (&status, row, "MOMENTS_R1");
+        source->moments->Mrh         = psMetadataLookupF32 (&status, row, "MOMENTS_RH");
+        source->moments->KronFlux    = psMetadataLookupF32 (&status, row, "KRON_FLUX");
+        source->moments->KronFluxErr = psMetadataLookupF32 (&status, row, "KRON_FLUX_ERR");
+
+        source->moments->KronFinner  = psMetadataLookupF32 (&status, row, "KRON_FLUX_INNER");
+        source->moments->KronFouter  = psMetadataLookupF32 (&status, row, "KRON_FLUX_OUTER");
+
+	// XXX we do not save all of the 3rd and 4th moment parameters. when we load in data,
+	// we are storing enough information so the output will be consistent with the input
+        source->moments->Mxxx = +1.0 * psMetadataLookupF32 (&status, row, "MOMENTS_M3C");
+        source->moments->Mxxy = 0.0;
+        source->moments->Mxyy = 0.0;
+        source->moments->Myyy = -1.0 * psMetadataLookupF32 (&status, row, "MOMENTS_M3S");
+
+        source->moments->Mxxxx = +1.00 * psMetadataLookupF32 (&status, row, "MOMENTS_M4C");
+        source->moments->Mxxxy = 0.0;
+        source->moments->Mxxyy = 0.0;
+        source->moments->Mxyyy = -0.25 * psMetadataLookupF32 (&status, row, "MOMENTS_M4S");
+        source->moments->Myyyy = 0.0;
+
         source->mode = psMetadataLookupU32 (&status, row, "FLAGS");
+        source->mode2 = psMetadataLookupU32 (&status, row, "FLAGS2");
         assert (status);
 
@@ -391,4 +471,5 @@
     psF32 xErr, yErr;
     int nRow = -1;
+    char keyword1[80], keyword2[80];
 
     // create a header to hold the output data
@@ -422,6 +503,4 @@
     bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
     bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
-    // bool doIsophotal    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ISOPHOTAL");
-    // bool doKron         = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_KRON");
 
     psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
@@ -429,24 +508,14 @@
     psAssert (radMin->n == radMax->n, "inconsistent annular bins");
 
-    // int nRadialBins = 0;
-    // if (doAnnuli) {
-    // 	// get the max count of radial bins
-    // 	for (int i = 0; i < sources->n; i++) {
-    // 	    pmSource *source = sources->data[i];
-    // 	    if (!source->extpars) continue;
-    // 	    if (!source->extpars->radProfile ) continue;
-    //         if (!source->extpars->radProfile->binSB) continue;
-    // 	    nRadialBins = PS_MAX(nRadialBins, source->extpars->radProfile->binSB->n);
-    // 	}
-    // }
+    // write the radial profile apertures to header
+    for (int i = 0; i < radMax->n; i++) {
+      sprintf (keyword1, "RMIN_%02d", i);
+      sprintf (keyword2, "RMAX_%02d", i);
+      psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);
+      psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
+    }
 
     // we write out all sources, regardless of quality.  the source flags tell us the state
     for (int i = 0; i < sources->n; i++) {
-        // skip source if it is not a ext sourc
-        // XXX we have two places that extended source parameters are measured:
-        // psphotExtendedSources, which measures the aperture-like parameters and (potentially) the psf-convolved extended source models,
-        // psphotFitEXT, which does the simple extended source model fit (not psf-convolved)
-        // should we require both?
-
         pmSource *source = sources->data[i];
 
@@ -514,39 +583,4 @@
         }
 
-# if (0)
-        // Kron measurements
-        if (doKron) {
-            pmSourceKronValues *kron = source->extpars->kron;
-            if (kron) {
-                psMetadataAdd (row, PS_LIST_TAIL, "KRON_MAG",        PS_DATA_F32, "Kron Magnitude",       kron->mag);
-                psMetadataAdd (row, PS_LIST_TAIL, "KRON_MAG_ERR",    PS_DATA_F32, "Kron Magnitude Error", kron->magErr);
-                psMetadataAdd (row, PS_LIST_TAIL, "KRON_RADIUS",     PS_DATA_F32, "Kron Radius",          kron->rad);
-                psMetadataAdd (row, PS_LIST_TAIL, "KRON_RADIUS_ERR", PS_DATA_F32, "Kron Radius Error",    kron->radErr);
-            } else {
-                psMetadataAdd (row, PS_LIST_TAIL, "KRON_MAG",        PS_DATA_F32, "Kron Magnitude",       NAN);
-                psMetadataAdd (row, PS_LIST_TAIL, "KRON_MAG_ERR",    PS_DATA_F32, "Kron Magnitude Error", NAN);
-                psMetadataAdd (row, PS_LIST_TAIL, "KRON_RADIUS",     PS_DATA_F32, "Kron Radius",          NAN);
-                psMetadataAdd (row, PS_LIST_TAIL, "KRON_RADIUS_ERR", PS_DATA_F32, "Kron Radius Error",    NAN);
-            }
-        }
-
-        // Isophot measurements
-        // XXX insert header data: isophotal level
-        if (doIsophotal) {
-            pmSourceIsophotalValues *isophot = source->extpars->isophot;
-            if (isophot) {
-                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_MAG",        PS_DATA_F32, "Isophot Magnitude",       isophot->mag);
-                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_MAG_ERR",    PS_DATA_F32, "Isophot Magnitude Error", isophot->magErr);
-                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_RADIUS",     PS_DATA_F32, "Isophot Radius",          isophot->rad);
-                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_RADIUS_ERR", PS_DATA_F32, "Isophot Radius Error",    isophot->radErr);
-            } else {
-                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_MAG",        PS_DATA_F32, "Isophot Magnitude",       NAN);
-                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_MAG_ERR",    PS_DATA_F32, "Isophot Magnitude Error", NAN);
-                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_RADIUS",     PS_DATA_F32, "Isophot Radius",          NAN);
-                psMetadataAdd (row, PS_LIST_TAIL, "ISOPHOT_RADIUS_ERR", PS_DATA_F32, "Isophot Radius Error",    NAN);
-            }
-        }
-# endif
-
         // Flux Annuli (if we have extended source measurements, we have these.  only optionally save them)
         if (doAnnuli) {
@@ -616,5 +650,5 @@
 
 // XXX this layout is still the same as PS1_DEV_1
-bool pmSourcesWrite_CMF_PS1_SV1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname)
+bool pmSourcesWrite_CMF_PS1_SV1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
 {
 
@@ -665,4 +699,7 @@
             assert (model);
 
+	    // skip models which were not actually fitted
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
+
             PAR = model->params->data.F32;
             dPAR = model->dparams->data.F32;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V1.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -45,6 +54,5 @@
 // followed by a zero-size matrix, followed by the table data
 
-bool pmSourcesWrite_CMF_PS1_V1 (psFits *fits, pmReadout *readout, psArray *sources,
-                                psMetadata *imageHeader, psMetadata *tableHeader, char *extname)
+bool pmSourcesWrite_CMF_PS1_V1 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -184,5 +192,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeight);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
@@ -310,8 +318,15 @@
         source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
         source->peak->flux = peakFlux;
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
         source->peak->dx   = dPAR[PM_PAR_XPOS];
         source->peak->dy   = dPAR[PM_PAR_YPOS];
-
-        source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF");
+        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
+          source->peak->SN = 1.0 / source->errMag;
+        } else {
+          source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
+        }
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
         source->crNsigma  = psMetadataLookupF32 (&status, row, "CR_NSIGMA");
         source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA");
@@ -516,5 +531,5 @@
 
 // XXX this layout is still the same as PS1_DEV_1
-bool pmSourcesWrite_CMF_PS1_V1_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname)
+bool pmSourcesWrite_CMF_PS1_V1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
 {
 
@@ -565,4 +580,7 @@
             assert (model);
 
+	    // skip models which were not actually fitted
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
+
             PAR = model->params->data.F32;
             dPAR = model->dparams->data.F32;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V2.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -45,5 +54,5 @@
 // followed by a zero-size matrix, followed by the table data
 
-bool pmSourcesWrite_CMF_PS1_V2 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname)
+bool pmSourcesWrite_CMF_PS1_V2 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -182,5 +191,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeight);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
@@ -314,9 +323,15 @@
         source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
         source->peak->flux = peakFlux;
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
         source->peak->dx   = dPAR[PM_PAR_XPOS];
         source->peak->dy   = dPAR[PM_PAR_YPOS];
-        source->peak->SN   = sqrt(source->peak->flux); // XXX a proxy: various functions sort by peak S/N
-
-        source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF");
+        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
+          source->peak->SN = 1.0 / source->errMag;
+        } else {
+          source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
+        }
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
         source->crNsigma  = psMetadataLookupF32 (&status, row, "CR_NSIGMA");
         source->extNsigma = psMetadataLookupF32 (&status, row, "EXT_NSIGMA");
@@ -578,5 +593,5 @@
 
 // XXX this layout is still the same as PS1_DEV_1
-bool pmSourcesWrite_CMF_PS1_V2_XFIT (psFits *fits, pmReadout *readout, psArray *sources, char *extname)
+bool pmSourcesWrite_CMF_PS1_V2_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
 {
 
@@ -627,4 +642,7 @@
             assert (model);
 
+	    // skip models which were not actually fitted
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
+
             PAR = model->params->data.F32;
             dPAR = model->dparams->data.F32;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c	(revision 29060)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMF_PS1_V3.c	(revision 29060)
@@ -0,0 +1,733 @@
+/** @file  pmSourceIO.c
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-18 02:44:19 $
+ *
+ *  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 "pmConfig.h"
+#include "pmDetrendDB.h"
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPALevel.h"
+#include "pmFPAview.h"
+#include "pmFPAfile.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+
+#include "pmSourceIO.h"
+
+// panstarrs-style FITS table output (header + table in 1st extension)
+// this format consists of a header derived from the image header
+// followed by a zero-size matrix, followed by the table data
+
+bool pmSourcesWrite_CMF_PS1_V3 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
+{
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    PS_ASSERT_PTR_NON_NULL(sources, false);
+    PS_ASSERT_PTR_NON_NULL(extname, false);
+
+    psArray *table;
+    psMetadata *row;
+    psF32 *PAR, *dPAR;
+    psEllipseAxes axes;
+    psF32 xPos, yPos;
+    psF32 xErr, yErr;
+    psF32 errMag, chisq, apRadius;
+    psS32 nPix, nDOF;
+
+    pmChip *chip = readout->parent->parent;
+    pmFPA  *fpa  = chip->parent;
+
+    bool status1 = false;
+    bool status2 = false;
+    float magOffset = NAN;
+    float exptime   = psMetadataLookupF32 (&status1, fpa->concepts, "FPA.EXPOSURE");
+    float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
+    if (!isfinite(zeropt)) {
+        zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
+    }
+    if (status1 && status2 && (exptime > 0.0)) {
+        magOffset = zeropt + 2.5*log10(exptime);
+    }
+    float zeroptErr = psMetadataLookupF32 (&status2, imageHeader, "ZPT_ERR");
+
+    // if the sequence is defined, write these in seq order; otherwise
+    // write them in S/N order:
+    if (sources->n > 0) {
+        pmSource *source = (pmSource *) sources->data[0];
+        if (source->seq == -1) {
+	    // let's write these out in S/N order
+	    sources = psArraySort (sources, pmSourceSortBySN);
+        } else {
+	    sources = psArraySort (sources, pmSourceSortBySeq);
+        }
+    }
+
+    table = psArrayAllocEmpty (sources->n);
+
+    // we write out PSF-fits for all sources, regardless of quality.  the source flags tell us the state
+    // by the time we call this function, all values should be assigned.  let's use asserts to be sure in some cases.
+    for (int i = 0; i < sources->n; i++) {
+        pmSource *source = (pmSource *) sources->data[i];
+
+        // If source->seq is -1, source was generated in this analysis.  If source->seq is
+        // not -1, source was read from elsewhere: in the latter case, preserve the source
+        // ID.  source.seq is used instead of source.id since the latter is a const
+        // generated on Alloc, and would thus be wrong for read in sources.
+        if (source->seq == -1) {
+	    source->seq = i;
+        }
+
+        // no difference between PSF and non-PSF model
+        pmModel *model = source->modelPSF;
+
+        if (model != NULL) {
+            PAR = model->params->data.F32;
+            dPAR = model->dparams->data.F32;
+            xPos = PAR[PM_PAR_XPOS];
+            yPos = PAR[PM_PAR_YPOS];
+            if (source->mode & PM_SOURCE_MODE_NONLINEAR_FIT) {
+		xErr = dPAR[PM_PAR_XPOS];
+		yErr = dPAR[PM_PAR_YPOS];
+            } else {
+		// in linear-fit mode, there is no error on the centroid
+		xErr = source->peak->dx;
+		yErr = source->peak->dy;
+            }
+            if (isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX]) && isfinite(PAR[PM_PAR_SXX])) {
+                axes = pmPSF_ModelToAxes (PAR, 20.0);
+            } else {
+                axes.major = NAN;
+                axes.minor = NAN;
+                axes.theta = NAN;
+            }
+            chisq = model->chisq;
+            nDOF = model->nDOF;
+            nPix = model->nPix;
+            apRadius = source->apRadius;
+            errMag = model->dparams->data.F32[PM_PAR_I0] / model->params->data.F32[PM_PAR_I0];
+        } else {
+            xPos = source->peak->xf;
+            yPos = source->peak->yf;
+            xErr = source->peak->dx;
+            yErr = source->peak->dy;
+            axes.major = NAN;
+            axes.minor = NAN;
+            axes.theta = NAN;
+            chisq = NAN;
+            nDOF = 0;
+            nPix = 0;
+            apRadius = NAN;
+            errMag = NAN;
+        }
+
+        float calMag = isfinite(magOffset) ? source->psfMag + magOffset : NAN;
+        float peakMag = (source->peak->flux > 0) ? -2.5*log10(source->peak->flux) : NAN;
+        psS16 nImageOverlap = 1;
+
+        psSphere ptSky = {0.0, 0.0, 0.0, 0.0};
+        float posAngle = 0.0;
+        float pltScale = 0.0;
+        pmSourceLocalAstrometry (&ptSky, &posAngle, &pltScale, chip, xPos, yPos);
+
+        row = psMetadataAlloc ();
+        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
+        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF",            PS_DATA_F32, "PSF x coordinate",                           xPos);
+        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF",            PS_DATA_F32, "PSF y coordinate",                           yPos);
+        psMetadataAdd (row, PS_LIST_TAIL, "X_PSF_SIG",        PS_DATA_F32, "Sigma in PSF x coordinate",                  xErr); // XXX this is only measured for non-linear fits
+        psMetadataAdd (row, PS_LIST_TAIL, "Y_PSF_SIG",        PS_DATA_F32, "Sigma in PSF y coordinate",                  yErr); // XXX this is only measured for non-linear fits
+        psMetadataAdd (row, PS_LIST_TAIL, "POSANGLE",         PS_DATA_F32, "position angle at source (degrees)",         posAngle*PS_DEG_RAD);
+        psMetadataAdd (row, PS_LIST_TAIL, "PLTSCALE",         PS_DATA_F32, "plate scale at source (arcsec/pixel)",       pltScale*PS_DEG_RAD*3600.0);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG",     PS_DATA_F32, "PSF fit instrumental magnitude",             source->psfMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_MAG_SIG", PS_DATA_F32, "Sigma of PSF instrumental magnitude",        errMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX",    PS_DATA_F32, "PSF fit instrumental flux (counts)",         source->psfFlux);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_INST_FLUX_SIG",PS_DATA_F32, "Sigma of PSF instrumental flux",             source->psfFluxErr);
+        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG",           PS_DATA_F32, "magnitude in standard aperture",             source->apMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RAW",       PS_DATA_F32, "magnitude in reported aperture",             source->apMagRaw);
+        psMetadataAdd (row, PS_LIST_TAIL, "AP_MAG_RADIUS",    PS_DATA_F32, "radius used for aperture mags",              apRadius);
+        psMetadataAdd (row, PS_LIST_TAIL, "PEAK_FLUX_AS_MAG", PS_DATA_F32, "Peak flux expressed as magnitude",           peakMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG",      PS_DATA_F32, "PSF Magnitude using supplied calibration",   calMag);
+        psMetadataAdd (row, PS_LIST_TAIL, "CAL_PSF_MAG_SIG",  PS_DATA_F32, "measured scatter of zero point calibration", zeroptErr);
+        psMetadataAdd (row, PS_LIST_TAIL, "RA_PSF",           PS_DATA_F64, "PSF RA coordinate (degrees)",                ptSky.r*PS_DEG_RAD);
+        psMetadataAdd (row, PS_LIST_TAIL, "DEC_PSF",          PS_DATA_F64, "PSF DEC coordinate (degrees)",               ptSky.d*PS_DEG_RAD);
+        psMetadataAdd (row, PS_LIST_TAIL, "SKY",              PS_DATA_F32, "Sky level",                                  source->sky);
+        psMetadataAdd (row, PS_LIST_TAIL, "SKY_SIGMA",        PS_DATA_F32, "Sigma of sky level",                         source->skyErr);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_CHISQ",        PS_DATA_F32, "Chisq of PSF-fit",                           chisq);
+        psMetadataAdd (row, PS_LIST_TAIL, "CR_NSIGMA",        PS_DATA_F32, "Nsigma deviations from PSF to CF",           source->crNsigma);
+        psMetadataAdd (row, PS_LIST_TAIL, "EXT_NSIGMA",       PS_DATA_F32, "Nsigma deviations from PSF to EXT",          source->extNsigma);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MAJOR",        PS_DATA_F32, "PSF width (major axis)",                     axes.major);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_MINOR",        PS_DATA_F32, "PSF width (minor axis)",                     axes.minor);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor (bad)",          source->pixWeightNotBad);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF_PERFECT",   PS_DATA_F32, "PSF coverage/quality factor (poor)",         source->pixWeightNotPoor);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NDOF",         PS_DATA_S32, "degrees of freedom",                         nDOF);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_NPIX",         PS_DATA_S32, "number of pixels in fit",                    nPix);
+
+        // distinguish moments measure from window vs S/N > XX ??
+        float Mxx = source->moments ? source->moments->Mxx : NAN;
+        float Mxy = source->moments ? source->moments->Mxy : NAN;
+        float Myy = source->moments ? source->moments->Myy : NAN;
+
+        float Mrf  = source->moments ? source->moments->Mrf : NAN;
+        float Mrh  = source->moments ? source->moments->Mrh : NAN;
+        float Krf  = source->moments ? source->moments->KronFlux : NAN;
+        float dKrf = source->moments ? source->moments->KronFluxErr : NAN;
+
+        float Kinner = source->moments ? source->moments->KronFinner : NAN;
+        float Kouter = source->moments ? source->moments->KronFouter : NAN;
+
+        float M_c3 = source->moments ? 1.0*source->moments->Mxxx - 3.0*source->moments->Mxyy : NAN;
+        float M_s3 = source->moments ? 3.0*source->moments->Mxxy - 1.0*source->moments->Myyy : NAN;
+        float M_c4 = source->moments ? 1.0*source->moments->Mxxxx - 6.0*source->moments->Mxxyy + 1.0*source->moments->Myyyy : NAN;
+        float M_s4 = source->moments ? 4.0*source->moments->Mxxxy - 4.0*source->moments->Mxyyy : NAN;
+
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XX",       PS_DATA_F32, "second moments (X^2)",                      Mxx);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_XY",       PS_DATA_F32, "second moments (X*Y)",                      Mxy);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_YY",       PS_DATA_F32, "second moments (Y*Y)",                      Myy);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3C",      PS_DATA_F32, "third momemt cos theta",                    M_c3);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M3S",      PS_DATA_F32, "third momemt sin theta",                    M_s3);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4C",      PS_DATA_F32, "fourth momemt cos theta",                   M_c4);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_M4S",      PS_DATA_F32, "fourth momemt sin theta",                   M_s4);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_R1",       PS_DATA_F32, "first radial moment",                       Mrf);
+        psMetadataAdd (row, PS_LIST_TAIL, "MOMENTS_RH",       PS_DATA_F32, "half radial moment",                        Mrh);
+        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX",        PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Krf);
+        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_ERR",    PS_DATA_F32, "Kron Flux Error",                          dKrf);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_INNER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Kinner);
+        psMetadataAdd (row, PS_LIST_TAIL, "KRON_FLUX_OUTER",  PS_DATA_F32, "Kron Flux (in 2.5 R1)",                     Kouter);
+
+        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS",            PS_DATA_U32, "psphot analysis flags",                     source->mode);
+        psMetadataAdd (row, PS_LIST_TAIL, "FLAGS2",           PS_DATA_U32, "psphot analysis flags",                     source->mode2);
+
+        // XXX not sure how to get this : need to load Nimages with weight?
+        psMetadataAdd (row, PS_LIST_TAIL, "N_FRAMES",         PS_DATA_U16, "Number of frames overlapping source center", nImageOverlap);
+        psMetadataAdd (row, PS_LIST_TAIL, "PADDING",          PS_DATA_S16, "padding", 0);
+
+        psArrayAdd (table, 100, row);
+        psFree (row);
+
+        // EXT_NSIGMA will be NAN if: 1) contour ellipse is imaginary; 2) source is not
+        // subtracted
+
+        // CR_NSIGMA will be NAN if: 1) source is not subtracted; 2) source is on the image
+        // edge; 3) any pixels in the 3x3 peak region are masked;
+    }
+
+    // XXX why do we make a copy here to be supplemented with the masks?  why not do this in the calling function?
+    psMetadata *header = psMetadataCopy(NULL, tableHeader);
+    pmSourceMasksHeader(header);
+
+    if (table->n == 0) {
+        if (!psFitsWriteBlank(fits, header, extname)) {
+            psError(psErrorCodeLast(), false, "Unable to write blank sources file.");
+            psFree(table);
+            psFree(header);
+            return false;
+        }
+        psFree(table);
+        psFree(header);
+        return true;
+    }
+
+    psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname);
+    if (!psFitsWriteTable(fits, header, table, extname)) {
+        psError(psErrorCodeLast(), false, "writing ext data %s\n", extname);
+        psFree(table);
+        psFree(header);
+        return false;
+    }
+    psFree(table);
+    psFree(header);
+
+    return true;
+}
+
+// read in a readout from the fits file
+psArray *pmSourcesRead_CMF_PS1_V3 (psFits *fits, psMetadata *header)
+{
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    PS_ASSERT_PTR_NON_NULL(header, false);
+
+    bool status;
+    psF32 *PAR, *dPAR;
+    psEllipseAxes axes;
+
+    // define PSF model type
+    // XXX need to carry the extra model parameters
+    int modelType = pmModelClassGetType ("PS_MODEL_GAUSS");
+
+    char *PSF_NAME = psMetadataLookupStr (&status, header, "PSF_NAME");
+    if (PSF_NAME != NULL) {
+        modelType = pmModelClassGetType (PSF_NAME);
+    }
+    assert (modelType > -1);
+
+    // We get the size of the table, and allocate the array of sources first because the table
+    // is large and ephemeral --- when the table gets blown away, whatever is allocated after
+    // the table is read blocks the free.  In fact, it's better to read the table row by row.
+    long numSources = psFitsTableSize(fits); // Number of sources in table
+    psArray *sources = psArrayAlloc(numSources); // Array of sources, to return
+
+    // convert the table to the pmSource entriesa
+    for (int i = 0; i < numSources; i++) {
+        psMetadata *row = psFitsReadTableRow(fits, i); // Table row
+        if (!row) {
+            psError(psErrorCodeLast(), false, "Unable to read row %d of sources", i);
+            psFree(sources);
+            return NULL;
+        }
+
+        pmSource *source = pmSourceAlloc ();
+        pmModel *model = pmModelAlloc (modelType);
+        source->modelPSF  = model;
+        source->type = PM_SOURCE_TYPE_STAR; // XXX this should be added to the flags
+
+        // NOTE: A SEGV here because "model" is NULL is probably caused by not initialising the models.
+        PAR = model->params->data.F32;
+        dPAR = model->dparams->data.F32;
+
+        source->seq       = psMetadataLookupU32 (&status, row, "IPP_IDET");
+        PAR[PM_PAR_XPOS]  = psMetadataLookupF32 (&status, row, "X_PSF");
+        PAR[PM_PAR_YPOS]  = psMetadataLookupF32 (&status, row, "Y_PSF");
+        dPAR[PM_PAR_XPOS] = psMetadataLookupF32 (&status, row, "X_PSF_SIG");
+        dPAR[PM_PAR_YPOS] = psMetadataLookupF32 (&status, row, "Y_PSF_SIG");
+        axes.major        = psMetadataLookupF32 (&status, row, "PSF_MAJOR");
+        axes.minor        = psMetadataLookupF32 (&status, row, "PSF_MINOR");
+        axes.theta        = psMetadataLookupF32 (&status, row, "PSF_THETA");
+
+        PAR[PM_PAR_SKY]   = psMetadataLookupF32 (&status, row, "SKY");
+        dPAR[PM_PAR_SKY]  = psMetadataLookupF32 (&status, row, "SKY_SIGMA");
+        source->sky       = PAR[PM_PAR_SKY];
+        source->skyErr    = dPAR[PM_PAR_SKY];
+
+        // XXX use these to determine PAR[PM_PAR_I0]?
+        source->psfMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG");
+        source->errMag    = psMetadataLookupF32 (&status, row, "PSF_INST_MAG_SIG");
+        source->apMag     = psMetadataLookupF32 (&status, row, "AP_MAG");
+
+        // XXX this scaling is incorrect: does not include the 2 \pi AREA factor
+        PAR[PM_PAR_I0]    = (isfinite(source->psfMag)) ? pow(10.0, -0.4*source->psfMag) : NAN;
+        dPAR[PM_PAR_I0]   = (isfinite(source->psfMag)) ? PAR[PM_PAR_I0] * source->errMag : NAN;
+
+        pmPSF_AxesToModel (PAR, axes);
+
+        float peakMag     = psMetadataLookupF32 (&status, row, "PEAK_FLUX_AS_MAG");
+        float peakFlux    = (isfinite(peakMag)) ? pow(10.0, -0.4*peakMag) : NAN;
+
+        // recreate the peak to match (xPos, yPos) +/- (xErr, yErr)
+        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
+        source->peak->flux = peakFlux;
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
+        source->peak->dx   = dPAR[PM_PAR_XPOS];
+        source->peak->dy   = dPAR[PM_PAR_YPOS];
+        if (isfinite (source->errMag) && (source->errMag > 0.0)) {
+          source->peak->SN = 1.0 / source->errMag;
+        } else {
+          source->peak->SN = sqrt(source->peak->flux); // an alternate proxy: various functions sort by peak S/N
+        }
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
+        source->pixWeightNotPoor = psMetadataLookupF32 (&status, row, "PSF_QF_PERFECT");
+        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.
+        model->chisq      = psMetadataLookupF32 (&status, row, "PSF_CHISQ");
+        model->nDOF       = psMetadataLookupS32 (&status, row, "PSF_NDOF");
+        model->nPix       = psMetadataLookupS32 (&status, row, "PSF_NPIX");
+
+        source->moments = pmMomentsAlloc ();
+        source->moments->Mxx = psMetadataLookupF32 (&status, row, "MOMENTS_XX");
+        source->moments->Mxy = psMetadataLookupF32 (&status, row, "MOMENTS_XY");
+        source->moments->Myy = psMetadataLookupF32 (&status, row, "MOMENTS_YY");
+
+        source->moments->Mrf         = psMetadataLookupF32 (&status, row, "MOMENTS_R1");
+        source->moments->Mrh         = psMetadataLookupF32 (&status, row, "MOMENTS_RH");
+        source->moments->KronFlux    = psMetadataLookupF32 (&status, row, "KRON_FLUX");
+        source->moments->KronFluxErr = psMetadataLookupF32 (&status, row, "KRON_FLUX_ERR");
+
+        source->moments->KronFinner  = psMetadataLookupF32 (&status, row, "KRON_FLUX_INNER");
+        source->moments->KronFouter  = psMetadataLookupF32 (&status, row, "KRON_FLUX_OUTER");
+
+	// XXX we do not save all of the 3rd and 4th moment parameters. when we load in data,
+	// we are storing enough information so the output will be consistent with the input
+        source->moments->Mxxx = +1.0 * psMetadataLookupF32 (&status, row, "MOMENTS_M3C");
+        source->moments->Mxxy = 0.0;
+        source->moments->Mxyy = 0.0;
+        source->moments->Myyy = -1.0 * psMetadataLookupF32 (&status, row, "MOMENTS_M3S");
+
+        source->moments->Mxxxx = +1.00 * psMetadataLookupF32 (&status, row, "MOMENTS_M4C");
+        source->moments->Mxxxy = 0.0;
+        source->moments->Mxxyy = 0.0;
+        source->moments->Mxyyy = -0.25 * psMetadataLookupF32 (&status, row, "MOMENTS_M4S");
+        source->moments->Myyyy = 0.0;
+
+        source->mode = psMetadataLookupU32 (&status, row, "FLAGS");
+        source->mode2 = psMetadataLookupU32 (&status, row, "FLAGS2");
+        assert (status);
+
+        sources->data[i] = source;
+        psFree(row);
+    }
+
+    return sources;
+}
+
+bool pmSourcesWrite_CMF_PS1_V3_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    bool status;
+    psArray *table;
+    psMetadata *row;
+    psF32 *PAR, *dPAR;
+    psF32 xPos, yPos;
+    psF32 xErr, yErr;
+    int nRow = -1;
+    char keyword1[80], keyword2[80];
+
+    // create a header to hold the output data
+    psMetadata *outhead = psMetadataAlloc ();
+
+    // write the links to the image header
+    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTNAME", PS_META_REPLACE, "xsrc table extension", extname);
+
+    pmChip *chip = readout->parent->parent;
+    pmFPA  *fpa  = chip->parent;
+
+    // zero point corrections
+    bool status1 = false;
+    bool status2 = false;
+    float magOffset = 0.0;
+    float exptime   = psMetadataLookupF32(&status1, fpa->concepts, "FPA.EXPOSURE");
+    float zeropt    = psMetadataLookupF32(&status2, fpa->concepts, "FPA.ZP");
+    if (!isfinite(zeropt)) {
+        zeropt    = psMetadataLookupF32 (&status2, imageHeader, "ZPT_OBS");
+    }
+    if (status1 && status2 && (exptime > 0.0)) {
+        magOffset = zeropt + 2.5*log10(exptime);
+    }
+
+    // let's write these out in S/N order
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    table = psArrayAllocEmpty (sources->n);
+
+    // which extended source analyses should we perform?
+    bool doAnnuli       = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
+    bool doPetrosian    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
+
+    psVector *radMin = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.LOWER");
+    psVector *radMax = psMetadataLookupPtr (&status, recipe, "RADIAL.ANNULAR.BINS.UPPER");
+    psAssert (radMin->n == radMax->n, "inconsistent annular bins");
+
+    // write the radial profile apertures to header
+    for (int i = 0; i < radMax->n; i++) {
+      sprintf (keyword1, "RMIN_%02d", i);
+      sprintf (keyword2, "RMAX_%02d", i);
+      psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword1, PS_META_REPLACE, "min radius for SB profile", radMin->data.F32[i]);
+      psMetadataAddF32 (outhead, PS_LIST_TAIL, keyword2, PS_META_REPLACE, "min radius for SB profile", radMax->data.F32[i]);
+    }
+
+    // we write out all sources, regardless of quality.  the source flags tell us the state
+    for (int i = 0; i < sources->n; i++) {
+        pmSource *source = sources->data[i];
+
+        // skip sources without measurements
+        if (source->extpars == NULL) continue;
+
+        // we require a PSF model fit (ignore the real crud)
+        pmModel *model = source->modelPSF;
+        if (model == NULL) continue;
+
+        // XXX I need to split the extended models from the extended aperture measurements
+        PAR = model->params->data.F32;
+        dPAR = model->dparams->data.F32;
+        xPos = PAR[PM_PAR_XPOS];
+        yPos = PAR[PM_PAR_YPOS];
+        xErr = dPAR[PM_PAR_XPOS];
+        yErr = dPAR[PM_PAR_YPOS];
+
+        row = psMetadataAlloc ();
+
+        // XXX we are not writing out the mode (flags) or the type (psf, ext, etc)
+        psMetadataAdd (row, PS_LIST_TAIL, "IPP_IDET",         PS_DATA_U32, "IPP detection identifier index",             source->seq);
+        psMetadataAdd (row, PS_LIST_TAIL, "X_EXT",            PS_DATA_F32, "EXT model x coordinate",                     xPos);
+        psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT",            PS_DATA_F32, "EXT model y coordinate",                     yPos);
+        psMetadataAdd (row, PS_LIST_TAIL, "X_EXT_SIG",        PS_DATA_F32, "Sigma in EXT x coordinate",                  xErr);
+        psMetadataAdd (row, PS_LIST_TAIL, "Y_EXT_SIG",        PS_DATA_F32, "Sigma in EXT y coordinate",                  yErr);
+
+	float AxialRatio = NAN;
+	float AxialTheta = NAN;
+	pmSourceExtendedPars *extpars = source->extpars;
+	if (extpars) {
+	    AxialRatio = extpars->axes.minor / extpars->axes.major;
+	    AxialTheta = extpars->axes.theta;
+	}
+        psMetadataAdd (row, PS_LIST_TAIL, "F25_ARATIO",       PS_DATA_F32, "Axial Ratio of radial profile",              AxialRatio);
+        psMetadataAdd (row, PS_LIST_TAIL, "F25_THETA",        PS_DATA_F32, "Angle of radial profile ellipse",                  AxialTheta);
+
+        // Petrosian measurements
+        // XXX insert header data: petrosian ref radius, flux ratio
+	// XXX check flags to see if Pet was measured
+        if (doPetrosian) {
+	    pmSourceExtendedPars *extpars = source->extpars;
+            if (extpars) {
+		// XXX note that this mag is either calibrated or instrumental depending on existence of zero point 
+		float mag = (extpars->petrosianFlux > 0.0) ? -2.5*log10(extpars->petrosianFlux) + magOffset : NAN; // XXX zero point
+		float magErr = (extpars->petrosianFlux > 0.0) ? extpars->petrosianFlux / extpars->petrosianFluxErr : NAN; // XXX zero point
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG",        PS_DATA_F32, "Petrosian Magnitude", mag);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR",    PS_DATA_F32, "Petrosian Magnitude Error", magErr);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS",     PS_DATA_F32, "Petrosian Radius (pix)", extpars->petrosianRadius);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error (pix)", extpars->petrosianRadiusErr);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50",     PS_DATA_F32, "Petrosian R50 (pix)", extpars->petrosianR50);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50_ERR", PS_DATA_F32, "Petrosian R50 Error (pix)", extpars->petrosianR50Err);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90",     PS_DATA_F32, "Petrosian R90 (pix)", extpars->petrosianR90);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90_ERR", PS_DATA_F32, "Petrosian R90 Error (pix)", extpars->petrosianR90Err);
+            } else {
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG",        PS_DATA_F32, "Petrosian Magnitude",       NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_MAG_ERR",    PS_DATA_F32, "Petrosian Magnitude Error", NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS",     PS_DATA_F32, "Petrosian Radius",          NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_ERR", PS_DATA_F32, "Petrosian Radius Error",    NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50",     PS_DATA_F32, "Petrosian R50 (pix)", NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_50_ERR", PS_DATA_F32, "Petrosian R50 Error (pix)",NAN); 
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90",     PS_DATA_F32, "Petrosian R90 (pix)", NAN);
+                psMetadataAdd (row, PS_LIST_TAIL, "PETRO_RADIUS_90_ERR", PS_DATA_F32, "Petrosian R90 Error (pix)",NAN); 
+            }
+        }
+
+        // Flux Annuli (if we have extended source measurements, we have these.  only optionally save them)
+        if (doAnnuli) {
+	    psVector *radSB   = psVectorAlloc(radMin->n, PS_TYPE_F32);
+	    psVector *radFlux = psVectorAlloc(radMin->n, PS_TYPE_F32);
+	    psVector *radFill = psVectorAlloc(radMin->n, PS_TYPE_F32);
+	    psVectorInit (radSB, NAN);
+	    psVectorInit (radFlux, NAN);
+	    psVectorInit (radFill, NAN);
+	    if (!source->extpars) goto empty_annuli;
+	    if (!source->extpars->radProfile) goto empty_annuli;
+	    if (!source->extpars->radProfile->binSB) goto empty_annuli;
+	    psAssert (source->extpars->radProfile->binSum, "programming error");
+	    psAssert (source->extpars->radProfile->binFill, "programming error");
+	    psAssert (source->extpars->radProfile->binSB->n <= radFlux->n, "inconsistent vector lengths");
+	    psAssert (source->extpars->radProfile->binSum->n <= radFlux->n, "inconsistent vector lengths");
+	    psAssert (source->extpars->radProfile->binFill->n <= radFlux->n, "inconsistent vector lengths");
+
+	    // copy the data from fluxVal (which is not guaranteed to be the full length) to radFlux
+	    for (int j = 0; j < source->extpars->radProfile->binSB->n; j++) {
+		radSB->data.F32[j]   = source->extpars->radProfile->binSB->data.F32[j];
+		radFlux->data.F32[j] = source->extpars->radProfile->binSum->data.F32[j];
+		radFill->data.F32[j] = source->extpars->radProfile->binFill->data.F32[j];
+	    }
+
+	empty_annuli:
+	    psMetadataAdd (row, PS_LIST_TAIL, "PROF_SB", PS_DATA_VECTOR, "mean surface brightness annuli", radSB);
+	    psMetadataAdd (row, PS_LIST_TAIL, "PROF_FLUX", PS_DATA_VECTOR, "flux within annuli", radFlux);
+	    psMetadataAdd (row, PS_LIST_TAIL, "PROF_FILL", PS_DATA_VECTOR, "fill factor of annuli", radFill);
+	    psFree (radSB);
+	    psFree (radFlux);
+	    psFree (radFill);
+	}
+	if (nRow < 0) {
+	    nRow = row->list->n;
+	} else {
+	    psAssert (nRow == row->list->n, "inconsistent row lengths");
+	}
+	psArrayAdd (table, 100, row);
+	psFree (row);
+    }
+    
+    if (table->n == 0) {
+	if (!psFitsWriteBlank (fits, outhead, extname)) {
+	    psError(psErrorCodeLast(), false, "Unable to write empty sources file.");
+	    psFree(outhead);
+	    psFree(table);
+	    return false;
+	}
+	psFree (outhead);
+	psFree (table);
+	return true;
+    }
+    
+    psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname);
+    if (!psFitsWriteTable (fits, outhead, table, extname)) {
+	psError(psErrorCodeLast(), false, "writing ext data %s\n", extname);
+	psFree (outhead);
+    psFree(table);
+    return false;
+    }
+    psFree (outhead);
+    psFree (table);
+    
+    return true;
+}
+
+// XXX this layout is still the same as PS1_DEV_1
+bool pmSourcesWrite_CMF_PS1_V3_XFIT (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
+{
+
+    psArray *table;
+    psMetadata *row;
+    psF32 *PAR, *dPAR;
+    psEllipseAxes axes;
+    psF32 xPos, yPos;
+    psF32 xErr, yErr;
+    char name[64];
+
+    // create a header to hold the output data
+    psMetadata *outhead = psMetadataAlloc ();
+
+    // write the links to the image header
+    psMetadataAddStr (outhead, PS_LIST_TAIL, "EXTNAME", PS_META_REPLACE, "xsrc table extension", extname);
+
+    // let's write these out in S/N order
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    // we are writing one row per model; we need to write out same number of columns for each row: find the max Nparams
+    int nParamMax = 0;
+    for (int i = 0; i < sources->n; i++) {
+        pmSource *source = sources->data[i];
+        if (source->modelFits == NULL) continue;
+        for (int j = 0; j < source->modelFits->n; j++) {
+            pmModel *model = source->modelFits->data[j];
+            assert (model);
+            nParamMax = PS_MAX (nParamMax, model->params->n);
+        }
+    }
+
+    table = psArrayAllocEmpty (sources->n);
+
+    // we write out all sources, regardless of quality.  the source flags tell us the state
+    for (int i = 0; i < sources->n; i++) {
+
+        pmSource *source = sources->data[i];
+
+        // XXX if no model fits are saved, write out modelEXT?
+        if (source->modelFits == NULL) continue;
+
+        // We have multiple sources : need to flag the one used to subtract the light (the 'best' model)
+        for (int j = 0; j < source->modelFits->n; j++) {
+
+            // choose the convolved EXT model, if available, otherwise the simple one
+            pmModel *model = source->modelFits->data[j];
+            assert (model);
+
+	    // skip models which were not actually fitted
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
+
+            PAR = model->params->data.F32;
+            dPAR = model->dparams->data.F32;
+            xPos = PAR[PM_PAR_XPOS];
+            yPos = PAR[PM_PAR_YPOS];
+            xErr = dPAR[PM_PAR_XPOS];
+            yErr = dPAR[PM_PAR_YPOS];
+
+            axes = pmPSF_ModelToAxes (PAR, 20.0);
+
+            row = psMetadataAlloc ();
+
+            // XXX we are not writing out the mode (flags) or the type (psf, ext, etc)
+            psMetadataAddU32 (row, PS_LIST_TAIL, "IPP_IDET",         0, "IPP detection identifier index",             source->seq);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "X_EXT",            0, "EXT model x coordinate",                     xPos);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "Y_EXT",            0, "EXT model y coordinate",                     yPos);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "X_EXT_SIG",        0, "Sigma in EXT x coordinate",                  xErr);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "Y_EXT_SIG",        0, "Sigma in EXT y coordinate",                  yErr);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_MAG",     0, "EXT fit instrumental magnitude",             model->mag);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_INST_MAG_SIG", 0, "Sigma of PSF instrumental magnitude",        model->magErr);
+
+            psMetadataAddF32 (row, PS_LIST_TAIL, "NPARAMS",          0, "number of model parameters",                 model->params->n);
+            psMetadataAddStr (row, PS_LIST_TAIL, "MODEL_TYPE",       0, "name of model",                              pmModelClassGetName (model->type));
+
+            // XXX these should be major and minor, not 'x' and 'y'
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MAJ",    0, "EXT width in x coordinate",                  axes.major);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_WIDTH_MIN",    0, "EXT width in y coordinate",                  axes.minor);
+            psMetadataAddF32 (row, PS_LIST_TAIL, "EXT_THETA",        0, "EXT orientation angle",                      axes.theta);
+
+            // write out the other generic parameters
+            for (int k = 0; k < nParamMax; k++) {
+                if (k == PM_PAR_I0) continue;
+                if (k == PM_PAR_SKY) continue;
+                if (k == PM_PAR_XPOS) continue;
+                if (k == PM_PAR_YPOS) continue;
+                if (k == PM_PAR_SXX) continue;
+                if (k == PM_PAR_SXY) continue;
+                if (k == PM_PAR_SYY) continue;
+
+                snprintf (name, 64, "EXT_PAR_%02d", k);
+
+                if (k < model->params->n) {
+                    psMetadataAdd (row, PS_LIST_TAIL, name, PS_DATA_F32, "", model->params->data.F32[k]);
+                } else {
+                    psMetadataAddF32 (row, PS_LIST_TAIL, name, PS_DATA_F32, "", NAN);
+                }
+            }
+
+            // XXX other parameters which may be set.
+            // XXX flag / value to define the model
+            // XXX write out the model type, fit status flags
+
+            psArrayAdd (table, 100, row);
+            psFree (row);
+        }
+    }
+
+    if (table->n == 0) {
+        if (!psFitsWriteBlank (fits, outhead, extname)) {
+            psError(psErrorCodeLast(), false, "Unable to write empty sources file.");
+            psFree(outhead);
+            psFree(table);
+            return false;
+        }
+        psFree (outhead);
+        psFree (table);
+        return true;
+    }
+
+    psTrace ("pmFPAfile", 5, "writing ext data %s\n", extname);
+    if (!psFitsWriteTable (fits, outhead, table, extname)) {
+        psError(psErrorCodeLast(), false, "writing ext data %s\n", extname);
+        psFree (outhead);
+        psFree(table);
+        return false;
+    }
+    psFree (outhead);
+    psFree (table);
+    return true;
+}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMP.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMP.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_CMP.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_MatchedRefs.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_MatchedRefs.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_MatchedRefs.c	(revision 29060)
@@ -28,16 +28,26 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
+
 #include "pmAstrometryObjects.h"
 #include "pmAstrometryWCS.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_OBJ.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_OBJ.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_OBJ.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_CAL_0.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_CAL_0.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_CAL_0.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -49,6 +58,5 @@
 // XXX how do I generate the source tables which I need to send to PSPS?
 
-bool pmSourcesWrite_PS1_CAL_0 (psFits *fits, pmReadout *readout, psArray *sources, 
-			       psMetadata *imageHeader, psMetadata *tableHeader, char *extname)
+bool pmSourcesWrite_PS1_CAL_0 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -180,5 +188,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_WIDTH_Y",      PS_DATA_F32, "PSF width in y coordinate",                  axes.minor);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeight);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
 
         // XXX not sure how to get this : need to load Nimages with weight?
@@ -289,6 +297,8 @@
         source->peak->dx   = dPAR[PM_PAR_XPOS];
         source->peak->dy   = dPAR[PM_PAR_YPOS];
-
-        source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF");
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
 
 	// note that some older versions used PSF_PROBABILITY: this was not well defined.
@@ -597,4 +607,7 @@
 	    assert (model);
 
+	    // skip models which were not actually fitted
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
+
 	    PAR = model->params->data.F32;
 	    dPAR = model->dparams->data.F32;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_DEV_0.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_DEV_0.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_DEV_0.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -49,6 +58,5 @@
 // XXX how do I generate the source tables which I need to send to PSPS?
 // XXX: input parameter imageHeader is never used.
-bool pmSourcesWrite_PS1_DEV_0 (psFits *fits, psArray *sources, psMetadata *imageHeader,
-                               psMetadata *tableHeader, char *extname)
+bool pmSourcesWrite_PS1_DEV_0 (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -117,5 +125,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_WIDTH_Y",      PS_DATA_F32, "PSF width in y coordinate",                  axes.minor);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeight);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
         // XXX not sure how to get this : need to load Nimages with weight
         psMetadataAdd (row, PS_LIST_TAIL, "N_FRAMES",         PS_DATA_U16, "Number of frames overlapping source center", nImageOverlap);
@@ -215,6 +223,8 @@
         source->peak->dx   = dPAR[PM_PAR_XPOS];
         source->peak->dy   = dPAR[PM_PAR_YPOS];
-
-        source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF");
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
 
         // XXX other values saved but not loaded?
@@ -228,2 +238,12 @@
     return (sources);
 }
+
+bool pmSourcesWrite_PS1_DEV_0_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
+
+bool pmSourcesWrite_PS1_DEV_0_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
+{
+    return true;
+}
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_DEV_1.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_DEV_1.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_PS1_DEV_1.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -47,8 +56,6 @@
 // this output format is valid for psphot analysis of an image, and does not include calibrated
 // values derived in the DVO database.
-// XXX how do I generate the source tables which I need to send to PSPS?
-
-bool pmSourcesWrite_PS1_DEV_1 (psFits *fits, psArray *sources, 
-			       psMetadata *imageHeader, psMetadata *tableHeader, char *extname)
+
+bool pmSourcesWrite_PS1_DEV_1(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -142,5 +149,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_WIDTH_Y",      PS_DATA_F32, "PSF width in y coordinate",                  axes.minor);
         psMetadataAdd (row, PS_LIST_TAIL, "PSF_THETA",        PS_DATA_F32, "PSF orientation angle",                      axes.theta);
-        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeight);
+        psMetadataAdd (row, PS_LIST_TAIL, "PSF_QF",           PS_DATA_F32, "PSF coverage/quality factor",                source->pixWeightNotBad);
 
         // XXX not sure how to get this : need to load Nimages with weight?
@@ -259,6 +266,8 @@
         source->peak->dx   = dPAR[PM_PAR_XPOS];
         source->peak->dy   = dPAR[PM_PAR_YPOS];
-
-        source->pixWeight = psMetadataLookupF32 (&status, row, "PSF_QF");
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
+
+        source->pixWeightNotBad = psMetadataLookupF32 (&status, row, "PSF_QF");
 
 	// note that some older versions used PSF_PROBABILITY: this was not well defined.
@@ -281,5 +290,5 @@
 }
 
-bool pmSourcesWrite_PS1_DEV_1_XSRC (psFits *fits, psArray *sources, char *extname, psMetadata *recipe)
+bool pmSourcesWrite_PS1_DEV_1_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
 {
 
@@ -453,5 +462,5 @@
 }
 
-bool pmSourcesWrite_PS1_DEV_1_XFIT (psFits *fits, psArray *sources, char *extname)
+bool pmSourcesWrite_PS1_DEV_1_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
 {
 
@@ -502,4 +511,7 @@
 	    assert (model);
 
+	    // skip models which were not actually fitted
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
+
 	    PAR = model->params->data.F32;
 	    dPAR = model->dparams->data.F32;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_RAW.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_RAW.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_RAW.c	(revision 29060)
@@ -28,16 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
-#include "pmSourcePhotometry.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -120,5 +128,5 @@
                  source[0].peak->SN,
                  source[0].apRadius,
-                 source[0].pixWeight,
+                 source[0].pixWeightNotBad,
                  model[0].nDOF,
                  model[0].nIter);
@@ -182,5 +190,5 @@
                  source[0].peak->SN,
                  source[0].apRadius,
-                 source[0].pixWeight,
+                 source[0].pixWeightNotBad,
                  model[0].nDOF,
                  model[0].nIter);
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_SMPDATA.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_SMPDATA.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_SMPDATA.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
@@ -45,6 +54,5 @@
 // followed by a zero-size matrix, followed by the table data
 // XXX: input parameter imageHeader is never used
-bool pmSourcesWrite_SMPDATA (psFits *fits, psArray *sources, psMetadata *imageHeader,
-                             psMetadata *tableHeader, char *extname)
+bool pmSourcesWrite_SMPDATA (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, psMetadata *tableHeader, char *extname, psMetadata *recipe)
 {
     PS_ASSERT_PTR_NON_NULL(fits, false);
@@ -106,5 +114,5 @@
         psMetadataAdd (row, PS_LIST_TAIL, "THETA",   PS_DATA_F32, "", axes.theta);
         psMetadataAdd (row, PS_LIST_TAIL, "DOPHOT",  PS_DATA_U8,  "", type);
-        psMetadataAdd (row, PS_LIST_TAIL, "WEIGHT",  PS_DATA_U8,  "", PS_MIN (255, PS_MAX(0, 255*source->pixWeight)));
+        psMetadataAdd (row, PS_LIST_TAIL, "WEIGHT",  PS_DATA_U8,  "", PS_MIN (255, PS_MAX(0, 255*source->pixWeightNotBad)));
         psMetadataAdd (row, PS_LIST_TAIL, "DUMMY",   PS_DATA_U16, "", 0);
 
@@ -189,5 +197,5 @@
         source->apMag  = psMetadataLookupF32 (&status, row, "MAG_AP")  - ZERO_POINT;
 
-        source->pixWeight = psMetadataLookupU8 (&status, row, "WEIGHT")/255.0;
+        source->pixWeightNotBad = psMetadataLookupU8 (&status, row, "WEIGHT")/255.0;
         int dophot = psMetadataLookupU8 (&status, row, "DOPHOT");
 	pmSourceSetDophotType (source, dophot);
@@ -204,2 +212,12 @@
     return (sources);
 }
+
+bool pmSourcesWrite_SMPDATA_XSRC (psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname, psMetadata *recipe)
+{
+    return true;
+}
+
+bool pmSourcesWrite_SMPDATA_XFIT(psFits *fits, pmReadout *readout, psArray *sources, psMetadata *imageHeader, char *extname)
+{
+    return true;
+} 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_SX.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_SX.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceIO_SX.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAfile.h"
 
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourceIO.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMasks.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMasks.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMasks.h	(revision 29060)
@@ -39,4 +39,11 @@
 } pmSourceMode;
 
+// Bit flags to distinguish analysis results
+// When adding to or subtracting from this list, please also modify pmSourceMaskHeader
+typedef enum {
+    PM_SOURCE_MODE2_DEFAULT          = 0x00000000, ///< Initial value: resets all bits
+    PM_SOURCE_MODE2_DIFF_WITH_SINGLE = 0x00000001, ///< diff source matched to a single positive detection
+    PM_SOURCE_MODE2_DIFF_WITH_DOUBLE = 0x00000002, ///< diff source matched to positive detections in both images
+} pmSourceMode2;
 
 /// Populate header with mask values
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMatch.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMatch.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMatch.c	(revision 29060)
@@ -6,6 +6,28 @@
 #include <string.h>
 #include <pslib.h>
-
+#include "pmHDU.h"
+#include "pmFPA.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+#include "pmDetections.h"
+
 #include "pmErrorCodes.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMatch.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMatch.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMatch.h	(revision 29060)
@@ -1,6 +1,4 @@
 #ifndef PM_SOURCE_MATCH_H
 #define PM_SOURCE_MATCH_H
-
-#include <pslib.h>
 
 /// Mask values for matched sources
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMoments.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMoments.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceMoments.c	(revision 29060)
@@ -22,16 +22,23 @@
 #include <strings.h>
 #include <pslib.h>
+
 #include "pmHDU.h"
 #include "pmFPA.h"
-#include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
 
@@ -54,4 +61,7 @@
 # define VALID_RADIUS(X,Y,RAD2) (((RAD2) >= (PS_SQR(X) + PS_SQR(Y))) ? 1 : 0)
 
+static bool beVerbose = false;
+void pmSourceMomentsSetVerbose(bool state){ beVerbose = state; }
+
 bool pmSourceMoments(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN, psImageMaskType maskVal)
 {
@@ -61,11 +71,18 @@
     PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false);
 
-    // use sky from moments if defined, 0.0 otherwise
+    // use sky from moments if defined, 0.0 otherwise 
+
+    // XXX this value comes from the sky model at the source center, and tends to over-estimate
+    // the sky in the vicinity of bright sources.  we are better off assuming the model worked
+    // well:
     psF32 sky = 0.0;
     if (source->moments == NULL) {
-        source->moments = pmMomentsAlloc();
-    } else {
-        sky = source->moments->Sky;
-    }
+      source->moments = pmMomentsAlloc();
+    }
+    // XXX if (source->moments == NULL) {
+    // XXX     source->moments = pmMomentsAlloc();
+    // XXX } else {
+    // XXX     sky = source->moments->Sky;
+    // XXX }
 
     // First Pass: calculate the first moments (these are subtracted from the coordinates below)
@@ -131,9 +148,11 @@
             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; // XXX : MWV says I should include < 0.0 valued points...
+	    // skip pixels below specified significance level.  for a PSFs, this
+	    // over-weights the wings of bright stars compared to those of faint stars.
+	    // for the estimator used for extended source analysis (where the window
+	    // function is allowed to be arbitrarily large), we need to clip to avoid
+	    // negative second moments.
+            if (PS_SQR(pDiff) < minSN2*wDiff) continue; // 
+            if ((minSN > 0.0) && (pDiff < 0)) continue; // 
 
 	    // Apply a Gaussian window function.  Be careful with the window function.  S/N
@@ -197,4 +216,7 @@
     // Xn  = SUM (x - xc)^n * (z - sky)
 
+    psF32 RF = 0.0;
+    psF32 RH = 0.0;
+    psF32 RS = 0.0;
     psF32 XX = 0.0;
     psF32 XY = 0.0;
@@ -244,5 +266,6 @@
 	    if (r > radius) continue;
 
-	    psF32 pDiff = *vPix - sky;
+	    psF32 fDiff = *vPix - sky;
+	    psF32 pDiff = fDiff;
 	    psF32 wDiff = *vWgt;
 
@@ -257,5 +280,7 @@
 	    if (sigma > 0.0) {
 		// XXX a lot of extra flops; can we do pre-calculate?
-		psF32 z  = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2;
+		// XXX we were re-calculating r2 (maybe the compiler caught this?)
+		// psF32 z  = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2;
+		psF32 z  = r2 * rsigma2;
 		assert (z >= 0.0);
 		psF32 weight  = exp(-z);
@@ -266,4 +291,17 @@
 
 	    Sum += pDiff;
+
+# if (1)
+# if (0)
+	    if (fDiff < 0) continue;
+# endif
+	    psF32 rf = r * fDiff;
+	    psF32 rh = sqrt(r) * fDiff;
+	    psF32 rs = fDiff;
+# else
+	    psF32 rf = r * pDiff;
+	    psF32 rh = sqrt(r) * pDiff;
+	    psF32 rs = pDiff;
+# endif
 
 	    psF32 x = xDiff * pDiff;
@@ -284,4 +322,8 @@
 	    psF32 xyyy = xDiff * yyy / r2;
 	    psF32 yyyy = yDiff * yyy / r2;
+
+	    RF  += rf;
+	    RH  += rh;
+	    RS  += rs;
 
 	    XX  += xx;
@@ -302,4 +344,7 @@
     }
 
+    source->moments->Mrf = RF/RS;
+    source->moments->Mrh = RH/RS;
+
     source->moments->Mxx = XX/Sum;
     source->moments->Mxy = XY/Sum;
@@ -317,12 +362,71 @@
     source->moments->Myyyy = YYYY/Sum;
 
-    // if (source->moments->Mxx < 0) {
-    // 	fprintf (stderr, "error: neg second moment??\n");
-    // }
-    // if (source->moments->Myy < 0) {
-    // 	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",
+    // Calculate the Kron magnitude (make this block optional?)
+    // float radKron = 2.5*source->moments->Mrf;
+    float radKinner = 1.0*source->moments->Mrf;
+    float radKron   = 2.5*source->moments->Mrf;
+    float radKouter = 4.0*source->moments->Mrf;
+
+    int nKronPix = 0;
+    Sum = Var = 0.0;
+    float SumInner = 0.0;
+    float SumOuter = 0.0;
+
+    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
+
+	psF32 yDiff = row - yCM;
+	if (fabs(yDiff) > radKron) 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 & maskVal) {
+		    vMsk++;
+		    continue;
+		}
+		vMsk++;
+	    }
+	    if (isnan(*vPix)) continue;
+
+	    psF32 xDiff = col - xCM;
+	    if (fabs(xDiff) > radKron) continue;
+
+	    // radKron is just a function of (xDiff, yDiff)
+	    psF32 r2  = PS_SQR(xDiff) + PS_SQR(yDiff);
+	    psF32 r  = sqrt(r2);
+
+	    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 (r < radKron) {
+		Sum += pDiff;
+		Var += wDiff;
+		nKronPix ++;
+		// if (beVerbose) fprintf (stderr, "mome: %d %d  %f  %f  %f\n", col, row, sky, *vPix, Sum);
+	    }
+
+	    if ((r > radKinner) && (r < radKron)) {
+		SumInner += pDiff;
+	    }
+	    if ((r > radKron)  && (r < radKouter)) {
+		SumOuter += pDiff;
+	    }
+	}
+    }
+    source->moments->KronFlux = Sum;
+    source->moments->KronFinner = SumInner;
+    source->moments->KronFouter = SumOuter;
+    source->moments->KronFluxErr = sqrt(Var);
+
+    psTrace ("psModules.objects", 4, "Mrf: %f  KronFlux: %f  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->Mrf,   source->moments->KronFlux, 
 	     source->moments->Mxx,   source->moments->Mxy,   source->moments->Myy,
 	     source->moments->Mxxx,  source->moments->Mxxy,  source->moments->Mxyy,  source->moments->Myyy,
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePhotometry.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePhotometry.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePhotometry.c	(revision 29060)
@@ -22,15 +22,25 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
-#include "pmSource.h"
-#include "pmModelClass.h"
+#include "pmPSFtry.h"
+
 #include "pmSourcePhotometry.h"
 
@@ -66,5 +76,5 @@
 
 // XXX masked region should be (optionally) elliptical
-bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal)
+bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal, psImageMaskType markVal)
 {
     PS_ASSERT_PTR_NON_NULL(source, false);
@@ -122,4 +132,5 @@
         for (int i = 0; i < source->modelFits->n; i++) {
             pmModel *model = source->modelFits->data[i];
+	    if (model->flags & PM_MODEL_STATUS_BADARGS) continue;
             status = pmSourcePhotometryModel (&model->mag, NULL, model);
             if (model == source->modelEXT) foundEXT = true;
@@ -145,10 +156,10 @@
     // measure the contribution of included pixels
     if (mode & PM_SOURCE_PHOT_WEIGHT) {
-        pmSourcePixelWeight (&source->pixWeight, model, source->maskObj, maskVal);
+        pmSourcePixelWeight (&source->pixWeightNotBad, &source->pixWeightNotPoor, model, source->maskObj, maskVal, markVal);
     }
 
     // measure the contribution of included pixels
     if (mode & PM_SOURCE_PHOT_DIFFSTATS) {
-        pmSourceMeasureDiffStats (source, maskVal);
+        pmSourceMeasureDiffStats (source, maskVal, markVal);
     }
 
@@ -191,5 +202,5 @@
 
     // measure object aperture photometry
-    status = pmSourcePhotometryAper  (&source->apMag, model, flux, mask, maskVal);
+    status = pmSourcePhotometryAper  (&source->apMagRaw, model, flux, mask, maskVal);
     if (!status) {
         psTrace ("psModules.objects", 3, "fail mag : bad Ap Mag");
@@ -199,11 +210,15 @@
     // if the aper mag is NAN, the flux < 0.  this can happen for sources near the
     // detection limits (esp near bright neighbors)
+    source->apMag = source->apMagRaw;
     if (isfinite (source->apMag) && isPSF && psf) {
         if (psf->growth && (mode & PM_SOURCE_PHOT_GROWTH)) {
-            source->apMag += pmGrowthCurveCorrect (psf->growth, source->apRadius);
+            source->apMag = source->apMagRaw + pmGrowthCurveCorrect (psf->growth, source->apRadius);
         }
         if (mode & PM_SOURCE_PHOT_APCORR) {
             // XXX this should be removed -- we no longer fit for the 'sky bias'
+	    // XXX is this happening???
             rflux   = pow (10.0, 0.4*source->psfMag);
+	    psAssert (psf->skyBias == 0.0, "sky bias not 0");
+	    psAssert (psf->skySat == 0.0, "sky sat not 0");
             source->apMag -= PS_SQR(source->apRadius)*rflux * psf->skyBias + psf->skySat / rflux;
         }
@@ -257,5 +272,8 @@
     PS_ASSERT_PTR_NON_NULL(image, false);
     PS_ASSERT_PTR_NON_NULL(mask, false);
-    PS_ASSERT_PTR_NON_NULL(model, false);
+
+    if (DO_SKY) {
+	PS_ASSERT_PTR_NON_NULL(model, false);
+    }
 
     float apSum = 0;
@@ -271,11 +289,14 @@
     psF32 **imData = image->data.F32;
     psImageMaskType **mkData = mask->data.PS_TYPE_IMAGE_MASK_DATA;
+    int nAperPix = 0;
 
     // measure apMag
-    for (int ix = 0; ix < image->numCols; ix++) {
-        for (int iy = 0; iy < image->numRows; iy++) {
+    for (int iy = 0; iy < image->numRows; iy++) {
+	for (int ix = 0; ix < image->numCols; ix++) {
             if (mkData[iy][ix] & maskVal)
                 continue;
             apSum += imData[iy][ix] - sky;
+	    nAperPix ++;
+	    // fprintf (stderr, "aper: %d %d  %f  %f  %f\n", ix, iy, sky, imData[iy][ix], apSum);
         }
     }
@@ -290,12 +311,14 @@
 
 // return source aperture magnitude
-bool pmSourcePixelWeight (float *pixWeight, pmModel *model, psImage *mask, psImageMaskType maskVal)
-{
-    PS_ASSERT_PTR_NON_NULL(pixWeight, false);
+bool pmSourcePixelWeight (float *pixWeightNotBad, float *pixWeightNotPoor, pmModel *model, psImage *mask, psImageMaskType maskVal, psImageMaskType markVal)
+{
+    PS_ASSERT_PTR_NON_NULL(pixWeightNotBad, false);
+    PS_ASSERT_PTR_NON_NULL(pixWeightNotPoor, false);
     PS_ASSERT_PTR_NON_NULL(mask, false);
     PS_ASSERT_PTR_NON_NULL(model, false);
 
     float modelSum = 0;
-    float validSum = 0;
+    float notBadSum = 0;
+    float notPoorSum = 0;
     float sky = 0;
     float value;
@@ -305,5 +328,6 @@
     int dY, DY, NY;
 
-    *pixWeight = 0.0;
+    *pixWeightNotBad = 0.0;
+    *pixWeightNotPoor = 0.0;
 
     // we only care about the value of the object model, not the local sky
@@ -345,28 +369,26 @@
 
             // for the full model, add all points
-            value = model->modelFunc (NULL, params, coord) - sky;
+            value = fabs(model->modelFunc (NULL, params, coord) - sky);
             modelSum += value;
 
             // include count only the unmasked pixels within the image area
-            if (mx < 0)
-                continue;
-            if (my < 0)
-                continue;
-            if (mx >= NX)
-                continue;
-            if (my >= NY)
-                continue;
-            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskVal)
-                continue;
-
-            validSum += value;
+            if (mx < 0) continue;
+            if (my < 0) continue;
+            if (mx >= NX) continue;
+            if (my >= NY) continue;
+
+            if (!(mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskVal)) {
+		notBadSum += value;
+	    }
+            if (!(mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & ~markVal)) {
+		notPoorSum += value;
+	    }
         }
     }
     psFree (coord);
 
-    if (validSum <= 0)
-        return false;
-
-    *pixWeight = validSum / modelSum;
+    *pixWeightNotBad  = notBadSum  / modelSum;
+    *pixWeightNotPoor = notPoorSum / modelSum;
+
     return (true);
 }
@@ -374,6 +396,6 @@
 # define FLUX_LIMIT 3.0
 
-// return source aperture magnitude
-bool pmSourceMeasureDiffStats (pmSource *source, psImageMaskType maskVal)
+// measure stats that may be using in difference images for distinguishing real sources from bad residuals
+bool pmSourceMeasureDiffStats (pmSource *source, psImageMaskType maskVal, psImageMaskType markVal)
 {
     PS_ASSERT_PTR_NON_NULL(source, false);
@@ -399,4 +421,8 @@
     for (int iy = 0; iy < flux->numRows; iy++) {
         for (int ix = 0; ix < flux->numCols; ix++) {
+	    // only count up the stats in the unmarked region (ie, the aperture)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & markVal) {
+                continue;
+            }
             if (mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal) {
                 nMask ++;
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePhotometry.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePhotometry.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePhotometry.h	(revision 29060)
@@ -52,9 +52,11 @@
 
 bool pmSourceMagnitudesInit (psMetadata *config);
-bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal);
-bool pmSourcePixelWeight (float *pixWeight, pmModel *model, psImage *mask, psImageMaskType maskVal);
+bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psImageMaskType maskVal, psImageMaskType markVal);
+
+bool pmSourcePixelWeight (float *pixWeightNotBad, float *pixWeightNotPoor, pmModel *model, psImage *mask, psImageMaskType maskVal, psImageMaskType markVal);
+
 bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *weight, psImageMaskType maskVal, const float covarFactor);
 
-bool pmSourceMeasureDiffStats (pmSource *source, psImageMaskType maskVal);
+bool pmSourceMeasureDiffStats (pmSource *source, psImageMaskType maskVal, psImageMaskType markVal);
 
 double pmSourceDataDotModel (const pmSource *Mi, const pmSource *Mj, const bool unweighted_sum, const float covarFactor, psImageMaskType maskVal);
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotApResid.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotApResid.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotApResid.c	(revision 29060)
@@ -25,15 +25,25 @@
 #include "pmFPAview.h"
 #include "pmFPAfile.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
 #include "pmDetections.h"
-#include "pmSource.h"
+
 #include "pmSourcePlots.h"
 #include "pmKapaPlots.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotMoments.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotMoments.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotMoments.c	(revision 29060)
@@ -28,15 +28,24 @@
 #include "pmFPAview.h"
 #include "pmFPAfile.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
 #include "pmDetections.h"
-#include "pmSource.h"
 #include "pmSourcePlots.h"
 #include "pmKapaPlots.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotPSFModel.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotPSFModel.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourcePlotPSFModel.c	(revision 29060)
@@ -28,15 +28,25 @@
 #include "pmFPAview.h"
 #include "pmFPAfile.h"
+
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmGrowthCurve.h"
-#include "pmResiduals.h"
-#include "pmTrend2D.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
-#include "pmModel.h"
 #include "pmDetections.h"
-#include "pmSource.h"
 #include "pmSourcePlots.h"
 #include "pmKapaPlots.h"
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceSky.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceSky.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceSky.c	(revision 29060)
@@ -21,17 +21,25 @@
 #include <string.h>
 #include <pslib.h>
+
 #include "pmHDU.h"
 #include "pmFPA.h"
-#include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
+
 #include "pmSourceSky.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceUtils.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceUtils.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceUtils.c	(revision 29060)
@@ -21,17 +21,25 @@
 #include <string.h>
 #include <pslib.h>
+
 #include "pmHDU.h"
 #include "pmFPA.h"
-#include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
+
 #include "pmSourceUtils.h"
 
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceVisual.c
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceVisual.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSourceVisual.c	(revision 29060)
@@ -4,8 +4,28 @@
 
 #include <pslib.h>
+#include "pmHDU.h"
+#include "pmFPA.h"
+
 #include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
 #include "pmPSF.h"
 #include "pmPSFtry.h"
-#include "pmSource.h"
+#include "pmDetections.h"
+
 #include "pmSourceVisual.h"
 
@@ -13,4 +33,5 @@
 #include <kapa.h>
 #include "pmVisual.h"
+#include "pmVisualUtils.h"
 
 // functions used to visualize the analysis as it goes
@@ -34,5 +55,5 @@
     Graphdata graphdata;
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.psf.metric", 2)) return true;
 
     if (kapa1 == -1) {
@@ -118,5 +139,5 @@
     Graphdata graphdata;
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.psf.subpix", 3)) return true;
 
     if (kapa1 == -1) {
@@ -280,5 +301,5 @@
 bool pmSourceVisualShowModelFits (pmPSF *psf, psArray *sources, psImageMaskType maskVal) {
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.psf.fits", 2)) return true;
 
     if (kapa2 == -1) {
@@ -360,5 +381,6 @@
 bool pmSourceVisualShowModelFit (pmSource *source) {
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.psf.fitresid", 2)) return true;
+
     if (!source->pixels) return false;
     if (!source->modelFlux) return false;
@@ -404,5 +426,6 @@
     Graphdata graphdata;
 
-    if (!pmVisualIsVisual() || !plotPSF) return true;
+    if (!plotPSF) return true;
+    if (!pmVisualTestLevel("psphot.psf.resid", 2)) return true;
 
     if (kapa1 == -1) {
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmSpan.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmSpan.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmSpan.h	(revision 29060)
@@ -10,6 +10,4 @@
 # ifndef PM_SPAN_H
 # define PM_SPAN_H
-
-#include <pslib.h>
 
 /// @addtogroup Objects Object Detection / Analysis Functions
Index: /branches/sc_branches/trunkTest/psModules/src/objects/pmTrend2D.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/objects/pmTrend2D.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/objects/pmTrend2D.h	(revision 29060)
@@ -12,6 +12,4 @@
 # ifndef PM_TREND_2D_H
 # define PM_TREND_2D_H
-
-#include <pslib.h>
 
 /// @addtogroup Objects Object Detection / Analysis Functions
Index: /branches/sc_branches/trunkTest/psModules/src/psmodules.h
===================================================================
--- /branches/sc_branches/trunkTest/psModules/src/psmodules.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psModules/src/psmodules.h	(revision 29060)
@@ -10,4 +10,5 @@
 #include <pmKapaPlots.h>
 #include <pmVisual.h>
+#include <pmVisualUtils.h>
 #include <ippStages.h>
 #include <ippDiffMode.h>
@@ -113,4 +114,8 @@
 
 // the following headers are from psModule:objects
+#include <pmTrend2D.h>
+#include <pmResiduals.h>
+#include <pmGrowthCurve.h>
+
 #include <pmSpan.h>
 #include <pmFootprintSpans.h>
@@ -119,23 +124,23 @@
 #include <pmDetections.h>
 #include <pmMoments.h>
+
+#include <pmModelFuncs.h>
+#include <pmModel.h>
+
+#include <pmSourceMasks.h>
 #include <pmSourceExtendedPars.h>
 #include <pmSourceDiffStats.h>
-#include <pmResiduals.h>
-#include <pmGrowthCurve.h>
-#include <pmTrend2D.h>
+#include <pmSource.h>
+#include <pmSourceFitModel.h>
 #include <pmPSF.h>
-#include <pmModel.h>
-#include <pmSourceMasks.h>
-#include <pmSource.h>
+#include <pmPSFtry.h>
 #include <pmPhotObj.h>
 #include <pmSourceUtils.h>
 #include <pmSourceIO.h>
 #include <pmSourceSky.h>
-#include <pmSourceFitModel.h>
 #include <pmSourceFitSet.h>
 #include <pmSourceContour.h>
 #include <pmSourcePlots.h>
 #include <pmPSF_IO.h>
-#include <pmPSFtry.h>
 #include <pmModelClass.h>
 #include <pmModelUtils.h>
@@ -144,4 +149,5 @@
 #include <pmSourceMatch.h>
 #include <pmDetEff.h>
+#include <pmPCMdata.h>
 
 // The following headers are from random locations, here because they cross bounds
Index: /branches/sc_branches/trunkTest/psastro/src/psastroModelFitBoresite.c
===================================================================
--- /branches/sc_branches/trunkTest/psastro/src/psastroModelFitBoresite.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psastro/src/psastroModelFitBoresite.c	(revision 29060)
@@ -80,5 +80,5 @@
     params->data.F32[PAR_T0] = 0.0;
 
-    psMinimization *myMin = psMinimizationAlloc (25, 0.001);
+    psMinimization *myMin = psMinimizationAlloc (25, 0.001, 1.0);
     psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
     
Index: /branches/sc_branches/trunkTest/psphot/doc/notes.20100715.txt
===================================================================
--- /branches/sc_branches/trunkTest/psphot/doc/notes.20100715.txt	(revision 29060)
+++ /branches/sc_branches/trunkTest/psphot/doc/notes.20100715.txt	(revision 29060)
@@ -0,0 +1,33 @@
+
+2010.08.12
+
+  speeding up the PCM fitting.  
+
+  * first, I need to convert the convolutions to FFTs (double check that this will actually be faster!)
+  * second, I need to thread the PCM fitting process
+
+  I have three options:
+
+  1) use the FFT threading in fftw -- each convolution would run threaded, but separate ones would be run in series
+     * con: the images are generally small, so the threading overhead may be large compared to the operation (test?)
+  2) each pass of the minimization has 1 + N convolutions to perform: run these in separate threads
+     * can only use 1+N threads, where N is the number of free parameters (Io, Sxx, Syy, Sxy, but maybe also Xo, Yo)
+  3) thread by source, using the system defined for the other fitting. 
+     * since these source are large, this is a bit trickier to guarantee non-collision. 
+     + infrastructure is easy -- copy psphotBlendFit.
+
+2010.07.15
+
+various psphot issues that need to be addressed:
+
+* update extNsigma based on kron mags 
+* convert EXT sigmas to a probability (watch that extNsigma is correctly defined)
+* psphot forced fails for negative flux
+  - do a run, plot a histogram of fluxes as various steps
+  FIXED: this was caused by minimum limit of 0.0 in linear fitting
+
+* capability to choose extended source fits based on |b|
+
+* update psf-convolved fitting to work with sersic (iteration)
+  DONE: but, needs to be sped up
+
Index: /branches/sc_branches/trunkTest/psphot/doc/psf.load.txt
===================================================================
--- /branches/sc_branches/trunkTest/psphot/doc/psf.load.txt	(revision 29060)
+++ /branches/sc_branches/trunkTest/psphot/doc/psf.load.txt	(revision 29060)
@@ -0,0 +1,75 @@
+
+We need to have consistent behavior when we determine the PSF from the image or load it externally.
+
+Here is a list of the metadata info generated during the psphot analysis (these are mostly stored on the 'analysis' metadata, sometimes in chip and sometimes in readout).
+
+  ANGLE               : PSF Model position angle 
+  APLOSS	      : flux lost out of reference aperture
+  APMIFIT	      : aperture magnitude - psf fit magnitude (aperture correction
+  DAPMIFIT	      : error on APMIFIT
+ *EFFECTIVE_AREA      : effective area of the PSF model
+  FLIMIT	      : limiting flux (not currently set correctly)
+  FSATUR	      : saturation flux (not currently set correctly)
+  FWHM_MAJ	      : PSF Model FWHM (Major-Axis)
+  FWHM_MIN	      : PSF Model FWHM (Minor-Axis)
+  FW_MJ_LQ	      : PSF Model FWHM (Major-Axis lower quartile)
+  FW_MJ_SG	      : PSF Model FWHM (Major-Axis sigma)
+  FW_MJ_UQ	      : PSF Model FWHM (Major-Axis upper quartile)
+  FW_MN_LQ	      : PSF Model FWHM (Minor-Axis lower quartile)
+  FW_MN_SG	      : PSF Model FWHM (Minor-Axis sigma)
+  FW_MN_UQ	      : PSF Model FWHM (Minor-Axis upper quartile)
+  IQ_FW1	      : Moments-based FWHM (Major-Axis)
+  IQ_FW1_E	      : Moments-based FWHM (Major-Axis Stdev)
+  IQ_FW2	      : Moments-based FWHM (Minor-Axis)
+  IQ_FW2_E	      : Moments-based FWHM (Minor-Axis Stdev)
+  IQ_M2	  	      : Moments-based shape parameter
+  IQ_M2C	      : Moments-based shape parameter
+  IQ_M2C_E	      : Moments-based shape parameter
+  IQ_M2C_L	      : Moments-based shape parameter
+  IQ_M2C_U	      : Moments-based shape parameter
+  IQ_M2S	      : Moments-based shape parameter
+  IQ_M2S_E	      : Moments-based shape parameter
+  IQ_M2S_L	      : Moments-based shape parameter
+  IQ_M2S_U	      : Moments-based shape parameter
+  IQ_M2_ER	      : Moments-based shape parameter
+  IQ_M2_LQ	      : Moments-based shape parameter
+  IQ_M2_UQ	      : Moments-based shape parameter
+  IQ_M3	  	      : Moments-based shape parameter
+  IQ_M3_ER	      : Moments-based shape parameter
+  IQ_M3_LQ	      : Moments-based shape parameter
+  IQ_M3_UQ	      : Moments-based shape parameter
+  IQ_M4	  	      : Moments-based shape parameter
+  IQ_M4_ER	      : Moments-based shape parameter
+  IQ_M4_LQ	      : Moments-based shape parameter
+  IQ_M4_UQ	      : Moments-based shape parameter
+  IQ_NSTAR            : Number of sources used to measure moments-based parameters
+  MOMENTS_GAUSS_SIGMA : Sigma of Gaussian window used for moments analysis 
+  MOMENTS_SX_MAX      : max allowed Mxx (second moment in x) allowed for PSF clump 
+  MOMENTS_SY_MAX      : max allowed Myy (second moment in y) allowed for PSF clump 
+  MSKY_MAX            : Sky Model max value
+  MSKY_MIN            : Sky Model min value
+  MSKY_MN             : Sky Model mean value
+  MSKY_NX             : Sky Model number of cells (x)
+  MSKY_NY             : Sky Model number of cells (y)
+  MSKY_SIG            : Sky Model sigma
+  NAPMIFIT            : Number of stars used for APMIFIT analysis
+  NDET_CR	      : Number of sources classified as 'cosmic ray'
+  NDET_EXT	      : Number of sources classified as 'extended'
+  NPSFSTAR	      : Number of sources used for PSF model
+  NSTARS	      : Total number of sources
+  PEAK_THRESHOLD      : threshold of peak detection analysis (saved but not re-used)
+  PSF.CLUMP.DX        : size of clump in X
+  PSF.CLUMP.DY        : size of clump in Y
+  PSF.CLUMP.NREGIONS  : number of PSF clump regions measured for this image
+  PSF.CLUMP.X         : center of clump in X
+  PSF.CLUMP.Y         : center of clump in Y
+  PSFMODEL	      : do we have a valid PSF model?
+  PSF_APERTURE        : aperture used to measure the aperture magnitude of PSF sources
+  PSF_CLUMP_GRID_SCALE: pixelization size used for PSF clump search 
+  PSF_FIT_RADIUS      : size of window used for PSF model fits
+  PSF_MAX_NSTARS      : maximum number of sources used to find the PSF model
+  PSF_MOMENTS_RADIUS  : size of window used for moments analysis (Gaussian window is applied within this radius)
+  SIGMA_SMOOTH        : sigma of kernel used for smoothing to generate the significance 
+  SIGNIFICANCE_SCALE_FACTOR : factor needed to adjust the level of the significance image
+  SKY_MEAN            : mean of background
+  SKY_STDEV	      : stdev of full background image
Index: /branches/sc_branches/trunkTest/psphot/doc/visual.txt
===================================================================
--- /branches/sc_branches/trunkTest/psphot/doc/visual.txt	(revision 29060)
+++ /branches/sc_branches/trunkTest/psphot/doc/visual.txt	(revision 29060)
@@ -0,0 +1,47 @@
+
+Visualization Options
+
+image   : display image
+backgnd : display image
+signif  : display image
+
+show image        : image 1 or object 1
+show background   : image 2 or backgnd 1
+show significance : image 3 or signif 1
+show residual     : image 2 or resid 1
+
+XXX: these all need to have the image:
+show peaks        : object 1 or peaks 1
+show moments      : object 2 or image.moments 1
+show footprints   : object 3 or footprints 1
+show rough class  : object 3 or class 3
+show flags        : (disabled)
+show size class   : object 2 or class 2
+show petrosian    : object 2 or petro 1
+
+plot final moments (2D) : moments 1  
+plot test moments (2D)  : moments 2
+plot source sizes : class 1 
+plot ap resid     : apresid 1
+plot chisq        : chisq 1
+
+show PSF model    : psf 1
+show PSF stars    : psf 2
+show Sat stars    : ?
+
+show radial profiles : profile 
+
+petrosian visualization:
+
+  psphotPetrosianVisualEllipticalContour
+  psphotPetrosianVisualStats
+  psphotPetrosianVisualProfileRadii
+  psphotPetrosianVisualProfileByAngle
+
+psphot visualization in psModules:
+
+ pmSourceVisualPSFModelResid
+ pmSourceVisualShowModelFit
+ pmSourceVisualShowModelFits
+ pmSourceVisualPlotPSFMetricSubpix
+ pmSourceVisualPlotPSFMetric
Index: /branches/sc_branches/trunkTest/psphot/src/Makefile.am
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/Makefile.am	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/Makefile.am	(revision 29060)
@@ -163,10 +163,8 @@
 	psphotOutput.c		       \
 	psphotFakeSources.c	       \
-	psphotModelWithPSF.c           \
 	psphotExtendedSourceAnalysis.c \
 	psphotExtendedSourceAnalysisByObject.c \
 	psphotExtendedSourceFits.c     \
 	psphotKernelFromPSF.c	       \
-	psphotPSFConvModel.c	       \
 	psphotFitSet.c		       \
 	psphotSourceFreePixels.c       \
Index: /branches/sc_branches/trunkTest/psphot/src/psphot.h
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphot.h	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphot.h	(revision 29060)
@@ -12,12 +12,4 @@
 
 #define PSPHOT_RECIPE_PSF_FAKE_ALLOW "PSF.FAKE.ALLOW" // Name for recipe component permitting fake PSFs
-
-// pmPCMData : PSF Convolved Model data storage structure
-typedef struct {
-    psImage *model;
-    psArray *dmodels;
-    psImage *modelConv;
-    psArray *dmodelsConv;
-} pmPCMData;
 
 // top-level psphot functions
@@ -114,4 +106,5 @@
 bool            psphotExtendedSourceFits (pmConfig *config, const pmFPAview *view, const char *filerule);
 bool            psphotExtendedSourceFitsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index, psMetadata *recipe);
+bool            psphotExtendedSourceFits_Threaded (psThreadJob *job);
 
 bool            psphotApResid (pmConfig *config, const pmFPAview *view, const char *filerule);
@@ -188,11 +181,11 @@
 
 // functions to set the correct source pixels
-bool            psphotInitRadiusPSF(const psMetadata *recipe, const psMetadata *analysis, const pmModelType type);
+bool            psphotInitRadiusPSF (psMetadata *recipe, pmReadout *readout);
+bool            psphotInitRadiusEXT (psMetadata *recipe, pmReadout *readout);
 
 bool            psphotCheckRadiusPSF (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
 bool            psphotCheckRadiusPSFBlend (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal, float dR);
-bool            psphotInitRadiusEXT (psMetadata *recipe, pmModelType type);
-bool            psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psImageMaskType markVal);
-float           psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal);
+bool            psphotSetRadiusFootprint (float *radius, pmReadout *readout, pmSource *source, psImageMaskType markVal, float factor);
+bool            psphotSetRadiusModel (pmModel *model, pmReadout *readout, pmSource *source, psImageMaskType markVal, bool deep);
 
 bool            psphotDumpMoments (psMetadata *recipe, psArray *sources);
@@ -210,10 +203,10 @@
 //  functions to support the source fitting process
 bool            psphotInitLimitsPSF (psMetadata *recipe, pmReadout *readout);
-bool            psphotInitLimitsEXT (psMetadata *recipe);
-bool            psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal);
-bool            psphotFitBlob (pmReadout *readout, pmSource *source, psArray *sources, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal);
-bool            psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal);
-pmModel        *psphotFitEXT (pmReadout *readout, pmSource *source, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal);
-psArray        *psphotFitDBL (pmReadout *readout, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal);
+bool            psphotInitLimitsEXT (psMetadata *recipe, pmReadout *readout);
+bool            psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
+bool            psphotFitBlob (pmReadout *readout, pmSource *source, psArray *sources, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
+bool            psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
+pmModel        *psphotFitEXT (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal);
+psArray        *psphotFitDBL (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
 
 // functions to support simultaneous multi-source fitting
@@ -252,4 +245,5 @@
 bool            psphotVisualShowBackground (pmConfig *config, const pmFPAview *view, pmReadout *readout);
 bool            psphotVisualShowSignificance (psImage *image, float min, float max);
+bool            psphotVisualShowLogSignificance (psImage *image, float min, float max);
 bool            psphotVisualShowPeaks (pmDetections *detections);
 bool            psphotVisualShowFootprints (pmDetections *detections);
@@ -292,33 +286,4 @@
 bool psphotRadialBins (psMetadata *recipe, pmSource *source, float radiusMax, float skynoise);
 
-// structures & functions to support psf-convolved model fitting
-
-// psf-convolved model fitting
-bool psphotModelWithPSF_LMM (
-    psMinimization *min,
-    psImage *covar,
-    psVector *params,
-    psMinConstraint *constraint,
-    pmSource *source,
-    const psKernel *psf,
-    psMinimizeLMChi2Func func);
-
-psF32 psphotModelWithPSF_SetABX(
-    psImage  *alpha,
-    psVector *beta,
-    const psVector *params,
-    const psVector *paramMask,
-    pmPCMData *pcm,
-    const pmSource *source,
-    const psKernel *psf,
-    psMinimizeLMChi2Func func);
-
-pmPCMData *pmPCMDataAlloc (
-    const psVector *params,
-    const psVector *paramMask,
-    pmSource *source);
-
-psImage *pmPCMDataSaveImage (pmPCMData *pcm);
-
 int psphotKapaOpen (void);
 bool psphotKapaClose (void);
@@ -364,6 +329,4 @@
 
 bool psphotFitSourcesLinearStack (pmConfig *config, psArray *objects, bool final);
-int pmPhotObjSortBySN (const void **a, const void **b);
-int pmPhotObjSortByX (const void **a, const void **b);
 
 typedef enum {
@@ -462,3 +425,8 @@
 bool psphotStackObjectsUnifyPosition (psArray *objects);
 
+bool psphotFitSersicIndex (pmModel *model, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal);
+
+bool psphotFitSersicIndexPCM (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
+pmModel *psphotFitPCM (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize);
+
 #endif
Index: /branches/sc_branches/trunkTest/psphot/src/psphotAddNoise.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotAddNoise.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotAddNoise.c	(revision 29060)
@@ -34,7 +34,4 @@
 
     bool status = false;
-    psEllipseShape oldshape;
-    psEllipseShape newshape;
-    psEllipseAxes axes;
 
     // find the currently selected readout
@@ -86,44 +83,5 @@
         if (!(source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED)) continue;
 
-        // select appropriate model
-        pmModel *model = pmSourceGetModel (NULL, source);
-        if (model == NULL) continue;  // model must be defined
-
-        if (add) {
-            psTrace ("psphot", 4, "adding noise for object at %f,%f\n", model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS]);
-        } else {
-            psTrace ("psphot", 4, "remove noise for object at %f,%f\n", model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS]);
-        }
-
-        psF32 *PAR = model->params->data.F32;
-
-        // save original values
-        float oldI0  = PAR[PM_PAR_I0];
-        oldshape.sx  = PAR[PM_PAR_SXX];
-        oldshape.sy  = PAR[PM_PAR_SYY];
-        oldshape.sxy = PAR[PM_PAR_SXY];
-
-        // XXX can this be done more intelligently?
-        if (oldI0 == 0.0) continue;
-        if (!isfinite(oldI0)) continue;
-
-        // increase size and height of source
-        axes = psEllipseShapeToAxes (oldshape, 20.0);
-        axes.major *= SIZE;
-        axes.minor *= SIZE;
-        newshape = psEllipseAxesToShape (axes);
-        PAR[PM_PAR_I0]  = FACTOR*oldI0;
-        PAR[PM_PAR_SXX] = newshape.sx;
-        PAR[PM_PAR_SYY] = newshape.sy;
-        PAR[PM_PAR_SXY] = newshape.sxy;
-
-        // XXX if we use pmSourceOp, the size (and possibly Io) will not be respected
-        pmSourceOp (source, PM_MODEL_OP_FULL | PM_MODEL_OP_NOISE, add, maskVal, 0, 0);
-
-        // restore original values
-        PAR[PM_PAR_I0]  = oldI0;
-        PAR[PM_PAR_SXX] = oldshape.sx;
-        PAR[PM_PAR_SYY] = oldshape.sy;
-        PAR[PM_PAR_SXY] = oldshape.sxy;
+	pmSourceNoiseOp (source, PM_MODEL_OP_FULL | PM_MODEL_OP_NOISE, FACTOR, SIZE, add, maskVal, 0, 0);
     }
     if (add) {
@@ -132,4 +90,5 @@
         psLogMsg ("psphot.noise", PS_LOG_INFO, "sub noise for %ld objects: %f sec\n", sources->n, psTimerMark ("psphot.noise"));
     }
+
     return true;
 }
Index: /branches/sc_branches/trunkTest/psphot/src/psphotApResid.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotApResid.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotApResid.c	(revision 29060)
@@ -459,5 +459,5 @@
         psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
 
-        bool status = pmSourceMagnitudes (source, psf, photMode, maskVal);
+        bool status = pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
 
         // clear the mask bit
Index: /branches/sc_branches/trunkTest/psphot/src/psphotArguments.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotArguments.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotArguments.c	(revision 29060)
@@ -176,10 +176,4 @@
     }
 
-    // visual : interactive display mode
-    if ((N = psArgumentGet (argc, argv, "-visual"))) {
-        psArgumentRemove (N, &argc, argv);
-        pmVisualSetVisual(true);
-    }
-
     // break : used from recipe throughout psphotReadout
     if ((N = psArgumentGet (argc, argv, "-break"))) {
Index: /branches/sc_branches/trunkTest/psphot/src/psphotBlendFit.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotBlendFit.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotBlendFit.c	(revision 29060)
@@ -65,19 +65,38 @@
     assert (status && fitIter > 0);
 
-    float fitTol = psMetadataLookupF32 (&status, recipe, "EXT_FIT_TOL"); // Fit tolerance
-    assert (status && isfinite(fitTol) && fitTol > 0);
+    float fitMinTol = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MIN_TOL"); // Fit tolerance
+    if (!status || !isfinite(fitMinTol) || fitMinTol <= 0) {
+	fitMinTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_TOL"); // Fit tolerance
+	if (!status || !isfinite(fitMinTol) || fitMinTol <= 0) {
+	    psAbort("PSF_FIT_MIN_TOL (and PSF_FIT_TOL) not defined or positive");
+	}
+    }
+
+    float fitMaxTol = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_TOL"); // Fit tolerance
+    if (!status || !isfinite(fitMaxTol) || fitMaxTol <= 0) {
+	fitMaxTol = 1.0;
+    }
 
     bool poisson = psMetadataLookupBool(&status, recipe, "POISSON.ERRORS.PHOT.LMM"); // Poisson errors?
     assert (status);
 
+    float maxChisqDOF = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_CHISQ"); // Fit tolerance
+
     float skySig = psMetadataLookupF32(&status, recipe, "SKY_SIG");
     assert (status && isfinite(skySig) && skySig > 0);
 
     // Define source fitting parameters for extended source fits
-    pmSourceFitModelInit(fitIter, fitTol, PS_SQR(skySig), poisson);
+    pmSourceFitOptions *fitOptions = pmSourceFitOptionsAlloc();
+    fitOptions->nIter         = fitIter;
+    fitOptions->minTol        = fitMinTol;
+    fitOptions->maxTol        = fitMaxTol;
+    fitOptions->maxChisqDOF   = maxChisqDOF;
+    fitOptions->poissonErrors = poisson;
+    fitOptions->weight        = PS_SQR(skySig);
+    fitOptions->mode          = PM_SOURCE_FIT_PSF;
 
     psphotInitLimitsPSF (recipe, readout);
-    psphotInitLimitsEXT (recipe);
-    psphotInitRadiusPSF (recipe, readout->analysis, psf->type);
+    psphotInitLimitsEXT (recipe, readout);
+    psphotInitRadiusPSF (recipe, readout);
 
     // starts the timer, sets up the array of fitSets
@@ -88,4 +107,5 @@
     if (!sources->n) {
         psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping blend");
+	psFree (fitOptions);
         return true;
     }
@@ -112,4 +132,5 @@
             psArrayAdd(job->args, 1, psf);
             psArrayAdd(job->args, 1, newSources); // return for new sources
+            psArrayAdd(job->args, 1, fitOptions); // default fit options
             psFree (newSources);
 
@@ -121,31 +142,7 @@
             if (!psThreadJobAddPending(job)) {
                 psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
+		psFree (fitOptions);
                 return NULL;
             }
-
-# if (0)
-            {
-                int nfit = 0;
-                int npsf = 0;
-                int next = 0;
-                int nfail = 0;
-                psArray *newSources = psArrayAllocEmpty(16);
-
-                if (!psphotBlendFit_Unthreaded (&nfit, &npsf, &next, &nfail, readout, recipe, cells->data[j], psf, newSources)) {
-                    psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
-                    return NULL;
-                }
-                Nfit += nfit;
-                Npsf += npsf;
-                Next += next;
-                Nfail += nfail;
-
-                // add these back onto sources
-                for (int k = 0; k < newSources->n; k++) {
-                    psArrayAdd (sources, 16, newSources->data[k]);
-                }
-                psFree (newSources);
-            }
-# endif
         }
 
@@ -153,4 +150,5 @@
         if (!psThreadPoolWait (false)) {
             psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
+	    psFree (fitOptions);
             return NULL;
         }
@@ -163,11 +161,11 @@
             } else {
                 psScalar *scalar = NULL;
-                scalar = job->args->data[5];
+                scalar = job->args->data[6];
                 Nfit += scalar->data.S32;
-                scalar = job->args->data[6];
+                scalar = job->args->data[7];
                 Npsf += scalar->data.S32;
-                scalar = job->args->data[7];
+                scalar = job->args->data[8];
                 Next += scalar->data.S32;
-                scalar = job->args->data[8];
+                scalar = job->args->data[9];
                 Nfail += scalar->data.S32;
 
@@ -186,4 +184,5 @@
       psphotSaveImage (NULL, readout->image,  "image.v2.fits");
     }
+    psFree (fitOptions);
 
     psLogMsg ("psphot.psphotBlendFit", PS_LOG_INFO, "fit models: %f sec for %d objects (%d psf, %d ext, %d failed, %ld skipped)\n", psTimerMark ("psphot.fit.nonlinear"), Nfit, Npsf, Next, Nfail, sources->n - Nfit);
@@ -204,9 +203,10 @@
     psScalar *scalar = NULL;
 
-    pmReadout *readout  = job->args->data[0];
-    psMetadata *recipe  = job->args->data[1];
-    psArray *sources    = job->args->data[2];
-    pmPSF *psf          = job->args->data[3];
-    psArray *newSources = job->args->data[4];
+    pmReadout *readout  	   = job->args->data[0];
+    psMetadata *recipe  	   = job->args->data[1];
+    psArray *sources    	   = job->args->data[2];
+    pmPSF *psf          	   = job->args->data[3];
+    psArray *newSources 	   = job->args->data[4];
+    pmSourceFitOptions *fitOptions = job->args->data[5];
 
     // bit-masks to test for good/bad pixels
@@ -269,8 +269,14 @@
         Nfit ++;
 
+	if (0) {
+	    psF32 Mxx = source->moments->Mxx;
+	    psF32 Myy = source->moments->Myy;
+	    fprintf (stderr, "1: Mxx: %f, Myy: %f\n", Mxx, Myy);
+	}
+
         // try fitting PSFs or extended sources depending on source->mode
         // these functions subtract the resulting fitted source
         if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
-            if (psphotFitBlob (readout, source, newSources, psf, maskVal, markVal)) {
+            if (psphotFitBlob (readout, source, newSources, psf, fitOptions, maskVal, markVal)) {
                 source->type = PM_SOURCE_TYPE_EXTENDED;
                 psTrace ("psphot", 5, "source at %7.1f, %7.1f is ext", source->peak->xf, source->peak->yf);
@@ -280,5 +286,5 @@
             }
         } else {
-            if (psphotFitBlend (readout, source, psf, maskVal, markVal)) {
+            if (psphotFitBlend (readout, source, psf, fitOptions, maskVal, markVal)) {
                 source->type = PM_SOURCE_TYPE_STAR;
                 psTrace ("psphot", 5, "source at %7.1f, %7.1f is psf", source->peak->xf, source->peak->yf);
@@ -289,4 +295,10 @@
         }
 
+	if (0) {
+	    psF32 Mxx = source->moments->Mxx;
+	    psF32 Myy = source->moments->Myy;
+	    fprintf (stderr, "2: Mxx: %f, Myy: %f\n", Mxx, Myy);
+	}
+
         psTrace ("psphot", 5, "source at %7.1f, %7.1f failed", source->peak->xf, source->peak->yf);
         Nfail ++;
@@ -298,14 +310,14 @@
 
     // change the value of a scalar on the array (wrap this and put it in psArray.h)
-    scalar = job->args->data[5];
+    scalar = job->args->data[6];
     scalar->data.S32 = Nfit;
 
-    scalar = job->args->data[6];
+    scalar = job->args->data[7];
     scalar->data.S32 = Npsf;
 
-    scalar = job->args->data[7];
+    scalar = job->args->data[8];
     scalar->data.S32 = Next;
 
-    scalar = job->args->data[8];
+    scalar = job->args->data[9];
     scalar->data.S32 = Nfail;
 
Index: /branches/sc_branches/trunkTest/psphot/src/psphotChoosePSF.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotChoosePSF.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotChoosePSF.c	(revision 29060)
@@ -74,5 +74,5 @@
 
     // structure to store user options defining the psf
-    pmPSFOptions *options = pmPSFOptionsAlloc ();
+    pmPSFOptions *options = pmPSFOptionsAlloc();
 
     // load user options from the recipe. no need to check existence -- they are
@@ -138,11 +138,28 @@
         return false;
     }
-    float fitTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_TOL"); // Fit tolerance
-    if (!status || !isfinite(fitTol) || fitTol <= 0) {
-        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSF_FIT_TOL is not positive");
-        return false;
-    }
-    pmSourceFitModelInit(fitIter, fitTol, PS_SQR(SKY_SIG), options->poissonErrorsPhotLMM);
-
+    float fitMinTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_MIN_TOL"); // Fit tolerance
+    if (!status || !isfinite(fitMinTol) || fitMinTol <= 0) {
+	fitMinTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_TOL"); // Fit tolerance
+	if (!status || !isfinite(fitMinTol) || fitMinTol <= 0) {
+	    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "PSF_FIT_MIN_TOL (and PSF_FIT_TOL) not defined or positive");
+	    return false;
+	}
+    }
+    float fitMaxTol = psMetadataLookupF32 (&status, recipe, "PSF_FIT_MAX_TOL"); // Fit tolerance
+    if (!status || !isfinite(fitMaxTol) || fitMaxTol <= 0) {
+	fitMaxTol = 1.0;
+    }
+    float maxChisqDOF = psMetadataLookupF32 (&status, recipe, "PSF_FIT_MAX_CHISQ"); // Fit tolerance
+
+    // options which modify the behavior of the model fitting
+    options->fitOptions                = pmSourceFitOptionsAlloc();
+    options->fitOptions->nIter         = fitIter;
+    options->fitOptions->minTol        = fitMinTol;
+    options->fitOptions->maxTol        = fitMaxTol;
+    options->fitOptions->maxChisqDOF   = maxChisqDOF;
+    options->fitOptions->poissonErrors = options->poissonErrorsPhotLMM;
+    options->fitOptions->weight        = PS_SQR(SKY_SIG);
+    options->fitOptions->mode          = PM_SOURCE_FIT_PSF;
+    
     psArray *stars = psArrayAllocEmpty (sources->n);
 
@@ -227,4 +244,5 @@
 
     // try each model option listed in config
+    // pmPSFtryModel makes a local copy of the sources -- those points are not the same as those for 'sources'
     for (int i = 0; i < modelNames->n; i++) {
         char *modelName = modelNames->data[i];
@@ -304,10 +322,42 @@
 
     // unset the PSFSTAR flag for stars not used for PSF model
+    // XXX a more efficient way of achieving this would be to record a pair of arrays
+    // of the source index and the source id for the psf stars.  but that would require we do
+    // not re-sort the source list in the meanwhile
+    int nDrop = 0;
     for (int i = 0; i < try->sources->n; i++) {
         pmSource *source = try->sources->data[i];
         if (try->mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
-            source->mode &= ~PM_SOURCE_MODE_PSFSTAR;
-        }
-    }
+	    // need to find this source in the original list (these are copies, not pointers)
+	    for (int j = 0; j < sources->n; j++) {
+		pmSource *realSource = sources->data[j];
+		if (realSource->id != source->id) continue;
+		realSource->mode &= ~PM_SOURCE_MODE_PSFSTAR;
+		source->mode &= ~PM_SOURCE_MODE_PSFSTAR;
+		nDrop ++;
+		break;
+	    }
+        }
+    }
+    // fprintf (stderr, "drop %d stars as PSF stars\n", nDrop);
+
+    // XXX is this working?
+    // int N1 = 0;
+    // for (int i = 0; i < try->sources->n; i++) {
+    //     pmSource *source = try->sources->data[i];
+    // 	fprintf (stderr, "%llx : %d\n", (long long int) source, (source->mode & PM_SOURCE_MODE_PSFSTAR));
+    // 	if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
+    // 	    N1 ++;
+    //     }
+    // }
+    // int N2 = 0;
+    // for (int i = 0; i < sources->n; i++) {
+    //     pmSource *source = sources->data[i];
+    // 	fprintf (stderr, "%llx : %d\n", (long long int) source, (source->mode & PM_SOURCE_MODE_PSFSTAR));
+    // 	if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
+    // 	    N2 ++;
+    //     }
+    // }
+    // fprintf (stderr, "N1: %d, N2: %d\n", N1, N2);
 
     // build a PSF residual image
Index: /branches/sc_branches/trunkTest/psphot/src/psphotEllipticalContour.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotEllipticalContour.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotEllipticalContour.c	(revision 29060)
@@ -82,5 +82,5 @@
     params->data.F32[PAR_RMIN]    = Rmin;
 
-    psMinimization *myMin = psMinimizationAlloc (25, 0.001);
+    psMinimization *myMin = psMinimizationAlloc (25, 0.01, 1.00);
     psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
     
Index: /branches/sc_branches/trunkTest/psphot/src/psphotExtendedSourceAnalysis.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotExtendedSourceAnalysis.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotExtendedSourceAnalysis.c	(revision 29060)
@@ -121,4 +121,6 @@
 	if (source->peak->y > AnalysisRegion.y1) continue;
 
+	// fprintf (stderr, "xsrc: %f, %f : %f\n", source->peak->xf, source->peak->yf, source->peak->SN); 
+
 	// replace object in image
 	if (source->tmpFlags & PM_SOURCE_TMPF_SUBTRACTED) {
@@ -157,27 +159,4 @@
 	}
 
-# if (0)
-	// Isophotal Mags
-	if (doIsophotal) {
-	    if (!psphotIsophotal (source, recipe, maskVal)) {
-		psTrace ("psphot", 5, "failed to measure isophotal mags for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
-	    } else {
-		psTrace ("psphot", 5, "measured isophotal mags for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
-		Nisophot ++;
-		source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
-	    }
-	}
-	// Kron Mags
-	if (doKron) {
-	    if (!psphotKron (source, recipe, maskVal)) {
-		psTrace ("psphot", 5, "failed to measure kron mags for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
-	    } else {
-		psTrace ("psphot", 5, "measure kron mags for source at %7.1f, %7.1f", source->moments->Mx, source->moments->My);
-		Nkron ++;
-		source->mode |= PM_SOURCE_MODE_EXTENDED_STATS;
-	    }
-	}
-# endif
-
 	// re-subtract the object, leave local sky
 	pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
@@ -201,4 +180,6 @@
     }
 
+    // fprintf (stderr, "xsrc : tried %ld objects\n", sources->n);
+
     return true;
 }
Index: /branches/sc_branches/trunkTest/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotExtendedSourceFits.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotExtendedSourceFits.c	(revision 29060)
@@ -31,4 +31,186 @@
 // non-linear model fitting for extended sources
 bool psphotExtendedSourceFitsReadout (pmConfig *config, const pmFPAview *view, const char *filerule, int index, psMetadata *recipe) {
+
+    bool status;
+    int Next = 0;
+    int Nconvolve = 0;
+    int NconvolvePass = 0;
+    int Nplain = 0;
+    int NplainPass = 0;
+
+    psTimerStart ("psphot.extended");
+
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, index); // File of interest
+    psAssert (file, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
+    psAssert (detections, "missing detections?");
+
+    psArray *sources = detections->allSources;
+    psAssert (sources, "missing sources?");
+
+    if (!sources->n) {
+	psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
+	return true;
+    }
+
+    // determine the number of allowed threads
+    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS"); // Number of threads
+    if (!status) {
+        nThreads = 0;
+    }
+
+    // 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);
+
+    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
+    // select the collection of desired models
+    psMetadata *models = psMetadataLookupMetadata (&status, recipe, "EXTENDED_SOURCE_MODELS");
+    if (!status) {
+        psWarning ("extended source model fits requested but model model is missing (EXTENDED_SOURCE_MODELS)\n");
+        return true;
+    }
+    if (models->list->n == 0) {
+        psWarning ("extended source model fits requested but no models are specified\n");
+        return true;
+    }
+
+    // validate the model entries
+    psMetadataIterator *iter = psMetadataIteratorAlloc (models, PS_LIST_HEAD, NULL);
+    psMetadataItem *item = NULL;
+    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
+
+      if (item->type != PS_DATA_METADATA) {
+        psAbort ("Invalid type for EXTENDED_SOURCE_MODEL entry %s, not a metadata folder", item->name);
+        // XXX we could cull the bad entries or build a validated model folder
+      }
+
+      psMetadata *model = (psMetadata *) item->data.md;
+
+      // check on the model type
+      char *modelName = psMetadataLookupStr (&status, model, "MODEL");
+      int modelType = pmModelClassGetType (modelName);
+      if (modelType < 0) {
+        psAbort ("Unknown model class for EXTENDED_SOURCE_MODEL entry %s: %s", item->name, modelName);
+      }
+      psMetadataAddS32 (model, PS_LIST_TAIL, "MODEL_TYPE", PS_META_REPLACE, "", modelType);
+
+      // check on the SNLIM, set a float value
+      char *SNword = psMetadataLookupStr (&status, model, "SNLIM");
+      if (!status) {
+        psAbort("SNLIM not defined for extended source model %s\n", item->name);
+      }
+      float SNlim = atof (SNword);
+      psMetadataAddF32 (model, PS_LIST_TAIL, "SNLIM_VALUE", PS_META_REPLACE, "", SNlim);
+
+      // check on the PSF-Convolution status
+      char *convolvedWord = psMetadataLookupStr (&status, model, "PSF_CONVOLVED");
+      if (!status || (strcasecmp (convolvedWord, "true") && strcasecmp (convolvedWord, "false"))) {
+        psAbort ("PSF_CONVOLVED entry invalid or missing for EXTENDED_SOURCE_MODEL entry %s", item->name);
+      }
+      bool convolved = !strcasecmp (convolvedWord, "true");
+      psMetadataAddBool (model, PS_LIST_TAIL, "PSF_CONVOLVED_VALUE", PS_META_REPLACE, "", convolved);
+    }
+    psFree (iter);
+
+    // option to limit analysis to a specific region
+    char *region = psMetadataLookupStr (&status, recipe, "ANALYSIS_REGION");
+    psRegion *AnalysisRegion = psRegionAlloc(0,0,0,0);
+    *AnalysisRegion = psRegionForImage(readout->image, psRegionFromString (region));
+    if (psRegionIsNaN (*AnalysisRegion)) psAbort("analysis region mis-defined");
+
+    // what fraction of the PSF is used? (radius in pixels : 2 -> 5x5 box)
+    int psfSize = psMetadataLookupS32 (&status, recipe, "PCM_BOX_SIZE");
+    assert (status);
+
+    // source analysis is done in S/N order (brightest first)
+    sources = psArraySort (sources, pmSourceSortBySN);
+
+    // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
+    int Cx = 1, Cy = 1;
+    psphotChooseCellSizes (&Cx, &Cy, readout, nThreads);
+
+    psArray *cellGroups = psphotAssignSources (Cx, Cy, sources);
+
+    for (int i = 0; i < cellGroups->n; i++) {
+
+        psArray *cells = cellGroups->data[i];
+
+        for (int j = 0; j < cells->n; j++) {
+
+            // allocate a job -- if threads are not defined, this just runs the job
+            psThreadJob *job = psThreadJobAlloc ("PSPHOT_EXTENDED_FIT");
+
+            psArrayAdd(job->args, 1, readout);
+            psArrayAdd(job->args, 1, cells->data[j]); // sources
+            psArrayAdd(job->args, 1, models);
+            psArrayAdd(job->args, 1, AnalysisRegion); // XXX make a pointer
+
+            PS_ARRAY_ADD_SCALAR(job->args, psfSize, 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 Next
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nconvolve
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for NconvolvePass
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for Nplain
+            PS_ARRAY_ADD_SCALAR(job->args, 0, PS_TYPE_S32); // this is used as a return value for NplainPass
+
+            if (!psThreadJobAddPending(job)) {
+                psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
+		psFree(AnalysisRegion);
+                return false;
+            }
+        }
+
+        // wait for the threads to finish and manage results
+        if (!psThreadPoolWait (false)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
+	    psFree(AnalysisRegion);
+            return false;
+        }
+
+        // we have only supplied one type of job, so we can assume the types here
+        psThreadJob *job = NULL;
+        while ((job = psThreadJobGetDone()) != NULL) {
+            if (job->args->n < 1) {
+                fprintf (stderr, "error with job\n");
+            } else {
+                psScalar *scalar = NULL;
+                scalar = job->args->data[7];
+                Next += scalar->data.S32;
+                scalar = job->args->data[8];
+                Nconvolve += scalar->data.S32;
+                scalar = job->args->data[9];
+                NconvolvePass += scalar->data.S32;
+                scalar = job->args->data[10];
+                Nplain += scalar->data.S32;
+                scalar = job->args->data[11];
+                NplainPass += scalar->data.S32;
+            }
+            psFree(job);
+	}
+    }
+    psFree (cellGroups);
+    psFree(AnalysisRegion);
+
+    psLogMsg ("psphot", PS_LOG_INFO, "extended source analysis: %f sec for %d objects\n", psTimerMark ("psphot.extended"), Next);
+    psLogMsg ("psphot", PS_LOG_INFO, "  %d convolved models (%d passed)\n", Nconvolve, NconvolvePass);
+    psLogMsg ("psphot", PS_LOG_INFO, "  %d plain models (%d passed)\n", Nplain, NplainPass);
+    return true;
+}
+
+// non-linear model fitting for extended sources
+bool psphotExtendedSourceFits_Threaded (psThreadJob *job) {
 
     bool status;
@@ -39,93 +221,24 @@
     int NplainPass = 0;
     bool savePics = false;
-
-    // find the currently selected readout
-    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filerule, index); // File of interest
-    psAssert (file, "missing file?");
-
-    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
-    psAssert (readout, "missing readout?");
-
-    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
-    psAssert (detections, "missing detections?");
-
-    psArray *sources = detections->allSources;
-    psAssert (sources, "missing sources?");
-
-    if (!sources->n) {
-	psLogMsg ("psphot", PS_LOG_INFO, "no sources, skipping source size");
-	return true;
-    }
-
-    // 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);
-
-    psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
-    assert (markVal);
-
-    // maskVal is used to test for rejected pixels, and must include markVal
-    maskVal |= markVal;
-
-    // select the collection of desired models
-    psMetadata *models = psMetadataLookupMetadata (&status, recipe, "EXTENDED_SOURCE_MODELS");
-    if (!status) {
-        psWarning ("extended source model fits requested but model model is missing (EXTENDED_SOURCE_MODELS)\n");
-        return true;
-    }
-    if (models->list->n == 0) {
-        psWarning ("extended source model fits requested but no models are specified\n");
-        return true;
-    }
-
-    // validate the model entries
-    psMetadataIterator *iter = psMetadataIteratorAlloc (models, PS_LIST_HEAD, NULL);
-    psMetadataItem *item = NULL;
-    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
-
-      if (item->type != PS_DATA_METADATA) {
-        psAbort ("Invalid type for EXTENDED_SOURCE_MODEL entry %s, not a metadata folder", item->name);
-        // XXX we could cull the bad entries or build a validated model folder
-      }
-
-      psMetadata *model = (psMetadata *) item->data.md;
-
-      // check on the model type
-      char *modelName = psMetadataLookupStr (&status, model, "MODEL");
-      int modelType = pmModelClassGetType (modelName);
-      if (modelType < 0) {
-        psAbort ("Unknown model class for EXTENDED_SOURCE_MODEL entry %s: %s", item->name, modelName);
-      }
-      psMetadataAddS32 (model, PS_LIST_TAIL, "MODEL_TYPE", PS_META_REPLACE, "", modelType);
-
-      // check on the SNLIM, set a float value
-      char *SNword = psMetadataLookupStr (&status, model, "SNLIM");
-      if (!status) {
-        psAbort("SNLIM not defined for extended source model %s\n", item->name);
-      }
-      float SNlim = atof (SNword);
-      psMetadataAddF32 (model, PS_LIST_TAIL, "SNLIM_VALUE", PS_META_REPLACE, "", SNlim);
-
-      // check on the PSF-Convolution status
-      char *convolvedWord = psMetadataLookupStr (&status, model, "PSF_CONVOLVED");
-      if (!status || (strcasecmp (convolvedWord, "true") && strcasecmp (convolvedWord, "false"))) {
-        psAbort ("PSF_CONVOLVED entry invalid or missing for EXTENDED_SOURCE_MODEL entry %s", item->name);
-      }
-      bool convolved = !strcasecmp (convolvedWord, "true");
-      psMetadataAddBool (model, PS_LIST_TAIL, "PSF_CONVOLVED_VALUE", PS_META_REPLACE, "", convolved);
-    }
-    psFree (iter);
-
-    // 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");
-
-    // what fraction of the PSF is used? (radius in pixels : 2 -> 5x5 box)
-    int psfSize = psMetadataLookupS32 (&status, recipe, "PCM_BOX_SIZE");
-    assert (status);
-
-    // source analysis is done in S/N order (brightest first)
-    sources = psArraySort (sources, pmSourceSortBySN);
+    float radius;
+    psScalar *scalar = NULL;
+
+    // arguments: readout, sources, models, region, psfSize, maskVal, markVal
+    pmReadout *readout      = job->args->data[0];
+    psArray *sources        = job->args->data[1];
+    psMetadata *models      = job->args->data[2];
+    psRegion *region        = job->args->data[3];
+    int psfSize             = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType markVal = PS_SCALAR_VALUE(job->args->data[6],PS_TYPE_IMAGE_MASK_DATA);
+
+    // Define source fitting parameters for extended source fits
+    pmSourceFitOptions *fitOptions = pmSourceFitOptionsAlloc();
+    fitOptions->mode          = PM_SOURCE_FIT_EXT;
+    // XXX for now, use the defaults for the rest:
+    // fitOptions->nIter         = fitIter;
+    // fitOptions->tol           = fitTol;
+    // fitOptions->poissonErrors = poisson;
+    // fitOptions->weight        = PS_SQR(skySig);
 
     // choose the sources of interest
@@ -140,8 +253,8 @@
 
         // XXX this should use peak?
-        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;
+        if (source->peak->x < region->x0) continue;
+        if (source->peak->y < region->y0) continue;
+        if (source->peak->x > region->x1) continue;
+        if (source->peak->y > region->y1) continue;
 
         // if model is NULL, we don't have a starting guess
@@ -155,7 +268,36 @@
         Next ++;
 
+	// set the radius based on the footprint (also sets the mask pixels)
+	if (!psphotSetRadiusFootprint(&radius, readout, source, markVal, 1.0)) {
+	    fprintf (stderr, "skipping (1) %f, %f\n", source->peak->xf, source->peak->yf);
+	    psFree (fitOptions)
+	    return false;
+	}
+
+	// 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
+	// this uses the footprint to judge both radius and aperture?
+	// XXX save the psf-based moments for output
+	if (!pmSourceMoments (source, radius, 0.0, 0.0, maskVal)) {
+	    fprintf (stderr, "skipping (2) %f, %f\n", source->peak->xf, source->peak->yf);
+	    // subtract the best fit from the object, leave local sky
+	    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+	    // XXX raise an error of some kind
+	    continue;
+	}
+
         // save the modelFlux here in case we need to subtract it (for failure)
         psImage *modelFluxStart = psMemIncrRefCounter (source->modelFlux);
-
+	if (!modelFluxStart) {
+	    pmSourceCacheModel (source, maskVal);
+	    modelFluxStart = psMemIncrRefCounter (source->modelFlux);
+	    if (!modelFluxStart) {
+		fprintf (stderr, "skipping (3) %f, %f\n", source->peak->xf, source->peak->yf);
+		// XXX raise an error of some kind?
+		continue;
+	    }
+	}
+	
         if (savePics) {
           psphotSaveImage (NULL, readout->image, "image.xp.fits");
@@ -183,4 +325,6 @@
           assert (status);
 
+	  // fprintf (stderr, "xfit: %f, %f : %f\n", source->peak->xf, source->peak->yf, source->peak->SN); 
+
           // limit selection to some SN limit
           assert (source->peak); // how can a source not have a peak?
@@ -201,5 +345,5 @@
           pmModel *modelFit = NULL;
           if (convolved) {
-              modelFit = psphotPSFConvModel (readout, source, modelType, maskVal, markVal, psfSize);
+              modelFit = psphotFitPCM (readout, source, fitOptions, modelType, maskVal, markVal, psfSize);
               if (!modelFit) {
                   psTrace ("psphot", 5, "failed to fit psf-conv model for object at %f, %f", source->moments->Mx, source->moments->My);
@@ -215,5 +359,5 @@
               psFree (source->modelFlux);
               source->modelFlux = NULL;
-              modelFit = psphotFitEXT (readout, source, modelType, maskVal, markVal);
+              modelFit = psphotFitEXT (readout, source, fitOptions, modelType, maskVal, markVal);
               if (!modelFit) {
                   psTrace ("psphot", 5, "failed to fit plain model for object at %f, %f", source->moments->Mx, source->moments->My);
@@ -233,4 +377,5 @@
 
           // test for fit quality / result
+	  modelFit->fitRadius = radius;
           psArrayAdd (source->modelFits, 4, modelFit);
 
@@ -311,8 +456,24 @@
         }
     }
-
-    psLogMsg ("psphot", PS_LOG_INFO, "extended source analysis: %f sec for %d objects\n", psTimerMark ("psphot"), Next);
-    psLogMsg ("psphot", PS_LOG_INFO, "  %d convolved models (%d passed)\n", Nconvolve, NconvolvePass);
-    psLogMsg ("psphot", PS_LOG_INFO, "  %d plain models (%d passed)\n", Nplain, NplainPass);
+    psFree (fitOptions);
+
+    // fprintf (stderr, "xfit : tried %ld objects\n", sources->n);
+
+    // change the value of a scalar on the array (wrap this and put it in psArray.h)
+    scalar = job->args->data[7];
+    scalar->data.S32 = Next;
+
+    scalar = job->args->data[8];
+    scalar->data.S32 = Nconvolve;
+
+    scalar = job->args->data[9];
+    scalar->data.S32 = NconvolvePass;
+
+    scalar = job->args->data[10];
+    scalar->data.S32 = Nplain;
+
+    scalar = job->args->data[11];
+    scalar->data.S32 = NplainPass;
+
     return true;
 }
Index: /branches/sc_branches/trunkTest/psphot/src/psphotFindDetections.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotFindDetections.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotFindDetections.c	(revision 29060)
@@ -90,10 +90,6 @@
     psphotVisualShowSignificance (significance, -1.0, PS_SQR(3.0*NSIGMA_PEAK));
 
-    // XXX getting some strange results from significance image
-    if (0) {
-	psImage *lsig = (psImage *) psUnaryOp (NULL, significance, "log");
-	psphotVisualShowSignificance (lsig, 0.0, 4.0);
-	psFree (lsig);
-    }	
+    // display the log significance image
+    psphotVisualShowLogSignificance (significance, 0.0, 4.5);
 
     // detect the peaks in the significance image
Index: /branches/sc_branches/trunkTest/psphot/src/psphotFitSet.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotFitSet.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotFitSet.c	(revision 29060)
@@ -24,6 +24,15 @@
     }
 
+    // Define source fitting parameters for extended source fits
+    pmSourceFitOptions *fitOptions = pmSourceFitOptionsAlloc();
+    fitOptions->mode          = PM_SOURCE_FIT_EXT;
+    // XXX for now, use the defaults for the rest:
+    // fitOptions->nIter         = fitIter;
+    // fitOptions->tol           = fitTol;
+    // fitOptions->poissonErrors = poisson;
+    // fitOptions->weight        = PS_SQR(skySig);
+
     // XXX pmSourceFitSet must cache the modelFlux?
-    pmSourceFitSet (source, modelSet, mode, maskVal);
+    pmSourceFitSet (source, modelSet, fitOptions, maskVal);
 
     // write out positive object
Index: /branches/sc_branches/trunkTest/psphot/src/psphotFitSourcesLinear.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotFitSourcesLinear.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotFitSourcesLinear.c	(revision 29060)
@@ -100,4 +100,13 @@
     if (!status) {
         SKY_FIT_LINEAR = false;
+    }
+    
+    float MIN_VALID_FLUX = psMetadataLookupF32(&status, recipe, "PSF_FIT_MIN_VALID_FLUX");
+    if (!status) {
+        MIN_VALID_FLUX = 1e-8;
+    }
+    float MAX_VALID_FLUX = psMetadataLookupF32(&status, recipe, "PSF_FIT_MAX_VALID_FLUX");
+    if (!status) {
+        MAX_VALID_FLUX = 1e+8;
     }
 
@@ -228,7 +237,7 @@
 
     psSparseConstraint constraint;
-    constraint.paramMin   = 0.0;
-    constraint.paramMax   = 1e8;
-    constraint.paramDelta = 1e8;
+    constraint.paramMin   = MIN_VALID_FLUX;
+    constraint.paramMax   = MAX_VALID_FLUX;
+    constraint.paramDelta = 1e7;
 
     // solve for normalization terms (need include local sky?)
Index: /branches/sc_branches/trunkTest/psphot/src/psphotFitSourcesLinearStack.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotFitSourcesLinearStack.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotFitSourcesLinearStack.c	(revision 29060)
@@ -170,17 +170,2 @@
     return true;
 }
-
-// sort by X (ascending)
-int pmPhotObjSortByX (const void **a, const void **b)
-{
-    pmPhotObj *objA = *(pmPhotObj **)a;
-    pmPhotObj *objB = *(pmPhotObj **)b;
-
-    psF32 fA = objA->x;
-    psF32 fB = objB->x;
-
-    psF32 diff = fA - fB;
-    if (diff > FLT_EPSILON) return (+1);
-    if (diff < FLT_EPSILON) return (-1);
-    return (0);
-}
Index: /branches/sc_branches/trunkTest/psphot/src/psphotGuessModels.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotGuessModels.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotGuessModels.c	(revision 29060)
@@ -80,5 +80,5 @@
 
     // setup the PSF fit radius details
-    psphotInitRadiusPSF (recipe, readout->analysis, psf->type);
+    psphotInitRadiusPSF (recipe, readout);
 
     // choose Cx, Cy (see psphotThreadTools.c for overview of the concepts)
Index: /branches/sc_branches/trunkTest/psphot/src/psphotLoadSRCTEXT.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotLoadSRCTEXT.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotLoadSRCTEXT.c	(revision 29060)
@@ -84,5 +84,6 @@
 	    source->peak->yf   = PAR[PM_PAR_YPOS]; // but we know the pixel coordinate
 
-	    source->pixWeight = 1.0;
+	    source->pixWeightNotBad = 1.0;
+	    source->pixWeightNotPoor = 1.0;
 	    source->crNsigma  = 0.0;
 	    source->extNsigma = 0.0;
Index: /branches/sc_branches/trunkTest/psphot/src/psphotMagnitudes.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotMagnitudes.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotMagnitudes.c	(revision 29060)
@@ -124,13 +124,4 @@
                 return false;
             }
-
-# if (0)
-                int nap = 0;
-                if (!psphotMagnitudes_Unthreaded (&nap, cells->data[j], psf, binning, backModel, backStdev, photMode, maskVal)) {
-                    psError(PS_ERR_UNKNOWN, false, "Unable to guess model.");
-                    return false;
-                }
-                Nap += nap;
-# endif
         }
 
@@ -186,5 +177,5 @@
         psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, source->apRadius, "OR", markVal);
 
-        status = pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
+        status = pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
         if (status && isfinite(source->apMag)) Nap ++;
 
@@ -268,4 +259,5 @@
             psArrayAdd(job->args, 1, cells->data[j]); // sources
             PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
+            PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
 
             if (!psThreadJobAddPending(job)) {
@@ -304,4 +296,5 @@
     psArray *sources                = job->args->data[0];
     psImageMaskType maskVal         = PS_SCALAR_VALUE(job->args->data[1],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType markVal         = PS_SCALAR_VALUE(job->args->data[2],PS_TYPE_IMAGE_MASK_DATA);
 
     for (int i = 0; i < sources->n; i++) {
@@ -312,12 +305,14 @@
         if (model == NULL) {
           psTrace ("psphot", 3, "fail mag : no valid model");
-          source->pixWeight = NAN;
+          source->pixWeightNotBad = NAN;
+          source->pixWeightNotPoor = NAN;
           continue;
         }
 
-        status = pmSourcePixelWeight (&source->pixWeight, model, source->maskObj, maskVal);
+        status = pmSourcePixelWeight (&source->pixWeightNotBad, &source->pixWeightNotPoor, model, source->maskObj, maskVal, markVal);
         if (!status) {
           psTrace ("psphot", 3, "fail to measure pixel weight");
-          source->pixWeight = NAN;
+          source->pixWeightNotBad = NAN;
+          source->pixWeightNotPoor = NAN;
           continue;
         }
Index: /branches/sc_branches/trunkTest/psphot/src/psphotModelWithPSF.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotModelWithPSF.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotModelWithPSF.c	(revision 29060)
@@ -73,7 +73,7 @@
 
     // iterate until the tolerance is reached, or give up
-    while ((min->iter < min->maxIter) && ((min->lastDelta > min->tol) || !isfinite(min->lastDelta))) {
+    while ((min->iter < min->maxIter) && ((min->lastDelta > min->minTol) || !isfinite(min->lastDelta))) {
         psTrace("psphot", 5, "Iteration number %d.  (max iterations is %d).\n", min->iter, min->maxIter);
-        psTrace("psphot", 5, "Last delta is %f.  Min->tol is %f.\n", min->lastDelta, min->tol);
+        psTrace("psphot", 5, "Last delta is %f.  Min->minTol is %f.\n", min->lastDelta, min->minTol);
 
 
@@ -166,11 +166,11 @@
     psFree(pcm);
 
-    if (min->iter == min->maxIter) {
-        psTrace("psphot", 3, "---- end (false) ----\n");
-        return(false);
-    }
-
-    psTrace("psphot", 3, "---- end (true) ----\n");
-    return(true);
+    // if the last improvement was at least as good as maxTol, accept the fit:
+    if (min->lastDelta <= min->maxTol) {
+	psTrace("psphot", 6, "---- end (true) ----\n");
+        return(true);
+    }
+    psTrace("psphot", 6, "---- end (false) ----\n");
+    return(false);
 }
 
Index: /branches/sc_branches/trunkTest/psphot/src/psphotPSFConvModel.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotPSFConvModel.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotPSFConvModel.c	(revision 29060)
@@ -4,10 +4,14 @@
 // save as static values so they may be set externally
 static psF32 PM_SOURCE_FIT_MODEL_NUM_ITERATIONS = 15;
-static psF32 PM_SOURCE_FIT_MODEL_TOLERANCE = 0.1;
+static psF32 PM_SOURCE_FIT_MODEL_MIN_TOL = 0.1;
+static psF32 PM_SOURCE_FIT_MODEL_MAX_TOL = 2.0;
 
 // input source has both modelPSF and modelEXT.  on successful exit, we set the
 // modelConv to contain the fitted parameters, and the modelFlux to contain the 
 // convolved model image.
-pmModel *psphotPSFConvModel (pmReadout *readout, pmSource *source, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
+
+// XXX need to generalize this -- number of fitted parameters must be flexible based on the fitOptions
+
+pmModel *psphotPSFConvModel (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
     
     // maskVal is used to test for rejected pixels, and must include markVal
@@ -90,5 +94,5 @@
 
     // set up the minimization process
-    psMinimization *myMin = psMinimizationAlloc (PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, PM_SOURCE_FIT_MODEL_TOLERANCE);
+    psMinimization *myMin = psMinimizationAlloc (PM_SOURCE_FIT_MODEL_NUM_ITERATIONS, PM_SOURCE_FIT_MODEL_MIN_TOL, PM_SOURCE_FIT_MODEL_MAX_TOL);
 
     psImage *covar = psImageAlloc (params->n, params->n, PS_TYPE_F32);
Index: /branches/sc_branches/trunkTest/psphot/src/psphotPetrosianVisual.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotPetrosianVisual.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotPetrosianVisual.c	(revision 29060)
@@ -1,4 +1,3 @@
 # include "psphotInternal.h"
-# define FORCE_VISUAL 0
 
 // this function displays representative images as the psphot analysis progresses:
@@ -54,6 +53,5 @@
     Graphdata graphdata;
 
-    // return true;
-    if (!FORCE_VISUAL && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.petro.byangle", 2)) return true;
 
     if (kapa2 == -1) {
@@ -101,6 +99,5 @@
     Graphdata graphdata;
 
-    // return true;
-    if (!FORCE_VISUAL && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.petro.radii", 2)) return true;
 
     if (kapa == -1) {
@@ -173,5 +170,5 @@
     KapaSection section;
 
-    if (!FORCE_VISUAL && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.petro.stats", 2)) return true;
 
     if (kapa2 == -1) {
@@ -311,5 +308,5 @@
     Graphdata graphdata;
 
-    if (!FORCE_VISUAL && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.petro.ellipse", 2)) return true;
 
     if (kapa == -1) {
Index: /branches/sc_branches/trunkTest/psphot/src/psphotRadiusChecks.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotRadiusChecks.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotRadiusChecks.c	(revision 29060)
@@ -8,5 +8,5 @@
                                         // and a per-object radius is calculated)
 
-bool psphotInitRadiusPSF(const psMetadata *recipe, const psMetadata *analysis, const pmModelType type) {
+bool psphotInitRadiusPSF(psMetadata *recipe, pmReadout *readout) {
 
     bool status = true;
@@ -15,10 +15,10 @@
     PSF_FIT_PADDING = psMetadataLookupF32(&status, recipe, "PSF_FIT_PADDING");
 
-    PSF_FIT_RADIUS =  psMetadataLookupF32(&status, analysis, "PSF_FIT_RADIUS");
+    PSF_FIT_RADIUS =  psMetadataLookupF32(&status, readout->analysis, "PSF_FIT_RADIUS");
     if (!status) {
         PSF_FIT_RADIUS = psMetadataLookupF32(&status, recipe, "PSF_FIT_RADIUS");
     }
 
-    PSF_APERTURE =  psMetadataLookupF32(&status, analysis, "PSF_APERTURE");
+    PSF_APERTURE =  psMetadataLookupF32(&status, readout->analysis, "PSF_APERTURE");
     if (!status) {
         PSF_APERTURE =  psMetadataLookupF32(&status, recipe, "PSF_APERTURE");
@@ -28,5 +28,5 @@
 
     if (PSF_FIT_RADIUS == 0.0) {
-        float gaussSigma = psMetadataLookupF32(&status, analysis, "MOMENTS_GAUSS_SIGMA");
+        float gaussSigma = psMetadataLookupF32(&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
         if (!status) {
             gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
@@ -37,5 +37,5 @@
 
     if (PSF_APERTURE == 0.0) {
-        float gaussSigma = psMetadataLookupF32(&status, analysis, "MOMENTS_GAUSS_SIGMA");
+        float gaussSigma = psMetadataLookupF32(&status, readout->analysis, "MOMENTS_GAUSS_SIGMA");
         if (!status) {
             gaussSigma = psMetadataLookupF32(&status, recipe, "MOMENTS_GAUSS_SIGMA");
@@ -122,9 +122,10 @@
 }
 
+static float EXT_FIT_SKY_SIG;
 static float EXT_FIT_NSIGMA;
 static float EXT_FIT_PADDING;
 static float EXT_FIT_MAX_RADIUS;
 
-bool psphotInitRadiusEXT (psMetadata *recipe, pmModelType type) {
+bool psphotInitRadiusEXT (psMetadata *recipe, pmReadout *readout) {
 
     bool status;
@@ -134,9 +135,16 @@
     EXT_FIT_MAX_RADIUS = psMetadataLookupF32 (&status, recipe, "EXT_FIT_MAX_RADIUS");
 
+    float skyMean  = psMetadataLookupF32 (&status, readout->analysis, "SKY_MEAN");
+    float skyStdev = psMetadataLookupF32 (&status, readout->analysis, "SKY_STDEV");
+
+    fprintf (stderr, "sky: %f +/- %f\n", skyMean, skyStdev);
+
+    EXT_FIT_SKY_SIG = skyStdev;
+
     return true;
 }
 
 // call this function whenever you (re)-define the EXT model
-float psphotSetRadiusEXT (pmReadout *readout, pmSource *source, psImageMaskType markVal) {
+bool psphotSetRadiusFootprint (float *radius, pmReadout *readout, pmSource *source, psImageMaskType markVal, float factor) {
 
     psAssert (source, "source not defined??");
@@ -146,11 +154,11 @@
 
     // set the radius based on the footprint:
-    if (!peak->footprint) goto escape;
+    if (!peak->footprint) return false;
     pmFootprint *footprint = peak->footprint;
-    if (!footprint->spans) goto escape;
-    if (footprint->spans->n < 1) goto escape;
+    if (!footprint->spans) return false;
+    if (footprint->spans->n < 1) return false;
 
     // find the max radius
-    float radius = 0.0;
+    float rawRadius = 0.0;
     for (int j = 0; j < footprint->spans->n; j++) {
         pmSpan *span = footprint->spans->data[j];
@@ -160,30 +168,22 @@
         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);
+        rawRadius = PS_MAX (rawRadius, hypot(dY, dX0));
+        rawRadius = PS_MAX (rawRadius, hypot(dY, dX1));
+    }
+    if (isnan(rawRadius)) return false;
+    rawRadius = PS_MIN (factor*rawRadius + EXT_FIT_PADDING, 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;
+    pmSourceRedefinePixels (source, readout, peak->xf, peak->yf, rawRadius);
+
+    // set the mask to flag the excluded pixels
+    psImageKeepCircle (source->maskObj, peak->xf, peak->yf, rawRadius, "OR", markVal);
+
+    *radius = rawRadius;
+    return true;
 }
 
 // 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");
+bool psphotSetRadiusModel (pmModel *model, pmReadout *readout, pmSource *source, psImageMaskType markVal, bool deep) {
 
     psF32 *PAR = model->params->data.F32;
@@ -193,14 +193,17 @@
 
     // set the fit radius based on the object flux limit and the model
-    float rawRadius = model->modelRadius (model->params, EXT_FIT_NSIGMA*moments->dSky);
-
-    model->fitRadius = rawRadius + EXT_FIT_PADDING;
-    if (isnan(model->fitRadius)) psAbort("error in radius");
+    float flux = deep ? EXT_FIT_NSIGMA*EXT_FIT_SKY_SIG : 0.1 * model->params->data.F32[PM_PAR_I0];
+
+    float rawRadius = model->modelRadius (model->params, flux);
+    if (isnan(rawRadius)) return false;
+
+    rawRadius = PS_MIN (rawRadius + EXT_FIT_PADDING, EXT_FIT_MAX_RADIUS);
+    model->fitRadius = rawRadius;
 
     // redefine the pixels if needed
-    bool status = pmSourceRedefinePixels (source, readout, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->fitRadius);
+    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->fitRadius, "OR", markVal);
-    return status;
-}
+    return true;
+}
Index: /branches/sc_branches/trunkTest/psphot/src/psphotReadout.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotReadout.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotReadout.c	(revision 29060)
@@ -53,6 +53,7 @@
     }
 
-    // load the psf model, if suppled.  FWHM_X,FWHM_Y,etc are determined and saved on
-    // readout->analysis XXX this function currently only works with a single PSPHOT.INPUT
+    // load the psf model, if suppled.  FWHM_MAJ,FWHM_MIN,etc are determined and saved on
+    // readout->analysis. XXX Note: this function currently only works with a single
+    // PSPHOT.INPUT
     if (!psphotLoadPSF (config, view)) { // ??? need to supply 2 ?
         psError (PSPHOT_ERR_UNKNOWN, false, "error loading psf model");
Index: /branches/sc_branches/trunkTest/psphot/src/psphotSetThreads.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotSetThreads.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotSetThreads.c	(revision 29060)
@@ -15,5 +15,5 @@
     psFree(task);
 
-    task = psThreadTaskAlloc("PSPHOT_PSF_WEIGHTS", 2);
+    task = psThreadTaskAlloc("PSPHOT_PSF_WEIGHTS", 3);
     task->function = &psphotPSFWeights_Threaded;
     psThreadTaskAdd(task);
@@ -30,6 +30,11 @@
     psFree(task);
 
-    task = psThreadTaskAlloc("PSPHOT_BLEND_FIT", 9);
+    task = psThreadTaskAlloc("PSPHOT_BLEND_FIT", 10);
     task->function = &psphotBlendFit_Threaded;
+    psThreadTaskAdd(task);
+    psFree(task);
+
+    task = psThreadTaskAlloc("PSPHOT_EXTENDED_FIT", 12);
+    task->function = &psphotExtendedSourceFits_Threaded;
     psThreadTaskAdd(task);
     psFree(task);
Index: /branches/sc_branches/trunkTest/psphot/src/psphotSignificanceImage.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotSignificanceImage.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotSignificanceImage.c	(revision 29060)
@@ -97,5 +97,6 @@
                 smooth_im->data.F32[j][i] = 0.0;
             } else {
-                smooth_im->data.F32[j][i] = factor * PS_SQR(value) / smooth_wt->data.F32[j][i];
+		float v2 = value + PS_SQR(value/1000.0);
+                smooth_im->data.F32[j][i] = factor * PS_SQR(v2) / smooth_wt->data.F32[j][i];
             }
         }
Index: /branches/sc_branches/trunkTest/psphot/src/psphotSourceFits.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotSourceFits.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotSourceFits.c	(revision 29060)
@@ -2,5 +2,4 @@
 
 // given a source with an existing modelPSF, attempt a full PSF fit, subtract if successful
-// XXX this function does not call pmSourceFitModelInit : fix this?
 
 static int NfitPSF = 0;
@@ -8,4 +7,5 @@
 static int NfitDBL = 0;
 static int NfitEXT = 0;
+static int NfitPCM = 0;
 
 bool psphotFitInit (int nThreads) {
@@ -18,11 +18,13 @@
 
     psLogMsg ("psphot.pspsf", PS_LOG_INFO, "fitted %5d psf, %5d blend, %5d ext, %5d dbl : %6.2f sec\n",
-             NfitPSF, NfitBlend, NfitEXT, NfitDBL, psTimerMark ("psphot.fits"));
-    return true;
-}
-
-bool psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal) {
+	      NfitPSF, NfitBlend, NfitEXT, NfitDBL, psTimerMark ("psphot.fits"));
+    return true;
+}
+
+bool psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
 
     float x, y, dR;
+
+    pmSourceFitOptions options = *fitOptions;
 
     // maskVal is used to test for rejected pixels, and must include markVal
@@ -31,5 +33,5 @@
     // if this source is not a possible blend, just fit as PSF
     if ((source->blends == NULL) || (source->mode & PM_SOURCE_MODE_SATSTAR)) {
-        bool status = psphotFitPSF (readout, source, psf, maskVal, markVal);
+        bool status = psphotFitPSF (readout, source, psf, fitOptions, maskVal, markVal);
         return status;
     }
@@ -91,5 +93,6 @@
 
     // fit PSF model
-    pmSourceFitSet (source, modelSet, PM_SOURCE_FIT_PSF, maskVal);
+    options.mode = PM_SOURCE_FIT_PSF;
+    pmSourceFitSet (source, modelSet, &options, maskVal);
 
     // clear the circular mask
@@ -154,7 +157,8 @@
 }
 
-bool psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal) {
+bool psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
 
     double chiTrend;
+    pmSourceFitOptions options = *fitOptions;
 
     // maskVal is used to test for rejected pixels, and must include markVal
@@ -171,5 +175,6 @@
 
     // fit PSF model (set/unset the pixel mask)
-    pmSourceFitModel (source, PSF, PM_SOURCE_FIT_PSF, maskVal);
+    options.mode = PM_SOURCE_FIT_PSF;
+    pmSourceFitModel (source, PSF, &options, maskVal);
 
     if (!isfinite(PSF->params->data.F32[PM_PAR_I0])) psAbort("nan in fit");
@@ -199,7 +204,8 @@
 }
 
+// save a local, static copy of the EXT model type so we don't have to lookup for each object
 static pmModelType modelTypeEXT;
 
-bool psphotInitLimitsEXT (psMetadata *recipe) {
+bool psphotInitLimitsEXT (psMetadata *recipe, pmReadout *readout) {
 
     bool status;
@@ -208,11 +214,13 @@
     char *modelNameEXT = psMetadataLookupStr (&status, recipe, "EXT_MODEL");
     modelTypeEXT = pmModelClassGetType (modelNameEXT);
-    psphotInitRadiusEXT (recipe, modelTypeEXT);
-
-    return true;
-}
-
-bool psphotFitBlob (pmReadout *readout, pmSource *source, psArray *newSources, pmPSF *psf, psImageMaskType maskVal, psImageMaskType markVal) {
-
+
+    psphotInitRadiusEXT (recipe, readout);
+
+    return true;
+}
+
+bool psphotFitBlob (pmReadout *readout, pmSource *source, psArray *newSources, pmPSF *psf, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
+
+    float radius;
     bool okEXT, okDBL;
     float chiEXT, chiDBL;
@@ -222,6 +230,8 @@
     pmModel *EXT = NULL;
     psArray *DBL = NULL;
+    pmMoments psfMoments;
 
     // skip the source if we don't think it is extended
+    // XXX are these robust, or do we have better info from the source-size analysis??
     if (source->type == PM_SOURCE_TYPE_UNKNOWN) return false;
     if (source->type == PM_SOURCE_TYPE_DEFECT) return false;
@@ -229,11 +239,17 @@
 
     // set the radius based on the footprint (also sets the mask pixels)
-    float radius = psphotSetRadiusEXT (readout, source, markVal);
+    if (!psphotSetRadiusFootprint(&radius, readout, source, markVal, 1.0)) return false;
 
     // XXX note that this changes the source moments that are published...
+    // XXX all published moments should use the same measurement
     // 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
     // this uses the footprint to judge both radius and aperture?
-    if (!pmSourceMoments (source, radius, 0.0, 0.0, maskVal)) return false;
+    // XXX save the psf-based moments for output
+    psfMoments = *source->moments;
+    if (!pmSourceMoments (source, radius, 0.0, 0.5, maskVal)) {
+      *source->moments = psfMoments;
+      return false;
+    }
 
     psTrace ("psphot", 5, "trying blob...\n");
@@ -244,42 +260,47 @@
     // this temporary source is used as a place-holder by the psphotEval functions below
     tmpSrc = pmSourceAlloc ();
-
-    // XXX need to handle failures better here
-    EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal, markVal);
-    if (!EXT) goto escape;
-    if (!isfinite(EXT->params->data.F32[PM_PAR_I0])) goto escape;
-
-    okEXT = psphotEvalEXT (tmpSrc, EXT);
-    chiEXT = EXT ? EXT->chisq / EXT->nDOF : NAN;
-
-    // DBL will always be defined, but DBL->data[n] might not
-    DBL = psphotFitDBL (readout, source, maskVal, markVal);
-    if (!DBL) goto escape;
-    if (!DBL->n) goto escape;
-
-    okDBL  = psphotEvalDBL (tmpSrc, DBL->data[0]);
-    okDBL &= psphotEvalDBL (tmpSrc, DBL->data[1]);
-    // XXX should I keep / save the flags set in the eval functions?
+    {
+	// DBL will always be defined, but DBL->data[n] might not
+	DBL = psphotFitDBL (readout, source, fitOptions, maskVal, markVal);
+	if (!DBL) goto escape;
+	if (!DBL->n) goto escape;
+
+	okDBL  = psphotEvalDBL (tmpSrc, DBL->data[0]);
+	okDBL &= psphotEvalDBL (tmpSrc, DBL->data[1]);
+	// XXX should I keep / save the flags set in the eval functions?
+
+	// 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;
+	    chiDBL = ONE->chisq / ONE->nDOF; // save chisq for double-star/galaxy comparison
+	    ONE->fitRadius = radius;
+	}
+
+	// correct second model chisqs for flux trend
+	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;
+	    ONE->fitRadius = radius;
+	}
+    }
+
+    { 
+	// XXX need to handle failures better here
+	EXT = psphotFitEXT (readout, source, fitOptions, modelTypeEXT, maskVal, markVal);
+	if (!EXT) goto escape;
+	if (!isfinite(EXT->params->data.F32[PM_PAR_I0])) goto escape;
+
+	okEXT = psphotEvalEXT (tmpSrc, EXT);
+	chiEXT = EXT ? EXT->chisq / EXT->nDOF : NAN;
+    }
 
     // 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;
-      chiDBL = ONE->chisq / ONE->nDOF; // save chisq for double-star/galaxy comparison
-    }
-
-    // correct second model chisqs for flux trend
-    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;
-    }
 
     psFree (tmpSrc);
@@ -298,5 +319,8 @@
 
     // both models failed; reject them both
-    // XXX -- change type flags to psf in this case and keep original moments?
+    // XXX -- change type flags to psf in this case, and make sure we subtract it?
+    // reset the psf moments
+    *source->moments = psfMoments;
+
     psFree (EXT);
     psFree (DBL);
@@ -308,6 +332,6 @@
 
     // save new model
+    // XXX save the correct radius...
     source->modelEXT = EXT;
-    source->modelEXT->fitRadius = radius;
     source->type = PM_SOURCE_TYPE_EXTENDED;
     source->mode |= PM_SOURCE_MODE_EXTMODEL;
@@ -327,4 +351,6 @@
 # endif
 
+    // reset the psf moments
+    *source->moments = psfMoments;
     return true;
 
@@ -337,10 +363,8 @@
     source->modelPSF = psMemIncrRefCounter (DBL->data[0]);
     source->mode     |= PM_SOURCE_MODE_PAIR;
-    source->modelPSF->fitRadius = radius;
 
     // copy most data from the primary source (modelEXT, blends stay NULL)
-    pmSource *newSrc = pmSourceCopy (source);
+    pmSource *newSrc = pmSourceCopyData (source);
     newSrc->modelPSF = psMemIncrRefCounter (DBL->data[1]);
-    newSrc->modelPSF->fitRadius = radius;
 
     // build cached models and subtract
@@ -365,4 +389,8 @@
 # endif
 
+    // reset the (original) psf moments
+    *source->moments = psfMoments;
+    *newSrc->moments = psfMoments;
+
     psArrayAdd (newSources, 100, newSrc);
     psFree (newSrc);
@@ -371,4 +399,6 @@
 
 escape:
+    // reset the psf moments
+    *source->moments = psfMoments;
     psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); 
     psFree (tmpSrc);
@@ -379,5 +409,5 @@
 
 // fit a double PSF source to an extended blob
-psArray *psphotFitDBL (pmReadout *readout, pmSource *source, psImageMaskType maskVal, psImageMaskType markVal) {
+psArray *psphotFitDBL (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
 
     float dx, dy;
@@ -387,4 +417,6 @@
     psEllipseMoments moments;
     psArray *modelSet;
+
+    pmSourceFitOptions options = *fitOptions;
 
     NfitDBL ++;
@@ -403,4 +435,8 @@
     axes = psEllipseMomentsToAxes (moments, 20.0);
 
+    if (isnan(axes.major)) return NULL;
+    if (isnan(axes.minor)) return NULL;
+    if (isnan(axes.theta)) return NULL;
+
     // XXX this is really arbitrary: 4 pixel separation?
     dx = 2 * cos (axes.theta);
@@ -426,9 +462,16 @@
 
     // fit PSF model (set/unset the pixel mask)
-    pmSourceFitSet (source, modelSet, PM_SOURCE_FIT_PSF, maskVal);
+    options.mode = PM_SOURCE_FIT_PSF;
+    pmSourceFitSet (source, modelSet, &options, maskVal);
     return (modelSet);
 }
 
-pmModel *psphotFitEXT (pmReadout *readout, pmSource *source, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal) {
+pmModel *psphotFitEXT (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType 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);
+    }
+
+    pmSourceFitOptions options = *fitOptions;
 
     NfitEXT ++;
@@ -438,16 +481,224 @@
 
     // use the source moments, etc to guess basic model parameters
-    pmModel *EXT = pmSourceModelGuess (source, modelType);
-    if (!EXT) {
+    pmModel *model = pmSourceModelGuess (source, modelType);
+    if (!model) {
 	psTrace ("psphot", 5, "failed to generate a model for source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
 	return NULL;
     }
 
+    // for sersic models, use a grid search to choose an index, then float the params there
+    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
+	// for the test fits, use a somewhat smaller radius
+	psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 0.5);
+    	psphotFitSersicIndex (model, readout, source, fitOptions, maskVal, markVal);
+    }
+
+    if (!psphotSetRadiusModel (model, readout, source, markVal, true)) {
+	psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 1.0);
+    }
+
+    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
+	options.mode = PM_SOURCE_FIT_NO_INDEX;
+    } else {
+	options.mode = PM_SOURCE_FIT_EXT;
+    }
+
+    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
+    pmSourceFitModel (source, model, &options, maskVal);
+    // fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
+
+    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
+    return (model);
+}
+
+pmModel *psphotFitPCM (pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, pmModelType modelType, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
+
     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);
     }
 
+    pmSourceFitOptions options = *fitOptions;
+
+    NfitPCM ++;
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
+    // allocate the model
+    pmModel *model = pmModelAlloc(modelType);
+    if (!model) {
+	return NULL;
+    }
+
+    pmPCMdata *pcm = pmPCMinit (source, &options, model, maskVal, psfSize);
+    if (!pcm) {
+	psTrace ("psphot", 5, "failed to generate a model for source: moments: %f %f\n", source->moments->Mxx, source->moments->Myy);
+        model->flags |= PM_MODEL_STATUS_BADARGS; // XXX this is probably already set in pmPCMinit
+	return model;
+    }
+
+    // use the source moments, etc to guess basic model parameters
+    if (!pmSourceModelGuessPCM (pcm, source, maskVal, markVal)) {
+	psFree (pcm);
+        model->flags |= PM_MODEL_STATUS_BADARGS;
+	return model;
+    }
+
+    // for sersic models, use a grid search to choose an index, then float the params there
+    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
+	// for the test fits, use a somewhat smaller radius
+	psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 0.5);
+
+    	if (!psphotFitSersicIndexPCM (pcm, readout, source, fitOptions, maskVal, markVal, psfSize)) {
+	    model->flags |= PM_MODEL_STATUS_BADARGS;
+	    return model;
+	}
+    }
+
+    if (!psphotSetRadiusModel (model, readout, source, markVal, true)) {
+	psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 1.0);
+    }
+
+    if (modelType == pmModelClassGetType("PS_MODEL_SERSIC")) {
+	options.mode = PM_SOURCE_FIT_NO_INDEX;
+    } else {
+	options.mode = PM_SOURCE_FIT_EXT;
+    }
+    // update the pcm elements if we have changed the circumstance (options.mode or source->pixels)
+    pmPCMupdate(pcm, source, &options, model);
+
+    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 5);
+    pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
+    // fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
+
+    // psTraceSetLevel("psLib.math.psMinimizeLMChi2", 0);
+    psFree (pcm);
+
+    return model;
+}
+
+// note that these should be 1/2n of the standard sersic index
+float indexGuess[] = {0.5, 0.33, 0.25, 0.167, 0.125, 0.083};
+# define N_INDEX_GUESS 6
+
+// A sersic model is very sensitive to the index.  attempt to find the index first by grid search in just the index
+// for a sersic model, attempt to fit just the index and normalization with a modest number of iterations
+bool psphotFitSersicIndex (pmModel *model, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal) {
+
+    assert (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
+
+    pmSourceFitOptions options = *fitOptions;
+    
     // fit EXT (not PSF) model (set/unset the pixel mask)
-    pmSourceFitModel (source, EXT, PM_SOURCE_FIT_EXT, maskVal);
-    return (EXT);
-}
+    options.mode = PM_SOURCE_FIT_NO_INDEX;
+    options.nIter = 4;
+
+    int iMin = -1;
+    float xMin = NAN;
+    float chiSquare[N_INDEX_GUESS];
+
+    for (int i = 0; i < N_INDEX_GUESS; i++) {
+	model->params->data.F32[PM_PAR_7] = indexGuess[i];
+
+	if (!model->modelGuess(model, source)) {
+	    model->flags |= PM_MODEL_STATUS_BADARGS;
+	    return false;
+	}
+
+	// each time we change the model guess, we need to adjust the radius
+	// XXX this did not work : we do not need such a large radius -- just uses moments-based radius
+	if (false && !psphotSetRadiusModel (model, readout, source, markVal, false)) {
+	    psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 0.5);
+	}
+	
+	pmSourceFitModel (source, model, &options, maskVal);
+	// fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
+
+	chiSquare[i] = model->chisqNorm;
+	if (i == 0) {
+	    xMin = chiSquare[i];
+	    iMin = i;
+	} else {
+	    if (chiSquare[i] < xMin) {
+		xMin = chiSquare[i];
+		iMin = i;
+	    }
+	}
+    }
+    assert (iMin >= 0);
+
+    model->flags = PM_MODEL_STATUS_NONE; // do not attempt to handle failures here, let the next iteration deal with it
+    model->params->data.F32[PM_PAR_7] = indexGuess[iMin];
+    model->modelGuess(model, source);
+
+    // each time we change the model guess, we need to adjust the radius
+    // if (!psphotSetRadiusModel (model, readout, source, markVal, true)) {
+    // 	psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal);
+    // }
+
+    return true;
+}
+
+// A sersic model is very sensitive to the index.  attempt to find the index first by grid search in just the index
+// for a sersic model, attempt to fit just the index and normalization with a modest number of iterations
+bool psphotFitSersicIndexPCM (pmPCMdata *pcm, pmReadout *readout, pmSource *source, pmSourceFitOptions *fitOptions, psImageMaskType maskVal, psImageMaskType markVal, int psfSize) {
+
+    pmModel *model = pcm->modelConv;
+
+    assert (model->type == pmModelClassGetType("PS_MODEL_SERSIC"));
+
+    pmSourceFitOptions options = *fitOptions;
+    
+    // fit EXT (not PSF) model (set/unset the pixel mask)
+    options.mode = PM_SOURCE_FIT_NO_INDEX;
+    options.nIter = 4;
+
+    // update the pcm elements if we have changed the circumstance (here, options.mode)
+    pmPCMupdate(pcm, source, &options, model);
+
+    int iMin = -1;
+    float xMin = NAN;
+    float chiSquare[N_INDEX_GUESS];
+
+    for (int i = 0; i < N_INDEX_GUESS; i++) {
+	model->params->data.F32[PM_PAR_7] = indexGuess[i];
+	
+	if (!model->modelGuess(model, source)) {
+	    model->flags |= PM_MODEL_STATUS_BADARGS;
+	    return false;
+	}
+
+	// each time we change the model guess, we need to adjust the radius
+	// XXX this did not work : we do not need such a large radius -- just uses moments-based radius
+	if (false && !psphotSetRadiusModel (model, readout, source, markVal, false)) {
+	    psphotSetRadiusFootprint(&model->fitRadius, readout, source, markVal, 0.5);
+	}
+	
+# if (0)
+	pmSourceFitModel (source, model, &options, maskVal);
+# else
+	pmSourceModelGuessPCM(pcm, source, maskVal, markVal);
+	pmSourceFitPCM (pcm, source, &options, maskVal, markVal, psfSize);
+# endif
+	// fprintf (stderr, "chisq: %f, nIter: %d, radius: %f, npix: %d\n", model->chisqNorm, model->nIter, model->fitRadius, model->nPix);
+
+	chiSquare[i] = model->chisq;
+	if (i == 0) {
+	    xMin = chiSquare[i];
+	    iMin = i;
+	} else {
+	    if (chiSquare[i] < xMin) {
+		xMin = chiSquare[i];
+		iMin = i;
+	    }
+	}
+    }
+    assert (iMin >= 0);
+    
+    model->flags = PM_MODEL_STATUS_NONE; // do not attempt to handle failures here, let the next iteration deal with it
+    model->params->data.F32[PM_PAR_7] = indexGuess[iMin];
+
+    pmSourceModelGuessPCM(pcm, source, maskVal, markVal);
+
+    return true;
+}
Index: /branches/sc_branches/trunkTest/psphot/src/psphotSourceSize.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotSourceSize.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotSourceSize.c	(revision 29060)
@@ -1,4 +1,6 @@
 # include "psphotInternal.h"
 # include <gsl/gsl_sf_gamma.h>
+
+# define KRON 1
 
 typedef struct {
@@ -168,4 +170,5 @@
     psVector *ApErr = psVectorAllocEmpty (100, PS_TYPE_F32);
 
+    psImageMaskType markVal = options->markVal;
     psImageMaskType maskVal = options->maskVal | options->markVal;
 
@@ -189,5 +192,5 @@
 
         // XXX can we test if psfMag is set and calculate only if needed?
-        pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
+        pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
 
         // clear the mask bit
@@ -197,5 +200,10 @@
         pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
 
+	// XXX test: switch to kron flux
+# if (KRON)
+        float apMag = -2.5*log10(source->moments->KronFlux);
+# else
         float apMag = -2.5*log10(source->moments->Sum);
+# endif
         float dMag = source->psfMag - apMag;
 
@@ -288,4 +296,5 @@
     pmSourcePhotometryMode photMode = PM_SOURCE_PHOT_WEIGHT;
 
+    psImageMaskType markVal = options->markVal;
     psImageMaskType maskVal = options->maskVal | options->markVal;
 
@@ -335,5 +344,5 @@
 
         // XXX can we test if psfMag is set and calculate only if needed?
-        pmSourceMagnitudes (source, psf, photMode, maskVal); // maskVal includes markVal
+        pmSourceMagnitudes (source, psf, photMode, maskVal, markVal);
 
         // clear the mask bit
@@ -343,16 +352,28 @@
         pmSourceSub (source, PM_MODEL_OP_FULL, options->maskVal);
 
+# if (KRON)
+        float apMag = -2.5*log10(source->moments->KronFlux);
+# else
         float apMag = -2.5*log10(source->moments->Sum);
+# endif
         float dMag = source->psfMag - apMag;
 
         // set nSigma to include both systematic and poisson error terms
         // XXX the 'poisson error' contribution for size is probably wrong...
-        float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, options->ApSysErr);
+	// XXX add in a hard floor on the Ap Sys Err (to be a bit generous)
+        float nSigmaMAG = (dMag - options->ApResid) / hypot(source->errMag, hypot(options->ApSysErr, 0.025));
         float nSigmaMXX = (Mxx - psfClump->X) / hypot(psfClump->dX, psfClump->X*psfClump->X*source->errMag);
         float nSigmaMYY = (Myy - psfClump->Y) / hypot(psfClump->dY, psfClump->Y*psfClump->Y*source->errMag);
 
-        // partially-masked sources are more likely to be mis-measured PSFs
+	// fprintf (stderr, "%f %f : Mxx: %f, Myy: %f, dx: %f, dy: %f, psfMag: %f, apMag: %f, dMag: %f, errMag: %f, nSigmaMag: %f, nSigmaMxx: %f, nSigmaMyy: %f\n", 
+	// source->peak->xf, source->peak->yf, Mxx, Myy, source->peak->xf - source->moments->Mx, source->peak->yf - source->moments->My, 
+	// source->psfMag, apMag, dMag, source->errMag, nSigmaMAG, nSigmaMXX, nSigmaMYY);
+
+        // XXX double check on ths stuff!! partially-masked sources are more likely to be mis-measured PSFs
         float sizeBias = 1.0;
-        if (source->pixWeight < 0.9) {
+        if (source->pixWeightNotBad < 0.9) {
+            sizeBias = 3.0;
+        }
+        if (source->pixWeightNotPoor < 0.9) {
             sizeBias = 3.0;
         }
@@ -389,5 +410,5 @@
         if (isCR) {
             psTrace("psphotSourceClassRegion.CR",4,"CLASS: %g %g %f\t%g %g  %g %g  %g %g\t%g %g\t%g CR\t%g %g\n",
-                    source->peak->xf,source->peak->yf,source->pixWeight,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
+                    source->peak->xf,source->peak->yf,source->pixWeightNotBad,Mxx,Myy,psfClump->X,psfClump->Y,psfClump->dX,psfClump->dY,apMag,dMag,nSigmaMAG,
                     options->nSigmaApResid,sizeBias*options->nSigmaMoments);
             source->mode |= PM_SOURCE_MODE_DEFECT;
Index: /branches/sc_branches/trunkTest/psphot/src/psphotSourceStats.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotSourceStats.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotSourceStats.c	(revision 29060)
@@ -1,3 +1,4 @@
 # include "psphotInternal.h"
+void pmSourceMomentsSetVerbose(bool state);
 
 // convert detections to sources and measure their basic properties (moments, local sky, sky
@@ -369,4 +370,6 @@
     maskVal |= markVal;
 
+    // XXX test : pmSourceMomentsSetVerbose(true);
+
     // threaded measurement of the sources moments
     int Nfail = 0;
@@ -408,4 +411,17 @@
         // measure basic source moments (no S/N clipping on input pixels)
         status = pmSourceMoments (source, RADIUS, SIGMA, 0.0, maskVal);
+	// XXX moments / aperture test:
+	if (0) {
+	    // 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, 4.0*source->moments->Mrf, "OR", markVal);
+	    
+	    float apMag = NAN;
+	    pmSourcePhotometryAper (&apMag, NULL, source->pixels, source->maskObj, maskVal);
+	    fprintf (stderr, "apMag: %f, kronMag: %f\n", apMag, -2.5*log10(source->moments->KronFlux));
+
+	    // clear the mask bit
+	    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal));
+	}	    
         if (status) {
             Nmoments ++;
@@ -502,5 +518,7 @@
         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, analysis, sources);
+	if (pmVisualTestLevel("psphot.moments.full", 2)) {
+	    psphotVisualPlotMoments (recipe, analysis, sources);
+	}
 #endif
 
Index: /branches/sc_branches/trunkTest/psphot/src/psphotStack.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotStack.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotStack.c	(revision 29060)
@@ -24,4 +24,13 @@
         exit (psphotGetExitStatus());
     }
+    // Dump configuration
+    bool mdok;
+    psString dump = psMetadataLookupStr(&mdok, config->arguments, "DUMP_CONFIG"); // File for config
+    if (dump && !pmConfigDump(config, dump)) {
+        psError(psErrorCodeLast(), false, "Unable to dump configuration.");
+        exit (psphotGetExitStatus());
+    }
+
+
 
     psLogMsg ("psphot", 3, "complete psphot run: %f sec\n", psTimerMark ("complete"));
Index: /branches/sc_branches/trunkTest/psphot/src/psphotStackMatchPSFsUtils.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotStackMatchPSFsUtils.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotStackMatchPSFsUtils.c	(revision 29060)
@@ -346,6 +346,6 @@
     if (!fake) goto escape;
 
-    dumpImage(fake, readoutSrc, index, "fake");
-    dumpImage(readoutSrc,  readoutSrc, index, "real");
+    // dumpImage(fake, readoutSrc, index, "fake");
+    // dumpImage(readoutSrc,  readoutSrc, index, "real");
 
     if (threads) pmSubtractionThreadsInit();
@@ -380,6 +380,6 @@
     }
 
-    dumpImage(readoutOut, readoutSrc, index, "conv");
-    dumpImageDiff(readoutOut, fake, readoutSrc, index, "diff");
+    // dumpImage(readoutOut, readoutSrc, index, "conv");
+    // dumpImageDiff(readoutOut, fake, readoutSrc, index, "diff");
 
     psFree(fake);
Index: /branches/sc_branches/trunkTest/psphot/src/psphotVisual.c
===================================================================
--- /branches/sc_branches/trunkTest/psphot/src/psphotVisual.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/psphot/src/psphotVisual.c	(revision 29060)
@@ -66,9 +66,9 @@
     int myKapa = psphotKapaChannel (channel);
     if (!(strcasecmp (overlay, "all"))) {
-      KiiEraseOverlay (myKapa, "red");
-      KiiEraseOverlay (myKapa, "green");
-      KiiEraseOverlay (myKapa, "blue");
-      KiiEraseOverlay (myKapa, "yellow");
-      return true;
+	KiiEraseOverlay (myKapa, "red");
+	KiiEraseOverlay (myKapa, "green");
+	KiiEraseOverlay (myKapa, "blue");
+	KiiEraseOverlay (myKapa, "yellow");
+	return true;
     }
     KiiEraseOverlay (myKapa, overlay);
@@ -182,5 +182,5 @@
 bool psphotVisualShowImage (pmReadout *readout) {
 
-    if (!pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.image", 1)) return true;
 
     int kapa = psphotKapaChannel (1);
@@ -199,5 +199,5 @@
     pmReadout *backgnd;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.image.backgnd", 2)) return true;
 
     int kapa = psphotKapaChannel (1);
@@ -208,7 +208,7 @@
 
     if (file->mode == PM_FPA_MODE_INTERNAL) {
-        backgnd = file->readout;
+	backgnd = file->readout;
     } else {
-        backgnd = pmFPAviewThisReadout (view, file->fpa);
+	backgnd = pmFPAviewThisReadout (view, file->fpa);
     }
 
@@ -222,5 +222,5 @@
 bool psphotVisualShowSignificance (psImage *image, float min, float max) {
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.image.signif", 2)) return true;
 
     int kapa = psphotKapaChannel (1);
@@ -233,4 +233,20 @@
 }
 
+bool psphotVisualShowLogSignificance (psImage *image, float min, float max) {
+
+    if (!pmVisualTestLevel("psphot.image.logsignif", 3)) return true;
+
+    int kapa = psphotKapaChannel (1);
+    if (kapa == -1) return false;
+
+    psImage *lsig = (psImage *) psUnaryOp (NULL, image, "log");
+    psphotVisualRangeImage (kapa, lsig, "log-signif", 2, min, max);
+    psFree (lsig);
+
+    pmVisualAskUser(NULL);
+    return true;
+}
+
+// XXX : requires psphotVisualShowImage
 bool psphotVisualShowPeaks (pmDetections *detections) {
 
@@ -238,5 +254,5 @@
     KiiOverlay *overlay;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.objects.peaks", 1)) return true;
 
     int kapa = psphotKapaChannel (1);
@@ -252,15 +268,15 @@
     for (int i = 0; i < peaks->n; i++) {
 
-        pmPeak *peak = peaks->data[i];
-        if (peak == NULL) continue;
-
-        overlay[Noverlay].type = KII_OVERLAY_BOX;
-        overlay[Noverlay].x = peak->xf;
-        overlay[Noverlay].y = peak->yf;
-        overlay[Noverlay].dx = 2.0;
-        overlay[Noverlay].dy = 2.0;
-        overlay[Noverlay].angle = 0.0;
-        overlay[Noverlay].text = NULL;
-        Noverlay ++;
+	pmPeak *peak = peaks->data[i];
+	if (peak == NULL) continue;
+
+	overlay[Noverlay].type = KII_OVERLAY_BOX;
+	overlay[Noverlay].x = peak->xf;
+	overlay[Noverlay].y = peak->yf;
+	overlay[Noverlay].dx = 2.0;
+	overlay[Noverlay].dy = 2.0;
+	overlay[Noverlay].angle = 0.0;
+	overlay[Noverlay].text = NULL;
+	Noverlay ++;
     }
 
@@ -272,4 +288,5 @@
 }
 
+// XXX : requires psphotVisualShowImage
 bool psphotVisualShowFootprints (pmDetections *detections) {
 
@@ -277,5 +294,5 @@
     KiiOverlay *overlay;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.objects.footprints", 3)) return true;
 
     int kapa = psphotKapaChannel (1);
@@ -292,82 +309,82 @@
     for (int i = 0; i < footprints->n; i++) {
 
-        pmSpan *span = NULL;
-
-        pmFootprint *footprint = footprints->data[i];
-        if (footprint == NULL) continue;
-        if (footprint->spans == NULL) continue;
-        if (footprint->spans->n < 1) continue;
-
-        // 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;
-        overlay[Noverlay].x = span->x0;
-        overlay[Noverlay].y = span->y;
-        overlay[Noverlay].dx = span->x1 - span->x0;
-        overlay[Noverlay].dy = 0;
-        overlay[Noverlay].angle = 0.0;
-        overlay[Noverlay].text = NULL;
-        Noverlay ++;
-        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
-
-        int ys = span->y;
-        int x0s = span->x0;
-        int x1s = span->x1;
-
-        // draw the outer span edges
-        for (int j = 1; j < footprint->spans->n; j++) {
-            pmSpan *span1 = footprint->spans->data[j];
-
-            int ye = span1->y;
-            int x0e = span1->x0;
-            int x1e = span1->x1;
-
-            // we cannot have two discontinuous spans on the top or bottom, right? (no, probably not right)
-            // find all of the spans in this row and generate x0e, x01:
-            for (int k = j + 1; k < footprint->spans->n; k++) {
-                pmSpan *span2 = footprint->spans->data[k];
-                if (span2->y > span1->y) break;
-                x0e = PS_MIN (x0e, span2->x0);
-                x1e = PS_MAX (x1e, span2->x1);
-                j++;
-            }
-
-            overlay[Noverlay].type = KII_OVERLAY_LINE;
-            overlay[Noverlay].x = x0s;
-            overlay[Noverlay].y = ys;
-            overlay[Noverlay].dx = x0e - x0s;
-            overlay[Noverlay].dy = ye - ys;
-            overlay[Noverlay].angle = 0.0;
-            overlay[Noverlay].text = NULL;
-            Noverlay ++;
-            CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
-
-            overlay[Noverlay].type = KII_OVERLAY_LINE;
-            overlay[Noverlay].x = x1s;
-            overlay[Noverlay].y = ys;
-            overlay[Noverlay].dx = x1e - x1s;
-            overlay[Noverlay].dy = ye - ys;
-            overlay[Noverlay].angle = 0.0;
-            overlay[Noverlay].text = NULL;
-            Noverlay ++;
-            CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
-
-            ys = ye;
-            x0s = x0e;
-            x1s = x1e;
-        }
-
-        // draw the bottom
-        span = footprint->spans->data[footprint->spans->n - 1];
-        overlay[Noverlay].type = KII_OVERLAY_LINE;
-        overlay[Noverlay].x = span->x0;
-        overlay[Noverlay].y = span->y;
-        overlay[Noverlay].dx = span->x1 - span->x0;
-        overlay[Noverlay].dy = 0;
-        overlay[Noverlay].angle = 0.0;
-        overlay[Noverlay].text = NULL;
-        Noverlay ++;
-        CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
+	pmSpan *span = NULL;
+
+	pmFootprint *footprint = footprints->data[i];
+	if (footprint == NULL) continue;
+	if (footprint->spans == NULL) continue;
+	if (footprint->spans->n < 1) continue;
+
+	// 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;
+	overlay[Noverlay].x = span->x0;
+	overlay[Noverlay].y = span->y;
+	overlay[Noverlay].dx = span->x1 - span->x0;
+	overlay[Noverlay].dy = 0;
+	overlay[Noverlay].angle = 0.0;
+	overlay[Noverlay].text = NULL;
+	Noverlay ++;
+	CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
+
+	int ys = span->y;
+	int x0s = span->x0;
+	int x1s = span->x1;
+
+	// draw the outer span edges
+	for (int j = 1; j < footprint->spans->n; j++) {
+	    pmSpan *span1 = footprint->spans->data[j];
+
+	    int ye = span1->y;
+	    int x0e = span1->x0;
+	    int x1e = span1->x1;
+
+	    // we cannot have two discontinuous spans on the top or bottom, right? (no, probably not right)
+	    // find all of the spans in this row and generate x0e, x01:
+	    for (int k = j + 1; k < footprint->spans->n; k++) {
+		pmSpan *span2 = footprint->spans->data[k];
+		if (span2->y > span1->y) break;
+		x0e = PS_MIN (x0e, span2->x0);
+		x1e = PS_MAX (x1e, span2->x1);
+		j++;
+	    }
+
+	    overlay[Noverlay].type = KII_OVERLAY_LINE;
+	    overlay[Noverlay].x = x0s;
+	    overlay[Noverlay].y = ys;
+	    overlay[Noverlay].dx = x0e - x0s;
+	    overlay[Noverlay].dy = ye - ys;
+	    overlay[Noverlay].angle = 0.0;
+	    overlay[Noverlay].text = NULL;
+	    Noverlay ++;
+	    CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
+
+	    overlay[Noverlay].type = KII_OVERLAY_LINE;
+	    overlay[Noverlay].x = x1s;
+	    overlay[Noverlay].y = ys;
+	    overlay[Noverlay].dx = x1e - x1s;
+	    overlay[Noverlay].dy = ye - ys;
+	    overlay[Noverlay].angle = 0.0;
+	    overlay[Noverlay].text = NULL;
+	    Noverlay ++;
+	    CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
+
+	    ys = ye;
+	    x0s = x0e;
+	    x1s = x1e;
+	}
+
+	// draw the bottom
+	span = footprint->spans->data[footprint->spans->n - 1];
+	overlay[Noverlay].type = KII_OVERLAY_LINE;
+	overlay[Noverlay].x = span->x0;
+	overlay[Noverlay].y = span->y;
+	overlay[Noverlay].dx = span->x1 - span->x0;
+	overlay[Noverlay].dy = 0;
+	overlay[Noverlay].angle = 0.0;
+	overlay[Noverlay].text = NULL;
+	Noverlay ++;
+	CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     }
 
@@ -379,4 +396,5 @@
 }
 
+// XXX : requires psphotVisualShowImage
 bool psphotVisualShowMoments (psArray *sources) {
 
@@ -387,5 +405,5 @@
     psEllipseAxes axes;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.objects.moments", 2)) return true;
 
     int kapa = psphotKapaChannel (1);
@@ -401,27 +419,27 @@
     for (int i = 0; i < sources->n; i++) {
 
-        pmSource *source = sources->data[i];
-        if (source == NULL) 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.xy = moments->Mxy;
-        emoments.y2 = moments->Myy;
-
-        axes = psEllipseMomentsToAxes (emoments, 20.0);
-
-        overlay[Noverlay].dx = 2.0*axes.major;
-        overlay[Noverlay].dy = 2.0*axes.minor;
-
-        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
-
-        overlay[Noverlay].text = NULL;
-        Noverlay ++;
+	pmSource *source = sources->data[i];
+	if (source == NULL) 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.xy = moments->Mxy;
+	emoments.y2 = moments->Myy;
+
+	axes = psEllipseMomentsToAxes (emoments, 20.0);
+
+	overlay[Noverlay].dx = 2.0*axes.major;
+	overlay[Noverlay].dy = 2.0*axes.minor;
+
+	overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
+
+	overlay[Noverlay].text = NULL;
+	Noverlay ++;
     }
 
@@ -439,5 +457,5 @@
     KapaSection section;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.moments", 1)) return true;
 
     int myKapa = psphotKapaChannel (2);
@@ -456,26 +474,26 @@
     float Ymin = 1000.0, Ymax = 0.0;
     {
-        int nRegions = psMetadataLookupS32 (&status, analysis, "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, analysis, 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 - 4.0*psfdX;
-            float X1 = psfX + 4.0*psfdX;
-            float Y0 = psfY - 4.0*psfdY;
-            float Y1 = psfY + 4.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); }
-        }
+	int nRegions = psMetadataLookupS32 (&status, analysis, "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, analysis, 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 - 4.0*psfdX;
+	    float X1 = psfX + 4.0*psfdX;
+	    float Y0 = psfY - 4.0*psfdY;
+	    float Y1 = psfY + 4.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); }
+	}
     }
     Xmin = PS_MAX(Xmin, -0.1);
@@ -498,21 +516,21 @@
     int nF = 0;
     for (int i = 0; i < sources->n; i++) {
-        pmSource *source = sources->data[i];
-        if (source->moments == NULL)
-            continue;
-
-        xFaint->data.F32[nF] = source->moments->Mxx;
-        yFaint->data.F32[nF] = source->moments->Myy;
-        mFaint->data.F32[nF] = -2.5*log10(source->moments->Sum);
-        nF++;
-
-        // XXX make this a user-defined cutoff
-        if (source->moments->SN < SN_LIM)
-            continue;
-
-        xBright->data.F32[nB] = source->moments->Mxx;
-        yBright->data.F32[nB] = source->moments->Myy;
-        mBright->data.F32[nB] = -2.5*log10(source->moments->Sum);
-        nB++;
+	pmSource *source = sources->data[i];
+	if (source->moments == NULL)
+	    continue;
+
+	xFaint->data.F32[nF] = source->moments->Mxx;
+	yFaint->data.F32[nF] = source->moments->Myy;
+	mFaint->data.F32[nF] = -2.5*log10(source->moments->Sum);
+	nF++;
+
+	// XXX make this a user-defined cutoff
+	if (source->moments->SN < SN_LIM)
+	    continue;
+
+	xBright->data.F32[nB] = source->moments->Mxx;
+	yBright->data.F32[nB] = source->moments->Myy;
+	mBright->data.F32[nB] = -2.5*log10(source->moments->Sum);
+	nB++;
     }
     xFaint->n = nF;
@@ -652,45 +670,45 @@
     // 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, analysis, "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, analysis, 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);
+	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, analysis, "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, analysis, 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);
     }
 
@@ -721,28 +739,28 @@
     for (int i = 0; i < sources->n; i++) {
 
-        pmSource *source = sources->data[i];
-        if (source == NULL) continue;
-
-        if (source->type != type) continue;
-        if (mode && !(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 = 2.0*axes.major;
-        overlay[Noverlay].dy = 2.0*axes.minor;
-        overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
-        overlay[Noverlay].text = NULL;
-        Noverlay ++;
+	pmSource *source = sources->data[i];
+	if (source == NULL) continue;
+
+	if (source->type != type) continue;
+	if (mode && !(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 = 2.0*axes.major;
+	overlay[Noverlay].dy = 2.0*axes.minor;
+	overlay[Noverlay].angle = axes.theta * PS_DEG_RAD;
+	overlay[Noverlay].text = NULL;
+	Noverlay ++;
     }
 
@@ -753,7 +771,8 @@
 }
 
+// XXX : requires psphotVisualShowImage
 bool psphotVisualShowRoughClass (psArray *sources) {
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.objects.size", 3)) return true;
 
     int myKapa = psphotKapaChannel (1);
@@ -776,5 +795,5 @@
 bool psphotVisualShowPSFModel (pmReadout *readout, pmPSF *psf) {
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.psf.model", 1)) return true;
 
     int myKapa = psphotKapaChannel (3);
@@ -797,28 +816,28 @@
     // generate a fake model at each of the 3x3 image grid positions
     for (int x = -2; x <= +2; x ++) {
-        for (int y = -2; y <= +2; y ++) {
-            // use the center of the center pixel of the image
-            float xc = (int)((0.5 + 0.225*x)*readout->image->numCols) + readout->image->col0 + 0.5;
-            float yc = (int)((0.5 + 0.225*y)*readout->image->numRows) + readout->image->row0 + 0.5;
-
-            // assign the x and y coords to the image center
-            // create an object with center intensity of 1000
-            modelRef->params->data.F32[PM_PAR_SKY] = 0;
-            modelRef->params->data.F32[PM_PAR_I0] = 1000;
-            modelRef->params->data.F32[PM_PAR_XPOS] = xc;
-            modelRef->params->data.F32[PM_PAR_YPOS] = yc;
-
-            // create modelPSF from this model
-            pmModel *model = pmModelFromPSF (modelRef, psf);
-            if (!model) continue;
-
-            // place the reference object in the image center
-            // no need to mask the source here
-            // XXX should we measure this for the analytical model only or the full model?
-            pmModelAddWithOffset (psfMosaic, NULL, model, PM_MODEL_OP_FULL | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
-            pmModelAddWithOffset (funMosaic, NULL, model, PM_MODEL_OP_FUNC | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
-            pmModelAddWithOffset (resMosaic, NULL, model, PM_MODEL_OP_RES0 | PM_MODEL_OP_RES1 | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
-            psFree (model);
-        }
+	for (int y = -2; y <= +2; y ++) {
+	    // use the center of the center pixel of the image
+	    float xc = (int)((0.5 + 0.225*x)*readout->image->numCols) + readout->image->col0 + 0.5;
+	    float yc = (int)((0.5 + 0.225*y)*readout->image->numRows) + readout->image->row0 + 0.5;
+
+	    // assign the x and y coords to the image center
+	    // create an object with center intensity of 1000
+	    modelRef->params->data.F32[PM_PAR_SKY] = 0;
+	    modelRef->params->data.F32[PM_PAR_I0] = 1000;
+	    modelRef->params->data.F32[PM_PAR_XPOS] = xc;
+	    modelRef->params->data.F32[PM_PAR_YPOS] = yc;
+
+	    // create modelPSF from this model
+	    pmModel *model = pmModelFromPSF (modelRef, psf);
+	    if (!model) continue;
+
+	    // place the reference object in the image center
+	    // no need to mask the source here
+	    // XXX should we measure this for the analytical model only or the full model?
+	    pmModelAddWithOffset (psfMosaic, NULL, model, PM_MODEL_OP_FULL | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
+	    pmModelAddWithOffset (funMosaic, NULL, model, PM_MODEL_OP_FUNC | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
+	    pmModelAddWithOffset (resMosaic, NULL, model, PM_MODEL_OP_RES0 | PM_MODEL_OP_RES1 | PM_MODEL_OP_CENTER, 0, x*DX, y*DY);
+	    psFree (model);
+	}
     }
 
@@ -842,5 +861,5 @@
     bool status;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.psf.stars", 2)) return true;
 
     int myKapa = psphotKapaChannel (3);
@@ -871,32 +890,32 @@
     for (int i = 0; i < sources->n; i++) {
 
-        pmSource *source = sources->data[i];
-
-        bool keep = false;
-        keep |= (source->mode & PM_SOURCE_MODE_PSFSTAR);
-        if (!keep) continue;
-
-        // how does this subimage get placed into the output image?
-        // DX = source->pixels->numCols
-        // DY = source->pixels->numRows
-
-        if (dX + DX > NX) {
-            // too wide for the rest of this row
-            if (dX == 0) {
-                // alone on this row
-                NY += DY;
-                dX = 0;
-                dY = 0;
-            } else {
-                // start the next row
-                NY += dY;
-                dX = DX;
-                dY = DY;
-            }
-        } else {
-            // extend this row
-            dX += DX;
-            dY = PS_MAX (dY, DY);
-        }
+	pmSource *source = sources->data[i];
+
+	bool keep = false;
+	keep |= (source->mode & PM_SOURCE_MODE_PSFSTAR);
+	if (!keep) continue;
+
+	// how does this subimage get placed into the output image?
+	// DX = source->pixels->numCols
+	// DY = source->pixels->numRows
+
+	if (dX + DX > NX) {
+	    // too wide for the rest of this row
+	    if (dX == 0) {
+		// alone on this row
+		NY += DY;
+		dX = 0;
+		dY = 0;
+	    } else {
+		// start the next row
+		NY += dY;
+		dX = DX;
+		dY = DY;
+	    }
+	} else {
+	    // extend this row
+	    dX += DX;
+	    dY = PS_MAX (dY, DY);
+	}
     }
     NY += DY;
@@ -918,59 +937,59 @@
     for (int i = 0; i < sources->n; i++) {
 
-        pmSource *source = sources->data[i];
-
-        bool keep = false;
-        if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
-            nPSF ++;
-            keep = true;
-        }
-        if (!keep) continue;
-
-        if (Xo + DX > NX) {
-            // too wide for the rest of this row
-            if (Xo == 0) {
-                // place source alone on this row
-                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);
-
-                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
-
-                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
-
-                Yo += DY;
-                Xo = 0;
-                dY = 0;
-            } else {
-                // start the next row
-                Yo += dY;
-                Xo = 0;
-
-                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);
-
-                pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-                psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
-
-                if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
-
-                Xo = DX;
-                dY = DY;
-            }
-        } else {
-            // extend this row
-            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);
-
-            pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-            psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
-            if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
-
-            Xo += DX;
-            dY = PS_MAX (dY, DY);
-        }
+	pmSource *source = sources->data[i];
+
+	bool keep = false;
+	if (source->mode & PM_SOURCE_MODE_PSFSTAR) {
+	    nPSF ++;
+	    keep = true;
+	}
+	if (!keep) continue;
+
+	if (Xo + DX > NX) {
+	    // too wide for the rest of this row
+	    if (Xo == 0) {
+		// place source alone on this row
+		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);
+
+		pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+		psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
+
+		if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
+
+		Yo += DY;
+		Xo = 0;
+		dY = 0;
+	    } else {
+		// start the next row
+		Yo += dY;
+		Xo = 0;
+
+		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);
+
+		pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+		psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
+
+		if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
+
+		Xo = DX;
+		dY = DY;
+	    }
+	} else {
+	    // extend this row
+	    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);
+
+	    pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+	    psphotMosaicSubimage (outsub, source, Xo, Yo, DX, DY, true);
+	    if (!subtracted) pmSourceAdd (source, PM_MODEL_OP_FULL, maskVal);
+
+	    Xo += DX;
+	    dY = PS_MAX (dY, DY);
+	}
     }
 
@@ -994,5 +1013,5 @@
     bool status;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.psf.sat", 3)) return true;
 
     int myKapa = psphotKapaChannel (3);
@@ -1023,32 +1042,32 @@
     for (int i = 0; i < sources->n; i++) {
 
-        pmSource *source = sources->data[i];
-
-        // 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?
-        // DX = source->pixels->numCols
-        // DY = source->pixels->numRows
-
-        if (dX + DX > NX) {
-            // too wide for the rest of this row
-            if (dX == 0) {
-                // alone on this row
-                NY += DY;
-                dX = 0;
-                dY = 0;
-            } else {
-                // start the next row
-                NY += dY;
-                dX = DX;
-                dY = DY;
-            }
-        } else {
-            // extend this row
-            dX += DX;
-            dY = PS_MAX (dY, DY);
-        }
+	pmSource *source = sources->data[i];
+
+	// 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?
+	// DX = source->pixels->numCols
+	// DY = source->pixels->numRows
+
+	if (dX + DX > NX) {
+	    // too wide for the rest of this row
+	    if (dX == 0) {
+		// alone on this row
+		NY += DY;
+		dX = 0;
+		dY = 0;
+	    } else {
+		// start the next row
+		NY += dY;
+		dX = DX;
+		dY = DY;
+	    }
+	} else {
+	    // extend this row
+	    dX += DX;
+	    dY = PS_MAX (dY, DY);
+	}
     }
     NY += DY;
@@ -1068,46 +1087,46 @@
     for (int i = 0; i < sources->n; i++) {
 
-        pmSource *source = sources->data[i];
-
-        // 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) {
-            // too wide for the rest of this row
-            if (Xo == 0) {
-                // place source alone on this row
-                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);
-                if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-
-                Yo += DY;
-                Xo = 0;
-                dY = 0;
-            } else {
-                // start the next row
-                Yo += dY;
-                Xo = 0;
-
-                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);
-                if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-
-                Xo = DX;
-                dY = DY;
-            }
-        } else {
-            // extend this row
-            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);
-            if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
-
-            Xo += DX;
-            dY = PS_MAX (dY, DY);
-        }
+	pmSource *source = sources->data[i];
+
+	// 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) {
+	    // too wide for the rest of this row
+	    if (Xo == 0) {
+		// place source alone on this row
+		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);
+		if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+
+		Yo += DY;
+		Xo = 0;
+		dY = 0;
+	    } else {
+		// start the next row
+		Yo += dY;
+		Xo = 0;
+
+		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);
+		if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+
+		Xo = DX;
+		dY = DY;
+	    }
+	} else {
+	    // extend this row
+	    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);
+	    if (subtracted) pmSourceSub (source, PM_MODEL_OP_FULL, maskVal);
+
+	    Xo += DX;
+	    dY = PS_MAX (dY, DY);
+	}
     }
 
@@ -1151,19 +1170,19 @@
     float Yo = source->modelPSF->params->data.F32[PM_PAR_YPOS] - source->pixels->row0;
     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]) {
-                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] = log10(rg->data.F32[ng]);
-                fg->data.F32[ng] = log10(source->pixels->data.F32[iy][ix]);
-                ng++;
-            }
-        }
+	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] = 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] = log10(rg->data.F32[ng]);
+		fg->data.F32[ng] = log10(source->pixels->data.F32[iy][ix]);
+		ng++;
+	    }
+	}
     }
 
@@ -1358,5 +1377,5 @@
     KapaSection section;  // put the positive profile in one and the residuals in another?
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.profiles", 3)) return true;
 
     int myKapa = psphotKapaChannel (2);
@@ -1394,22 +1413,22 @@
     for (int i = 0; i < sources->n; i++) {
 
-        pmSource *source = sources->data[i];
-        if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
-
-        psphotVisualPlotRadialProfile (myKapa, source, maskVal);
-
-        // pause and wait for user input:
-        // continue, save (provide name), ??
-        char key[10];
-        fprintf (stdout, "[e]rase and continue? [o]verplot and continue? [s]kip rest of stars? : ");
-        if (!fgets(key, 8, stdin)) {
-            psWarning("Unable to read option");
-        }
-        if (key[0] == 'e') {
-            KapaClearPlots (myKapa);
-        }
-        if (key[0] == 's') {
-            break;
-        }
+	pmSource *source = sources->data[i];
+	if (!(source->mode & PM_SOURCE_MODE_PSFSTAR)) continue;
+
+	psphotVisualPlotRadialProfile (myKapa, source, maskVal);
+
+	// pause and wait for user input:
+	// continue, save (provide name), ??
+	char key[10];
+	fprintf (stdout, "[e]rase and continue? [o]verplot and continue? [s]kip rest of stars? : ");
+	if (!fgets(key, 8, stdin)) {
+	    psWarning("Unable to read option");
+	}
+	if (key[0] == 'e') {
+	    KapaClearPlots (myKapa);
+	}
+	if (key[0] == 's') {
+	    break;
+	}
     }
 
@@ -1429,5 +1448,5 @@
     return true;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.objects.flags", 3)) return true;
 
     int myKapa = psphotKapaChannel (1);
@@ -1445,62 +1464,62 @@
     for (int i = 0; i < sources->n; i++) {
 
-        float Xo, Yo, Rmaj, Rmin, cs, sn;
-
-        pmSource *source = sources->data[i];
-        if (source == NULL) continue;
-
-        pmMoments *moments = source->moments;
-        if (0) {
-            emoments.x2 = moments->Mxx;
-            emoments.y2 = moments->Myy;
-            emoments.xy = moments->Mxy;
-            Xo = moments->Mx;
-            Yo = moments->My;
-
-            axes = psEllipseMomentsToAxes (emoments, 20.0);
-            Rmaj = 2.0*axes.major;
-            Rmin = 2.0*axes.minor;
-            cs = cos(axes.theta);
-            sn = sin(axes.theta);
-        } else {
-            Rmaj = Rmin = 5.0;
-            cs = 1.0;
-            sn = 0.0;
-            Xo = source->peak->xf;
-            Yo = source->peak->yf;
-        }
-
-        unsigned short int flagMask = 0x01;
-        for (int j = 0; j < 8; j++) {
-            if (source->mode & flagMask) {
-                overlayE[NoverlayE].type = KII_OVERLAY_LINE;
-                overlayE[NoverlayE].x = Xo;
-                overlayE[NoverlayE].y = Yo;
-
-                float phi = j*M_PI/4.0;
-                overlayE[NoverlayE].dx = +Rmaj*cos(phi)*cs - Rmin*sin(phi)*sn;
-                overlayE[NoverlayE].dy = +Rmaj*cos(phi)*sn + Rmin*sin(phi)*cs;
-                overlayE[NoverlayE].angle = 0;
-                overlayE[NoverlayE].text = NULL;
-                NoverlayE ++;
-                CHECK_REALLOCATE (overlayE, KiiOverlay, NOVERLAYE, NoverlayE, 100);
-            }
-            flagMask <<= 1;
-
-            if (source->mode & flagMask) {
-                overlayO[NoverlayO].type = KII_OVERLAY_LINE;
-                overlayO[NoverlayO].x = Xo + 1;
-                overlayO[NoverlayO].y = Yo;
-
-                float phi = j*M_PI/4.0;
-                overlayO[NoverlayO].dx = +Rmaj*cos(phi)*cs - Rmin*sin(phi)*sn;
-                overlayO[NoverlayO].dy = +Rmaj*cos(phi)*sn + Rmin*sin(phi)*cs;
-                overlayO[NoverlayO].angle = 0;
-                overlayO[NoverlayO].text = NULL;
-                NoverlayO ++;
-                CHECK_REALLOCATE (overlayO, KiiOverlay, NOVERLAYO, NoverlayO, 100);
-            }
-            flagMask <<= 1;
-        }
+	float Xo, Yo, Rmaj, Rmin, cs, sn;
+
+	pmSource *source = sources->data[i];
+	if (source == NULL) continue;
+
+	pmMoments *moments = source->moments;
+	if (0) {
+	    emoments.x2 = moments->Mxx;
+	    emoments.y2 = moments->Myy;
+	    emoments.xy = moments->Mxy;
+	    Xo = moments->Mx;
+	    Yo = moments->My;
+
+	    axes = psEllipseMomentsToAxes (emoments, 20.0);
+	    Rmaj = 2.0*axes.major;
+	    Rmin = 2.0*axes.minor;
+	    cs = cos(axes.theta);
+	    sn = sin(axes.theta);
+	} else {
+	    Rmaj = Rmin = 5.0;
+	    cs = 1.0;
+	    sn = 0.0;
+	    Xo = source->peak->xf;
+	    Yo = source->peak->yf;
+	}
+
+	unsigned short int flagMask = 0x01;
+	for (int j = 0; j < 8; j++) {
+	    if (source->mode & flagMask) {
+		overlayE[NoverlayE].type = KII_OVERLAY_LINE;
+		overlayE[NoverlayE].x = Xo;
+		overlayE[NoverlayE].y = Yo;
+
+		float phi = j*M_PI/4.0;
+		overlayE[NoverlayE].dx = +Rmaj*cos(phi)*cs - Rmin*sin(phi)*sn;
+		overlayE[NoverlayE].dy = +Rmaj*cos(phi)*sn + Rmin*sin(phi)*cs;
+		overlayE[NoverlayE].angle = 0;
+		overlayE[NoverlayE].text = NULL;
+		NoverlayE ++;
+		CHECK_REALLOCATE (overlayE, KiiOverlay, NOVERLAYE, NoverlayE, 100);
+	    }
+	    flagMask <<= 1;
+
+	    if (source->mode & flagMask) {
+		overlayO[NoverlayO].type = KII_OVERLAY_LINE;
+		overlayO[NoverlayO].x = Xo + 1;
+		overlayO[NoverlayO].y = Yo;
+
+		float phi = j*M_PI/4.0;
+		overlayO[NoverlayO].dx = +Rmaj*cos(phi)*cs - Rmin*sin(phi)*sn;
+		overlayO[NoverlayO].dy = +Rmaj*cos(phi)*sn + Rmin*sin(phi)*cs;
+		overlayO[NoverlayO].angle = 0;
+		overlayO[NoverlayO].text = NULL;
+		NoverlayO ++;
+		CHECK_REALLOCATE (overlayO, KiiOverlay, NOVERLAYO, NoverlayO, 100);
+	    }
+	    flagMask <<= 1;
+	}
     }
 
@@ -1531,33 +1550,33 @@
     for (int i = 0; i < sources->n; i++) {
 
-        pmSource *source = sources->data[i];
-        if (source == NULL) 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 ++;
+	pmSource *source = sources->data[i];
+	if (source == NULL) 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 ++;
     }
 
@@ -1570,5 +1589,5 @@
 bool psphotVisualShowSourceSize (pmReadout *readout, psArray *sources) {
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.objects.size", 2)) return true;
 
     int myKapa = psphotKapaChannel (1);
@@ -1597,5 +1616,5 @@
     KapaSection section;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.size", 2)) return true;
 
     int myKapa = psphotKapaChannel (2);
@@ -1612,26 +1631,26 @@
     float Ymin = 1000.0, Ymax = 0.0;
     {
-        int nRegions = psMetadataLookupS32 (&status, analysis, "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, analysis, 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); }
-        }
+	int nRegions = psMetadataLookupS32 (&status, analysis, "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, analysis, 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); }
+	}
     }
     Xmin = PS_MAX(Xmin, -0.1);
@@ -1677,53 +1696,53 @@
     int nCR  = 0;
     for (int i = 0; i < sources->n; i++) {
-        pmSource *source = sources->data[i];
-        if (source->moments == NULL) continue;
+	pmSource *source = sources->data[i];
+	if (source->moments == NULL) continue;
 
 	// only plot the measured sources...
-        if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)) 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->errMag > 0.1) {
-            xLOW->data.F32[nLOW] = source->moments->Mxx;
-            yLOW->data.F32[nLOW] = source->moments->Myy;
-            mLOW->data.F32[nLOW] = -2.5*log10(source->moments->Sum);
-            sLOW->data.F32[nLOW] = source->extNsigma;
-            nLOW++;
-            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++;
+	if (!(source->tmpFlags & PM_SOURCE_TMPF_SIZE_MEASURED)) 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->errMag > 0.1) {
+	    xLOW->data.F32[nLOW] = source->moments->Mxx;
+	    yLOW->data.F32[nLOW] = source->moments->Myy;
+	    mLOW->data.F32[nLOW] = -2.5*log10(source->moments->Sum);
+	    sLOW->data.F32[nLOW] = source->extNsigma;
+	    nLOW++;
+	    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++;
     }
 
@@ -2029,45 +2048,45 @@
     // 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, analysis, "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, analysis, 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);
+	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, analysis, "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, analysis, 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);
     }
 
@@ -2108,5 +2127,5 @@
 bool psphotVisualShowResidualImage (pmReadout *readout) {
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.image.resid", 2)) return true;
 
     int myKapa = psphotKapaChannel (1);
@@ -2124,5 +2143,5 @@
     float lineX[2], lineY[2];
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.apresid", 1)) return true;
 
     int myKapa = psphotKapaChannel (2);
@@ -2144,19 +2163,19 @@
     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->apMag)) continue;
-        if (!isfinite (source->psfMag)) continue;
-
-        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]);
-        graphdata.ymin = PS_MIN(graphdata.ymin, y->data.F32[n]);
-        graphdata.ymax = PS_MAX(graphdata.ymax, y->data.F32[n]);
-
-        n++;
+	pmSource *source = sources->data[i];
+	if (!source) continue;
+	if (source->type != PM_SOURCE_TYPE_STAR) continue;
+	if (!isfinite (source->apMag)) continue;
+	if (!isfinite (source->psfMag)) continue;
+
+	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]);
+	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;
@@ -2242,5 +2261,5 @@
     Graphdata graphdata;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.chisq", 1)) return true;
 
     int myKapa = psphotKapaChannel (2);
@@ -2263,22 +2282,22 @@
     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 (!source->moments) continue;
-        if (!isfinite(source->moments->Sum)) continue;
-        if (!source->modelPSF) continue;
-        if (!isfinite(source->modelPSF->chisq)) continue;
-
-        x->data.F32[n] = -2.5*log10(source->moments->Sum);
-        y->data.F32[n] = source->modelPSF->chisq / source->modelPSF->nDOF;
-        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]);
-
-        fprintf (f, "%d %d %f %f\n", i, n, x->data.F32[n], y->data.F32[n]);
-
-        n++;
+	pmSource *source = sources->data[i];
+	if (!source) continue;
+	if (source->type != PM_SOURCE_TYPE_STAR) continue;
+	if (!source->moments) continue;
+	if (!isfinite(source->moments->Sum)) continue;
+	if (!source->modelPSF) continue;
+	if (!isfinite(source->modelPSF->chisq)) continue;
+
+	x->data.F32[n] = -2.5*log10(source->moments->Sum);
+	y->data.F32[n] = source->modelPSF->chisq / source->modelPSF->nDOF;
+	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]);
+
+	fprintf (f, "%d %d %f %f\n", i, n, x->data.F32[n], y->data.F32[n]);
+
+	n++;
     }
     x->n = y->n = n;
@@ -2326,5 +2345,5 @@
     KiiOverlay *overlay;
 
-    if (!DEBUG && !pmVisualIsVisual()) return true;
+    if (!pmVisualTestLevel("psphot.objects.petro", 2)) return true;
 
     int kapa = psphotKapaChannel (1);
@@ -2336,32 +2355,32 @@
 
     for (int i = 0; i < sources->n; i++) {
-        pmSource *source = sources->data[i];
-
-        if (!source) continue;
-        if (!source->extpars) continue;
-        if (!source->extpars->petProfile) continue;
-
-        float petrosianRadius = source->extpars->petrosianRadius;
+	pmSource *source = sources->data[i];
+
+	if (!source) continue;
+	if (!source->extpars) continue;
+	if (!source->extpars->petProfile) continue;
+
+	float petrosianRadius = source->extpars->petrosianRadius;
 	psEllipseAxes *axes = &source->extpars->axes;
 
-        overlay[Noverlay].type = KII_OVERLAY_CIRCLE;
-        overlay[Noverlay].x = source->peak->xf;
-        overlay[Noverlay].y = source->peak->yf;
-        overlay[Noverlay].dx = 1.0*petrosianRadius;
-        overlay[Noverlay].dy = 1.0*petrosianRadius*axes->minor/axes->major;
-        overlay[Noverlay].angle = 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 = 2.0*petrosianRadius;
-        // overlay[Noverlay].dy = 2.0*petrosianRadius*axes->minor/axes->major;
-        // overlay[Noverlay].angle = 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 = 1.0*petrosianRadius;
+	overlay[Noverlay].dy = 1.0*petrosianRadius*axes->minor/axes->major;
+	overlay[Noverlay].angle = 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 = 2.0*petrosianRadius;
+	// overlay[Noverlay].dy = 2.0*petrosianRadius*axes->minor/axes->major;
+	// overlay[Noverlay].angle = axes->theta * PS_DEG_RAD;
+	// overlay[Noverlay].text = NULL;
+	// Noverlay ++;
+	// CHECK_REALLOCATE (overlay, KiiOverlay, NOVERLAY, Noverlay, 100);
     }
 
Index: /branches/sc_branches/trunkTest/pstamp/scripts/detectability_respond.pl
===================================================================
--- /branches/sc_branches/trunkTest/pstamp/scripts/detectability_respond.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/pstamp/scripts/detectability_respond.pl	(revision 29060)
@@ -98,4 +98,8 @@
 	    my $key = shift(@key_values);
 	    my $val = shift(@key_values);
+	    # if we have wisdom, then we should have updated already.  If not, we'll bomb out later in the code.
+	    if ($key eq 'FAULT') {
+		$val = 0;
+	    }
 	    $query{$fpa_id}{$key}[$i] = $val;
 	}
@@ -148,36 +152,36 @@
 	# Determine the query style for this fpa_id
 	if ($fpa_id =~ /o.*g.*o/) {
-	$query_style = 'byexp';
-    }
+	    $query_style = 'byexp';
+	}
 	elsif ($fpa_id =~ /\d+/) {
-	$query_style = 'byid';
-    }
+	    $query_style = 'byid';
+	}
 	else {
-	exit_with_failure(21,"Parse error in request file");
-    }
+	    exit_with_failure(21,"Parse error in request file");
+	}
 	# Confirm that we only have one stage/filter/mjd
 	for (my $i = 0; $i <= $#{ $query{$fpa_id}{STAGE} }; $i++) {
-	$temp_hash{STAGE}{$query{$fpa_id}{STAGE}[$i]} = 1;
-	$temp_hash{FILTER}{$query{$fpa_id}{FILTER}[$i]} = 1;
-	$temp_hash{'MJD-OBS'}{$query{$fpa_id}{'MJD-OBS'}[$i]} = 1;
-    }
+	    $temp_hash{STAGE}{$query{$fpa_id}{STAGE}[$i]} = 1;
+	    $temp_hash{FILTER}{$query{$fpa_id}{FILTER}[$i]} = 1;
+	    $temp_hash{'MJD-OBS'}{$query{$fpa_id}{'MJD-OBS'}[$i]} = 1;
+	}
 	if (scalar(keys(%{ $temp_hash{STAGE} })) == 1) {
 	    $stage = (keys(%{ $temp_hash{STAGE} }))[0];
 	}
 	else {
-	exit_with_failure(21,"Too many STAGEs specified");
-    }
+	    exit_with_failure(21,"Too many STAGEs specified");
+	}
 	if (scalar(keys(%{ $temp_hash{FILTER} })) == 1) {
-	$filter = (keys(%{ $temp_hash{FILTER} }))[0];
-    }
+	    $filter = (keys(%{ $temp_hash{FILTER} }))[0];
+	}
 	else {
-	exit_with_failure(21,"Too many FILTERs specified");
-    }
+	    exit_with_failure(21,"Too many FILTERs specified");
+	}
 	if (scalar(keys(%{ $temp_hash{'MJD-OBS'} })) == 1) {
-	$mjd = (keys(%{ $temp_hash{'MJD-OBS'} }))[0];
-    }
+	    $mjd = (keys(%{ $temp_hash{'MJD-OBS'} }))[0];
+	}
 	else {
-	exit_with_failure(21,"Too many MJD-OBS specified");
-    }
+	    exit_with_failure(21,"Too many MJD-OBS specified");
+	}
 	# Set common request components
 	my $option_mask |= 1;
@@ -231,6 +235,6 @@
 		    }
 		    else {
-		    $query{$fpa_id}{CATALOG}[$valid_index] = $this_image_ref->{cmf};
-		}
+			$query{$fpa_id}{CATALOG}[$valid_index] = $this_image_ref->{cmf};
+		    }
 		    if (exists($this_image_ref->{class_id})) {
 			$query{$fpa_id}{COMPONENT_ID}[$valid_index] = $this_image_ref->{class_id};
@@ -304,5 +308,5 @@
 	    ($query{$fpa_id}{STATE}[$i],$query{$fpa_id}{STAGE}[$i],$query{$fpa_id}{STAGE_ID}[$i],
 	     $query{$fpa_id}{COMPONENT_ID}[$i],$query{$fpa_id}{NEED_MAGIC}[$i],$query{$fpa_id}{IMAGE_DB}[$i]);
-	push @{ $processing_request{$fpa_id}{$query{$fpa_id}{IMAGE}[$i]} }, $i;
+ 	push @{ $processing_request{$fpa_id}{$query{$fpa_id}{IMAGE}[$i]} }, $i;
     }
 }
@@ -384,6 +388,6 @@
 	    my ($r_ra,$r_dec,$trash,$r_x,$r_y,$r_chip) = split /\s+/, $line;
 	    print $targetfile "$r_x $r_y\n";
-	    if (($r_ra == $query{$fpa_id}{RA1_DEG}[$processing_request{$fpa_id}{$image}[$i]])&&
-		($r_dec == $query{$fpa_id}{DEC1_DEG}[$processing_request{$fpa_id}{$image}[$i]])) {
+	    if ((abs($r_ra - $query{$fpa_id}{RA1_DEG}[$processing_request{$fpa_id}{$image}[$i]]) < 1e-8)&&
+		(abs($r_dec - $query{$fpa_id}{DEC1_DEG}[$processing_request{$fpa_id}{$image}[$i]]) < 1e-8)) {
 		$query{$fpa_id}{X_PXL}[$processing_request{$fpa_id}{$image}[$i]] = $r_x;
 		$query{$fpa_id}{Y_PXL}[$processing_request{$fpa_id}{$image}[$i]] = $r_y;
@@ -392,5 +396,5 @@
 	    else {
 		$error_code = $PS_EXIT_PROG_ERROR;
-		my_die("Unable to match input RA/DEC with output RA/DEC: ($query{$fpa_id}{RA1_DEG}[$i],$query{$fpa_id}{DEC1_DEG}[$i]) -> ($r_ra,$r_dec) i. $error_code",
+		my_die("Unable to match input RA/DEC with output RA/DEC: ($query{$fpa_id}{RA1_DEG}[$i],$query{$fpa_id}{DEC1_DEG}[$i]) -> ($r_ra,$r_dec) $error_code",
 		   $query{$fpa_id}{QUERY_ID}[$index],$fpa_id,$query{$fpa_id}{'MJD-OBS'}[$index],
 		   $query{$fpa_id}{FILTER}[$index],$query{$fpa_id}{OBSCODE}[$index],$query{$fpa_id}{STAGE}[$index],
Index: /branches/sc_branches/trunkTest/pstamp/scripts/pstamp_checkdependent.pl
===================================================================
--- /branches/sc_branches/trunkTest/pstamp/scripts/pstamp_checkdependent.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/pstamp/scripts/pstamp_checkdependent.pl	(revision 29060)
@@ -644,5 +644,8 @@
     # if the input file is already magicked no need to queue destreaking for this chipRun
     if ($need_magic and !$input_magicked) {
-        if ($dsRun_state eq 'cleaned') {
+        if (!defined($dsRun_state) or ($dsRun_state eq 'NULL')) {
+            print "No magicDSRun for chipRun $stage_id and magic is required\n";
+            faultJobs('stop', undef, undef, $PSTAMP_NOT_DESTREAKED);
+        } elsif ($dsRun_state eq 'cleaned') {
             my $command = "$magicdstool -updaterun -set_state new -stage $stage -stage_id $stage_id";
             $command .= " -set_label $rlabel" if $rlabel;
@@ -658,5 +661,5 @@
             }
         } elsif ($dsRun_state eq 'failed_revert') {
-            print "magicDSRun.state = $dsRun_state for chipRun $stage_id is in state failed_revert cannot update";
+            print "magicDSRun.state = $dsRun_state for chipRun $stage_id is in state failed_revert cannot update\n";
             faultJobs('stop', undef, undef, $PSTAMP_NOT_AVAILABLE);
         } else {
Index: /branches/sc_branches/trunkTest/pswarp/src/pswarpTransformSources.c
===================================================================
--- /branches/sc_branches/trunkTest/pswarp/src/pswarpTransformSources.c	(revision 29059)
+++ /branches/sc_branches/trunkTest/pswarp/src/pswarpTransformSources.c	(revision 29060)
@@ -102,5 +102,6 @@
         new->errMag = source->errMag;
         new->apMag = source->apMag;
-        new->pixWeight = source->pixWeight;
+        new->pixWeightNotBad = source->pixWeightNotBad;
+        new->pixWeightNotPoor = source->pixWeightNotPoor;
         new->psfChisq = source->psfChisq;
         new->crNsigma = source->crNsigma;
Index: /branches/sc_branches/trunkTest/tools/czarclean.pl
===================================================================
--- /branches/sc_branches/trunkTest/tools/czarclean.pl	(revision 29060)
+++ /branches/sc_branches/trunkTest/tools/czarclean.pl	(revision 29060)
@@ -0,0 +1,62 @@
+#!/usr/bin/perl -w
+
+use warnings;
+use strict;
+use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
+
+# local classes
+use czartool::CzarDb;
+
+my $czarDbName = undef;
+my $begin = undef;
+my $end = undef;
+my $interval = undef;
+my $verbose = undef;
+
+GetOptions (
+        "dbname|d=s" => \$czarDbName,
+        "interval|i=s" => \$interval,
+        "begin|b=s" => \$begin,
+        "end|e=s" => \$end,
+        "verbose|v" => \$verbose,
+        );
+
+print "\n*******************************************************************************\n";
+print "* \n";
+my $quit = 0;
+
+if (@ARGV) {
+    $quit=1;
+    print "* UNKNKOWN: option                          @ARGV\n";
+}
+if (!$begin) {
+    $quit=1;
+    print "* REQUIRED: choose a begin date             -b <datetime>                (default=7am this morning)\n";
+}
+if (!$end) {
+    $end=$begin;
+    print "* OPTIONAL: choose an end date              -e <datetime>                (default=$end)\n";
+}
+if (!$czarDbName) {
+    $czarDbName = "czardb";
+    print "* OPTIONAL: choose czar Db name             -d <name>                    (default=$czarDbName\n";
+}
+if (!$interval) {
+    $interval = "30 MINUTE";
+    print "* OPTIONAL: choose time interval            -i <'1 hour'|'2 hour'|etc>   (default=$interval)\n";
+}
+print "*\n*******************************************************************************\n";
+
+if ($quit) { exit; }
+
+
+my $save_temps = 0;
+
+
+my $czarDb = new czartool::CzarDb($czarDbName, "ippdb01", "ipp", "ipp", 0, $save_temps); # TODO last arg here is save_temps, should get as arg
+
+my $labels = undef;
+
+
+$czarDb->cleanupDateRange($begin, $end, "1 HOUR");
+
Index: /branches/sc_branches/trunkTest/tools/czarplot.pl
===================================================================
--- /branches/sc_branches/trunkTest/tools/czarplot.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/tools/czarplot.pl	(revision 29060)
@@ -38,5 +38,12 @@
         );
 
-print "\n";
+
+print "\n*******************************************************************************\n";
+print "* \n";
+my $quit = 0;
+if (@ARGV) {
+    $quit=1;
+    print "* UNKNKOWN: option                          @ARGV\n";
+}
 if (!$histogram) {
     print "* OPTIONAL: plot histogram                  -h                          (default=off)\n";}
@@ -50,5 +57,5 @@
     print "* OPTIONAL: choose a stage                  -s <chip|cam|warp|etc>      (default=none)\n";}
 if (!$interval) {
-    print "* OPTIONAL: choose time interval in past    -i <'1 hour'|'1 day'|etc>   (default=interval since 7am this morning)\n";} 
+    print "* OPTIONAL: choose time interval in past    -i <'1 hour'|'1 day'|etc>   (default=none\n";} 
 if (!$begin) {
     print "* OPTIONAL: choose a begin time             -b <datetime>               (default=7am this morning)\n";} 
@@ -57,6 +64,7 @@
 if (!$path) {
     print "* OPTIONAL: choose an output location       -o <path>                   (default=none)\n";} 
+print "*\n*******************************************************************************\n";
 
-print "\n";
+if ($quit) { exit; }
 
 # default values
@@ -71,7 +79,7 @@
 $czarDb->setDateFormat("%Y%m%d-%H%i%s");
 
+
+# GENE PLOTS my $czarplot = new czartool::Czarplot($czarDb, "%Y%m%d-%H%M%S", $savingToFile ? "png size 1280,960 font \"/usr/share/fonts/corefonts/arial.ttf\" 12" : "X11", $path, $save_temps);
 my $czarplot = new czartool::Czarplot($czarDb, "%Y%m%d-%H%M%S", $savingToFile ? "png font \"/usr/share/fonts/corefonts/arial.ttf\" 8" : "X11", $path, $save_temps);
-
-my @allStages = ("chip", "cam", "fake", "warp", "stack", "diff", "magic", "magicDS", "dist");
 
 # sort out times
@@ -79,5 +87,5 @@
 if (!$begin) {
     if ($interval) {$begin = $czarDb->subtractInterval($end, $interval);}
-    else {$begin =  strftime('%Y-%m-%d 07:00',localtime);}
+    else {$begin =  strftime('%Y-%m-%d 06:30',localtime);}
 }
 
Index: /branches/sc_branches/trunkTest/tools/czartool/Burntool.pm
===================================================================
--- /branches/sc_branches/trunkTest/tools/czartool/Burntool.pm	(revision 29060)
+++ /branches/sc_branches/trunkTest/tools/czartool/Burntool.pm	(revision 29060)
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+package czartool::Burntool;
+
+use warnings;
+use strict;
+
+use IPC::Cmd 0.36 qw( can_run run );
+
+###########################################################################
+#
+# Constructor
+#
+###########################################################################
+sub new {
+    my $class = shift;
+    my $self = {};
+    $self->{_verbose} = 0;
+
+    # get today's date
+    my ($day, $month, $year) = (localtime)[3,4,5];
+    $self->{_today} = sprintf("%04d-%02d-%02d", $year+1900, $month+1, $day);
+
+    bless $self, $class;
+    return $self;
+}
+
+###########################################################################
+#
+# Get pending and processed for this label
+#
+###########################################################################
+sub getPendingAndProcessed {
+    my ($self, $label, $pending, $processed) = @_;
+
+    ${$pending} = ${$processed} = 0;
+
+    my $target = undef;
+
+    if ($label =~ m/(.*)\.nightlyscience/) {
+
+        $target = $1;
+    }
+    else {return 0;}
+
+
+    if ($self->{_verbose}) {print "Checking $target for $self->{_today}\n";}
+    my $command = "automate_stacks.pl --check_chips --burntool_stats --this_target_only $target --date $self->{_today} ";
+    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
+                run(command => $command, verbose => $self->{_verbose});
+
+    if (!$success) {return 0;}
+
+    my $line;
+    foreach $line (@{$stdout_buf}) {
+
+        chomp($line);
+        if($line =~ m/([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)/) {
+            if ($self->{_verbose}) {print "Output =  $1 $2 $3 $4\n";}
+            ${$pending} = ($2 - $3)/60;
+            ${$processed} = $3/60;
+            return 1;
+        }
+    }
+
+    return 0;
+}
+1;
+
+
Index: /branches/sc_branches/trunkTest/tools/czartool/CzarDb.pm
===================================================================
--- /branches/sc_branches/trunkTest/tools/czartool/CzarDb.pm	(revision 29059)
+++ /branches/sc_branches/trunkTest/tools/czartool/CzarDb.pm	(revision 29060)
@@ -1,3 +1,3 @@
-#!/usr/bin/perl i-w
+#!/usr/bin/perl -w
 
 package czartool::CzarDb;
@@ -6,5 +6,5 @@
 use strict;
 
-my @stages = ("chip", "cam", "fake", "warp", "stack", "diff", "magic", "magicDS", "dist"); # TODO put elsewhere
+my @stages = ("burntool", "chip", "cam", "fake", "warp", "stack", "diff", "magic", "magicDS", "dist"); # TODO put elsewhere
 
 use base 'czartool::MySQLDb';
@@ -491,4 +491,117 @@
 }
 
+
+###########################################################################
+#
+# Deletes all but one row per interval from all stage tables for all labels between the two dates
+#
+###########################################################################
+sub cleanupDateRange {
+    my ($self, $startDay, $endDay, $interval) = @_;
+
+    my $thisDay = $startDay;
+    my $quit = 0;
+    while(!$quit) {
+
+        if (!$self->isBefore($thisDay, $endDay)) {
+        
+            $quit = 1;
+        }
+
+        print "* Running cleanup for $thisDay with an interval of $interval\n";
+        $self->cleanupADay($thisDay, $interval);
+        $thisDay = $self->addInterval($thisDay, "1 DAY");
+
+    }
+}
+###########################################################################
+#
+# Deletes all but one row per interval from all stage tables for all labels between the provided day
+#
+###########################################################################
+sub cleanupADay {
+    my ($self, $startDay, $interval) = @_;
+
+    my $endDay =  $self->addInterval($startDay, "1 DAY");
+
+    my $labels = undef;
+    my $fromTime = $startDay;
+    my $toTime = undef;
+    my $totalDeleted = undef;
+    my $quit = 0;
+    while(!$quit) {
+
+        $toTime = $self->addInterval($fromTime, $interval);
+        if (!$self->isBefore($toTime, $endDay)) {
+        
+            $toTime = $endDay;
+            $quit = 1;
+        }
+   
+        my $stage = undef;
+        $totalDeleted = 0;
+        foreach $stage (@stages) {
+
+            if (!$self->getLabelsInThisTimePeriod($stage, $fromTime, $toTime, \$labels)) {next;}
+
+            my $label = undef;
+            my $row = undef;
+            foreach $row ( @{$labels} ) {
+                my ($label) = @{$row};
+
+                my $query = $self->{_db}->prepare(<<SQL);
+                SELECT COUNT(*) 
+                    FROM $stage 
+                    WHERE timestamp > '$fromTime'
+                    AND timestamp <= '$toTime'
+                    AND label = '$label' 
+SQL
+
+                    $query->execute;
+
+                my $toDelete = scalar $query->fetchrow_array() - 1;
+                if ($toDelete < 1) {next;}
+
+                $query = $self->{_db}->prepare(<<SQL);
+                DELETE FROM $stage 
+                    WHERE timestamp > '$fromTime' 
+                    AND timestamp <= '$toTime' 
+                    AND label = '$label' ORDER BY timestamp DESC LIMIT $toDelete
+SQL
+                    $query->execute;
+
+                $totalDeleted += $toDelete;
+            }
+        }
+        print "   * Deleted $totalDeleted between $fromTime and  $toTime\n";
+        $fromTime = $toTime;
+    }
+}
+
+###########################################################################
+#
+# Returns an array of labels present during the provided time frame 
+#
+###########################################################################
+sub getLabelsInThisTimePeriod {
+    my ($self, $stage, $fromTime, $toTime, $labels) = @_;
+
+    my $query = $self->{_db}->prepare(<<SQL);
+    SELECT DISTINCT label 
+        FROM $stage 
+        WHERE timestamp > '$fromTime' 
+        AND timestamp <= '$toTime';
+SQL
+
+        if (!$query->execute) {
+
+            return 0;
+        }
+
+    ${$labels} = $query->fetchall_arrayref();
+
+    return 1;
+}
+
 ###########################################################################
 #
@@ -500,7 +613,6 @@
 
     my $currentRevision = -1;
-    my $latestRevision = 10;
-
-    while ($currentRevision != $latestRevision) {
+
+    while (1) {
 
         $currentRevision = $self->getRevision();
@@ -517,4 +629,6 @@
         elsif ($currentRevision == 8) {$self->createRevision_9();}
         elsif ($currentRevision == 9) {$self->createRevision_10();}
+        elsif ($currentRevision == 10) {$self->createRevision_11();}
+        else {last;}
     }
 }
@@ -841,4 +955,36 @@
 }
 
+#######################################################################################
+# 
+# Create revision 11 of the database 
+#
+#######################################################################################
+sub createRevision_11 {
+    my ($self) = @_;
+
+    print "* Creating revision 11 of '$self->{_dbName}'\n";
+
+    # same shape as other stage tables to enable easy update
+    my $query = $self->{_db}->prepare(<<SQL);
+    CREATE TABLE burntool (
+            timestamp TIMESTAMP DEFAULT NOW(),
+            label VARCHAR(128) DEFAULT "NONE", 
+            pending BIGINT NOT NULL,
+            processed BIGINT NOT NULL,
+            faults BIGINT NOT NULL);
+SQL
+
+      $query->execute;
+        $query = $self->{_db}->prepare(<<SQL);
+        CREATE INDEX burntoolIndex ON burntool (timestamp, label);
+SQL
+
+      $query->execute;
+
+    $self->setRevision(11);
+}
+
+
+
 1;
 
Index: /branches/sc_branches/trunkTest/tools/czartool/Czarplot.pm
===================================================================
--- /branches/sc_branches/trunkTest/tools/czartool/Czarplot.pm	(revision 29059)
+++ /branches/sc_branches/trunkTest/tools/czartool/Czarplot.pm	(revision 29060)
@@ -5,5 +5,5 @@
 use strict;
 
-my @allStages = ("chip", "cam", "fake", "warp", "stack", "diff", "magic", "magicDS", "dist");
+my @allStages = ("burntool", "chip", "cam", "fake", "warp", "stack", "diff", "magic", "magicDS", "dist");
 
 
@@ -75,5 +75,5 @@
     if ($numOfPlots == 0 ) {
 
-        print "Warning: No plots could be generated for '$label' during time period '$beginTime', '$endTime'\n";
+        print "Warning: No plots could be generated for stage '$selectedStage' and label '$label' during time period '$beginTime', '$endTime'\n";
         return;
     } 
@@ -103,8 +103,11 @@
     my ($processed, $pending, $faults);
     my $stage = undef;
+    my $pendingMinusFaults = undef;
     foreach $stage (@allStages) {
 
         $self->{_czarDb}->countProcessedPendingAndFaults($label, $stage, $beginTime, $endTime, \$processed, \$pending, \$faults);
-        print GNUDAT "$stage $processed, $pending, $faults\n";
+
+        $pendingMinusFaults = $pending - $faults;
+        print GNUDAT "$stage $faults $processed, $pendingMinusFaults\n";
     }
 
@@ -258,11 +261,11 @@
         if ($numOfPlots == 1) {
 
-            print GP "'" . $gnuplotFiles->{$stage} . "' using 1:4 title \"Processed\" with lines lt 2,";
-            print GP "'" . $gnuplotFiles->{$stage} . "' using 1:2 title \"Pending\" with lines lt 4,";
-            print GP "'" . $gnuplotFiles->{$stage} . "' using 1:3 title \"Faults\" with lines lt 7";
+            print GP "'" . $gnuplotFiles->{$stage} . "' using 1:4 title \"Processed\" with lines lt 2 lw 2,";
+            print GP "'" . $gnuplotFiles->{$stage} . "' using 1:2 title \"Pending\" with lines lt 4 lw 2,";
+            print GP "'" . $gnuplotFiles->{$stage} . "' using 1:3 title \"Faults\" with lines lt 7 lw 2";
         }
         # when plotting multiple stages, show only processed
         else {
-            print GP "'" . $gnuplotFiles->{$stage} . "' using 1:4 title \"$stage\" with lines";
+            print GP "'" . $gnuplotFiles->{$stage} . "' using 1:4 title \"$stage\" with lines lw 2";
         }
         $firstIn = 0;
@@ -339,10 +342,12 @@
         "set boxwidth;" .
         "set style data histogram;" .
-        "set style histogram cluster gap 3;" .
+ "set style histogram rowstacked;" .
         "set style fill solid border -1;" .
-        "set bmargin 5;" .
         "set ylabel \"Exposures\";" .
-        "plot '$inputFile' using 2:xtic(1) title \"Processed\" lt 2, '' using 3 title \"Pending\" lt 4, '' using 4 title \"Faults\" lt 7;" . 
+        "set boxwidth 0.75;" .
+        "plot '$inputFile' using 2:xtic(1) title \"Faults\" lt 1, '' using 3 title \"Processed\" lt 2, '' using 4 title \"Pending\" lt 7;" . 
         "\n";
+
+
 
     close GP;
Index: /branches/sc_branches/trunkTest/tools/czartool/MySQLDb.pm
===================================================================
--- /branches/sc_branches/trunkTest/tools/czartool/MySQLDb.pm	(revision 29059)
+++ /branches/sc_branches/trunkTest/tools/czartool/MySQLDb.pm	(revision 29060)
@@ -64,4 +64,20 @@
     return $self->{_dbHost};                                                 
 }                                                                               
+
+###########################################################################
+#
+# Adds the provided interval to the provided time
+#
+###########################################################################
+sub addInterval {
+    my ($self, $time, $interval) = @_;
+
+      my $query = $self->{_db}->prepare(<<SQL);
+          SELECT '$time' + INTERVAL $interval; 
+SQL
+    $query->execute;
+
+return scalar $query->fetchrow_array();
+}
 
 ###########################################################################
Index: /branches/sc_branches/trunkTest/tools/neb-grep
===================================================================
--- /branches/sc_branches/trunkTest/tools/neb-grep	(revision 29060)
+++ /branches/sc_branches/trunkTest/tools/neb-grep	(revision 29060)
@@ -0,0 +1,90 @@
+#!/usr/bin/perl -w
+
+$debug = "/dev/null";
+open DEBUG, ">$debug" or die "Can't open $debug";
+# Note:
+# Debug messages are prepended with the "DEBUG: " pattern
+# Therefore:
+#     neb-grep -v GREP_PATTERN FILE_PATTERN | grep -v ^DEBUG
+# is equivalent to:
+#     neb-grep GREP_PATTERN FILE_PATTERN
+
+#
+# We need at least two arguments
+#
+if (@ARGV < 2) {
+    $usage = "Usage: neb-grep [--verbose|-v] [--server <URL>] [GREP OPTIONS] <grep_pattern> <file_pattern>\n";
+    $usage .= "  See grep man page for <grep_pattern> and [GREP OPTIONS]\n";
+    $usage .= "  <file_pattern> is a SQL-like pattern (file_pattern search is based on neb-ls --path)\n";
+    $usage .= "  http://nebulous.mhpcc.ipp.ifa.hawaii.edu/nebulous is default <URL> value\n";
+    $usage .= "  [-v|--verbose] show details\n";
+    $usage .= "\n";
+    $usage .= "  Example(s):\n";
+    $usage .= "    neb-grep \"my_die\" gpc1/ThreePi.nt/2010/08/24/o5432g0503o.212622/o5432g0503o.212622.ch.126887.%.log\n";
+    $usage .= "    neb-grep -i \"MY_DIE\" gpc1/ThreePi.nt/2010/08/24/o5432g0503o.212622/o5432g0503o.212622.ch.126887.%.log\n";
+    &bye(2, $usage);
+}
+
+# 
+# Parse arguments 
+#
+$args = "";
+while (@ARGV > 1) {
+    if ($ARGV[0] =~ /--path/) {
+	#Forget it since it's always added
+	shift;
+    } elsif ( $ARGV[0] =~ /--server/ ) {
+	shift;
+	$server = $ARGV[0];
+	shift;
+    } elsif ( ($ARGV[0] =~ /--verbose/) || ($ARGV[0] =~ /-v/) ){
+	close DEBUG;
+	$debug = "/dev/stdout";
+	open DEBUG, ">$debug" or die "Can't open $debug";
+	shift;
+    } else {
+	$args .= $ARGV[0]." ";
+	shift;
+    }
+}
+$file_pattern=$ARGV[0];
+chop $args;
+print DEBUG "DEBUG: file_pattern = [$file_pattern]\n";
+print DEBUG "DEBUG: grep arguments = [$args]\n";
+
+# Define server with the default value if needed
+if (!(defined $server)) {
+    $server = "http://nebulous.mhpcc.ipp.ifa.hawaii.edu/nebulous";
+}
+
+# Get the filenames from neb-ls command
+print DEBUG "DEBUG: Executing command: neb-ls --path --server $server  --path $file_pattern 2>&1\n";
+@nebitems = `neb-ls --path --server $server --path $file_pattern 2>&1`;
+
+# Deal with non-matching file patterns
+if ( (@nebitems == 0) || ($nebitems[0] =~ /no instances/) ) {
+    &bye(1, "no instances");
+}
+
+# Deal with matching file patterns by running the "grep" command
+for $filename (@nebitems) {
+    chomp $filename;
+    print DEBUG "DEBUG: Executing grep $args $filename\n";
+    $output = `grep $args $filename`;
+    print DEBUG "DEBUG: Output is [$output]\n";
+    if (!($output =~ /^$/)) {
+	print $filename, ": ", $output;
+    }
+}
+&bye(0, "");
+
+sub bye {
+    my $status = shift;
+    my $message = shift;
+    close DEBUG;
+    unless ($message =~ /^$/) {
+	print STDERR $message,"\n";
+    }
+    exit $status;
+}
+
Index: /branches/sc_branches/trunkTest/tools/roboczar.pl
===================================================================
--- /branches/sc_branches/trunkTest/tools/roboczar.pl	(revision 29059)
+++ /branches/sc_branches/trunkTest/tools/roboczar.pl	(revision 29060)
@@ -12,4 +12,5 @@
 use czartool::Nebulous;
 use czartool::Czarplot;
+use czartool::Burntool;
 
 my $period = 60;
@@ -27,7 +28,9 @@
 my $pantasks = new czartool::Pantasks();
 my $czarplot = new czartool::Czarplot($czarDb, "%Y%m%d-%H%M%S", "png font \"/usr/share/fonts/corefonts/arial.ttf\" 8", "/tmp", $save_temps); # TODO hardcoded font path
+my $burntool = new czartool::Burntool();
+
 $czarDb->setDateFormat("%Y%m%d-%H%i%s");
 
-my @stages = ("chip", "cam", "fake", "warp", "stack", "diff", "magic", "magicDS", "dist");
+my @stages = ("burntool", "chip", "cam", "fake", "warp", "stack", "diff", "magic", "magicDS", "dist");
 
 
@@ -105,5 +108,5 @@
 
         # sort out times
-        $begin =  strftime('%Y-%m-%d 07:00',localtime);
+        $begin =  strftime('%Y-%m-%d 06:30',localtime);
         $end = $czarDb->getNowTimestamp();
 
@@ -233,8 +236,19 @@
             chomp($label);
 
-            $new = $gpc1Db->countExposures($label, $stage, $newState);
-            $full = $gpc1Db->countExposures($label, $stage, "full");
-            $faults = $gpc1Db->countFaults($label, $stage, $newState);
-
+            if ($stage eq "burntool") {
+
+                if ($labelServer eq "stdscience") {
+
+                    $burntool->getPendingAndProcessed($label, \$new, \$full);
+                    $faults = 0;
+                }
+                else { $new = $full = $faults = 0;}
+            }
+            else {
+
+                $new = $gpc1Db->countExposures($label, $stage, $newState);
+                $full = $gpc1Db->countExposures($label, $stage, "full");
+                $faults = $gpc1Db->countFaults($label, $stage, $newState);
+            }
             #printf("%s  %s, %s, %d, %d\n", $labelServer, $label, $stage, $new, $faults);
             $totalNew += $new;
