Index: trunk/psModules/src/pmObjects.c
===================================================================
--- trunk/psModules/src/pmObjects.c	(revision 3723)
+++ trunk/psModules/src/pmObjects.c	(revision 3877)
@@ -5,6 +5,6 @@
  *  @author GLG, MHPCC
  *
- *  @version $Revision: 1.20 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2005-04-19 23:44:54 $
+ *  @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2005-05-10 23:48:19 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -20,5 +20,5 @@
 /******************************************************************************
 pmPeakAlloc(): Allocate the psPeak data structure and set appropriate members.
- *****************************************************************************/
+*****************************************************************************/
 psPeak *pmPeakAlloc(psS32 x,
                     psS32 y,
@@ -38,5 +38,5 @@
 pmMomentsAlloc(): Allocate the psMoments structure and initialize the members
 to zero.
- *****************************************************************************/
+*****************************************************************************/
 psMoments *pmMomentsAlloc()
 {
@@ -45,5 +45,5 @@
     tmp->y = 0.0;
     tmp->Sx = 0.0;
-    tmp->Sy = 0.0;
+    tmp->Sx = 0.0;
     tmp->Sxy = 0.0;
     tmp->Sum = 0.0;
@@ -64,5 +64,6 @@
 pmModelAlloc(): Allocate the psModel structure, along with its parameters,
 and initialize the type member.  Initialize the params to 0.0.
- *****************************************************************************/
+XXX EAM: changing params and dparams to psVector 
+*****************************************************************************/
 psModel *pmModelAlloc(psModelType type)
 {
@@ -73,32 +74,26 @@
     switch (type) {
     case PS_MODEL_GAUSS:
-        tmp->Nparams = 7;
-        tmp->params = (psF32 *) psAlloc(7 * sizeof(PS_TYPE_F32));
-        tmp->dparams = (psF32 *) psAlloc(7 * sizeof(PS_TYPE_F32));
+        tmp->params  = psVectorAlloc(7, PS_TYPE_F32);
+        tmp->dparams = psVectorAlloc(7, PS_TYPE_F32);
         break;
     case PS_MODEL_PGAUSS:
-        tmp->Nparams = 7;
-        tmp->params = (psF32 *) psAlloc(7 * sizeof(PS_TYPE_F32));
-        tmp->dparams = (psF32 *) psAlloc(7 * sizeof(PS_TYPE_F32));
+        tmp->params  = psVectorAlloc(7, PS_TYPE_F32);
+        tmp->dparams = psVectorAlloc(7, PS_TYPE_F32);
         break;
     case PS_MODEL_TWIST_GAUSS:
-        tmp->Nparams = 11;
-        tmp->params = (psF32 *) psAlloc(11 * sizeof(PS_TYPE_F32));
-        tmp->dparams = (psF32 *) psAlloc(11 * sizeof(PS_TYPE_F32));
+        tmp->params  = psVectorAlloc(11, PS_TYPE_F32);
+        tmp->dparams = psVectorAlloc(11, PS_TYPE_F32);
         break;
     case PS_MODEL_WAUSS:
-        tmp->Nparams = 9;
-        tmp->params = (psF32 *) psAlloc(9 * sizeof(PS_TYPE_F32));
-        tmp->dparams = (psF32 *) psAlloc(9 * sizeof(PS_TYPE_F32));
+        tmp->params  = psVectorAlloc(9, PS_TYPE_F32);
+        tmp->dparams = psVectorAlloc(9, PS_TYPE_F32);
         break;
     case PS_MODEL_SERSIC:
-        tmp->Nparams = 8;
-        tmp->params = (psF32 *) psAlloc(8 * sizeof(PS_TYPE_F32));
-        tmp->dparams = (psF32 *) psAlloc(8 * sizeof(PS_TYPE_F32));
+        tmp->params  = psVectorAlloc(8, PS_TYPE_F32);
+        tmp->dparams = psVectorAlloc(8, PS_TYPE_F32);
         break;
     case PS_MODEL_SERSIC_CORE:
-        tmp->Nparams = 12;
-        tmp->params = (psF32 *) psAlloc(12 * sizeof(PS_TYPE_F32));
-        tmp->dparams = (psF32 *) psAlloc(12 * sizeof(PS_TYPE_F32));
+        tmp->params  = psVectorAlloc(12, PS_TYPE_F32);
+        tmp->dparams = psVectorAlloc(12, PS_TYPE_F32);
         break;
     default:
@@ -107,7 +102,7 @@
     }
 
-    for (psS32 i = 0 ; i < tmp->Nparams ; i++) {
-        tmp->params[i] = 0.0;
-        tmp->dparams[i] = 0.0;
+    for (psS32 i = 0; i < tmp->params->n; i++) {
+        tmp->params->data.F32[i] = 0.0;
+        tmp->dparams->data.F32[i] = 0.0;
     }
 
@@ -117,13 +112,14 @@
 
 /******************************************************************************
-p_psSourceFree(tmp): a private function which frees the psSource struct.
- *****************************************************************************/
-static void p_psSourceFree(psSource *tmpSrc)
-{
-    psFree(tmpSrc->peak);
-    psFree(tmpSrc->pixels);
-    psFree(tmpSrc->mask);
-    psFree(tmpSrc->moments);
-    psFree(tmpSrc->models);
+XXX: We don't free pixels and mask since that caused a memory error.
+We might need to increase the reference counter and decrease it here.
+*****************************************************************************/
+static void p_psSourceFree(psSource *tmp)
+{
+    psFree(tmp->peak);
+    //    psFree(tmp->pixels);
+    //    psFree(tmp->mask);
+    psFree(tmp->moments);
+    psFree(tmp->models);
 }
 
@@ -131,16 +127,17 @@
 pmSourceAlloc(): Allocate the psSource structure and initialize its members
 to NULL.
- *****************************************************************************/
+*****************************************************************************/
 psSource *pmSourceAlloc()
 {
-    psSource *tmpSrc = (psSource *) psAlloc(sizeof(psSource));
-    tmpSrc->peak = NULL;
-    tmpSrc->pixels = NULL;
-    tmpSrc->mask = NULL;
-    tmpSrc->moments = NULL;
-    tmpSrc->models = NULL;
-    psMemSetDeallocator(tmpSrc, (psFreeFcn) p_psSourceFree);
-
-    return(tmpSrc);
+    psSource *tmp = (psSource *) psAlloc(sizeof(psSource));
+    tmp->peak = NULL;
+    tmp->pixels = NULL;
+    tmp->mask = NULL;
+    tmp->moments = NULL;
+    tmp->models = NULL;
+    tmp->type = 0;
+    psMemSetDeallocator(tmp, (psFreeFcn) p_psSourceFree);
+
+    return(tmp);
 }
 
@@ -154,7 +151,6 @@
 XXX: We currently step through the input vector twice; once to determine the
 size of the output vector, then to set the values of the output vector.
-Depending upon actual use, this may need to be optimized.  Use the function
-which adds to a psVector.  It's not clear which way is faster.
- *****************************************************************************/
+Depending upon actual use, this may need to be optimized.
+*****************************************************************************/
 psVector *pmFindVectorPeaks(const psVector *vector,
                             psF32 threshold)
@@ -250,7 +246,5 @@
  
 XXX: Is there a better way to do this?
- 
-XXX: Use memcpy() on the data transfer.
- *****************************************************************************/
+*****************************************************************************/
 psVector *p_psGetRowVectorFromImage(psImage *image,
                                     psU32 row)
@@ -267,202 +261,62 @@
 
 /******************************************************************************
-p_psGetColVectorFromImage(): a private function which simply returns a
-psVector containing the specified col of data from the psImage.
- 
-XXX: Is there a better way to do this?
- 
-XXX: Use memcpy() on the data transfer.
- *****************************************************************************/
-psVector *p_psGetColVectorFromImage(psImage *image,
-                                    psU32 col)
+MyListAddPeak(): A private function which allocates a psArray, if the list
+argument is NULL, otherwise it adds the peak to that list.
+XXX EAM : changed the output to psArray 
+XXX EAM : Switched row, col args 
+XXX EAM : NOTE: this was changed in the call, so the new code is consistent
+*****************************************************************************/
+psArray *MyListAddPeak(psArray *list,
+                       psS32 row,
+                       psS32 col,
+                       psF32 counts,
+                       psPeakType type)
+{
+    psPeak *tmpPeak = pmPeakAlloc(col, row, counts, type);
+
+    if (list == NULL) {
+        list = psArrayAlloc(100);
+        list->n = 0;
+    }
+    psArrayAdd(list, 100, tmpPeak);
+
+    return(list);
+}
+
+/******************************************************************************
+pmFindImagePeaks(image, threshold): Find all local peaks in the given psImage
+above the given threshold.  Returns a psArray containing location (x/y value)
+of all peaks.
+ 
+XXX: I'm not convinced the peak type definition in the SDRS is mutually
+exclusive.  Some peaks can have multiple types.  Edges for sure.  Also, a
+digonal line with the same value at each point will have a peak for every
+point on that line.
+ 
+XXX: This does not work if image has either a single row, or a single column.
+ 
+XXX: In the output psArray elements, should we use the image row/column offsets?
+     Currently, we do not.
+*****************************************************************************/
+psArray *pmFindImagePeaks(const psImage *image,
+                          psF32 threshold)
 {
     PS_IMAGE_CHECK_NULL(image, NULL);
     PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, NULL);
-
-    psVector *tmpVector = psVectorAlloc(image->numRows, PS_TYPE_F32);
-    for (psU32 row = 0; row < image->numRows ; row++) {
-        tmpVector->data.F32[row] = image->data.F32[row][col];
-    }
-    return(tmpVector);
-}
-
-/******************************************************************************
-MyListAddPeak(): A private function which allocates a psList, if the list
-argument is NULL, otherwise it adds the peak to that list.
- *****************************************************************************/
-psList *MyListAddPeak(psList *list,
-                      psS32 col,
-                      psS32 row,
-                      psF32 counts,
-                      psPeakType type)
-{
-    psPeak *tmpPeak = pmPeakAlloc(col, row, counts, type);
-
-    if (list == NULL) {
-        list = psListAlloc(tmpPeak);
-    } else {
-        psListAdd(list, PS_LIST_HEAD, tmpPeak);
-    }
-
-    return(list);
-}
-
-/******************************************************************************
-pmFindImagePeaks(image, threshold): Find all local peaks in the given psImage
-above the given threshold.  Returns a psList containing location (x/y value)
-of all peaks.
- *****************************************************************************/
-psList *pmFindImagePeaks(const psImage *image,
-                         psF32 threshold)
-{
-    PS_IMAGE_CHECK_NULL(image, NULL);
-    PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, NULL);
-    psPeakType myPeakClass = PM_PEAK_UNDEF;
+    if ((image->numRows == 1) || (image->numCols == 1)) {
+        psError(PS_ERR_UNKNOWN, true, "Currently, input image must have at least 2 rows and 2 columns.");
+    }
     psVector *tmpRow = NULL;
     psU32 col = 0;
     psU32 row = 0;
-    psList *list = NULL;
-
-    //
-    // Special case: a 1-by-1 image.
-    //
-    if ((image->numCols == 1) && (image->numRows == 1)) {
-        if (image->data.F32[row][col] > threshold) {
-            myPeakClass = PM_PEAK_EDGE | PM_PEAK_LONE;
-            list = MyListAddPeak(list, 0, 0, image->data.F32[row][col], myPeakClass);
-            return(list);
-        } else {
-            return(NULL);
-        }
-    }
-
-    //
-    // Find peaks in row 0 only (single-row image).  This is a special case since
-    // we can not test data at image->data.F32[row+1][...])
-    //
-    if (image->numRows == 1) {
-        row = 0;
-        tmpRow = p_psGetRowVectorFromImage((psImage *) image, row);
-        psVector *row1 = pmFindVectorPeaks(tmpRow, threshold);
-        for (psU32 i = 0 ; i < row1->n ; i++ ) {
-            col = row1->data.U32[i];
-            //
-            // Determine if pixel (0,0) is a peak.
-            //
-            if (col == 0) {
-                if ( (image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >  image->data.F32[row][col+1])) {
-                    myPeakClass = PM_PEAK_EDGE | PM_PEAK_LONE;
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
-                }
-            } else if (col < (image->numCols - 1)) {
-
-                if ( (image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >= image->data.F32[row][col-1]) &&
-                        (image->data.F32[row][col] >  image->data.F32[row][col+1])) {
-                    myPeakClass = PM_PEAK_EDGE;
-
-                    if (image->data.F32[row][col] > image->data.F32[row][col-1]) {
-                        myPeakClass|= PM_PEAK_LONE;
-                    } else {
-                        myPeakClass|= PM_PEAK_FLAT;
-                    }
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
-                }
-
-            } else if (col == (image->numCols - 1)) {
-                if ( (image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >= image->data.F32[row][col-1])) {
-                    myPeakClass = PM_PEAK_EDGE;
-
-                    if (image->data.F32[row][col] > image->data.F32[row][col-1]) {
-                        myPeakClass|= PM_PEAK_LONE;
-                    } else {
-                        myPeakClass|= PM_PEAK_FLAT;
-                    }
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
-                }
-            } else {
-                psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");
-            }
-
-        }
-        //
-        // We exit here since this is a single-row image.
-        //
-        // XXX: Why are we not getting memory leak errors?
-        //
-        //
-        // psFree(tmpRow);
-        // psFree(row1);
-        //
-        return(list);
-    }
-
-    //
-    // Find peaks in col 0 only (single-col image).  This is a special case since
-    // we can not test data at image->data.F32[...][col+1])
-    //
-    if (image->numCols == 1) {
-        col = 0;
-        psVector *tmpCol = p_psGetColVectorFromImage((psImage *) image, col);
-        psVector *col1 = pmFindVectorPeaks(tmpCol, threshold);
-        for (psU32 i = 0 ; i < col1->n ; i++ ) {
-            row = col1->data.U32[i];
-            //
-            // Determine if pixel (0,0) is a peak.
-            //
-            if (row == 0) {
-                if ( (image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >  image->data.F32[row+1][col])) {
-                    myPeakClass = PM_PEAK_EDGE | PM_PEAK_LONE;
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
-                }
-            } else if (row < (image->numRows - 1)) {
-
-                if ( (image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >= image->data.F32[row-1][col]) &&
-                        (image->data.F32[row][col] >  image->data.F32[row+1][col])) {
-                    myPeakClass = PM_PEAK_EDGE;
-
-                    if (image->data.F32[row][col] > image->data.F32[row-1][col]) {
-                        myPeakClass|= PM_PEAK_LONE;
-                    } else {
-                        myPeakClass|= PM_PEAK_FLAT;
-                    }
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
-                }
-
-            } else if (row == (image->numRows - 1)) {
-                if ( (image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >= image->data.F32[row-1][col])) {
-                    myPeakClass = PM_PEAK_EDGE;
-
-                    if (image->data.F32[row][col] > image->data.F32[row-1][col]) {
-                        myPeakClass|= PM_PEAK_LONE;
-                    } else {
-                        myPeakClass|= PM_PEAK_FLAT;
-                    }
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
-                }
-            } else {
-                psError(PS_ERR_UNKNOWN, true, "peak specified outside valid row range.");
-            }
-
-        }
-        //
-        // We exit here since this is a single-column image.
-        //
-        // XXX: free tmpRow col1?
-        //
-        return(list);
-    }
-
-    //
-    // Find peaks in row 0 only (multi-row image).
+    psArray *list = NULL;
+
+    //
+    // Find peaks in row 0 only.
     //
     row = 0;
     tmpRow = p_psGetRowVectorFromImage((psImage *) image, row);
     psVector *row1 = pmFindVectorPeaks(tmpRow, threshold);
+
     for (psU32 i = 0 ; i < row1->n ; i++ ) {
         col = row1->data.U32[i];
@@ -472,52 +326,41 @@
         //
         if (col == 0) {
-            if ( (image->data.F32[row][col] > threshold) &&
-                    (image->data.F32[row][col] >  image->data.F32[row][col+1]) &&
+            if ( (image->data.F32[row][col] >  image->data.F32[row][col+1]) &&
                     (image->data.F32[row][col] >  image->data.F32[row+1][col]) &&
                     (image->data.F32[row][col] >= image->data.F32[row+1][col+1])) {
-                myPeakClass = PM_PEAK_EDGE;
-                if (image->data.F32[row][col] > image->data.F32[row+1][col+1]) {
-                    myPeakClass|= PM_PEAK_LONE;
-                } else {
-                    myPeakClass|= PM_PEAK_FLAT;
+                if (image->data.F32[row][col] > threshold) {
+                    list = MyListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
                 }
-                list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
             }
         } else if (col < (image->numCols - 1)) {
-            if ( (image->data.F32[row][col] > threshold) &&
-                    (image->data.F32[row][col] >= image->data.F32[row][col-1]) &&
+            if ( (image->data.F32[row][col] >= image->data.F32[row][col-1]) &&
                     (image->data.F32[row][col] >  image->data.F32[row][col+1]) &&
                     (image->data.F32[row][col] >= image->data.F32[row+1][col-1]) &&
                     (image->data.F32[row][col] >  image->data.F32[row+1][col]) &&
                     (image->data.F32[row][col] >= image->data.F32[row+1][col+1])) {
-
-                myPeakClass = PM_PEAK_EDGE;
-                if ( (image->data.F32[row][col] > image->data.F32[row][col-1]) &&
-                        (image->data.F32[row][col] > image->data.F32[row+1][col-1]) &&
-                        (image->data.F32[row][col] > image->data.F32[row+1][col+1])) {
-                    myPeakClass|= PM_PEAK_LONE;
-                } else {
-                    myPeakClass|= PM_PEAK_FLAT;
+                if (image->data.F32[row][col] > threshold) {
+                    list = MyListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
                 }
-                list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
             }
 
         } else if (col == (image->numCols - 1)) {
-            if ( (image->data.F32[row][col] > threshold) &&
-                    (image->data.F32[row][col] >= image->data.F32[row][col-1]) &&
+            if ( (image->data.F32[row][col] >= image->data.F32[row][col-1]) &&
                     (image->data.F32[row][col] > image->data.F32[row+1][col]) &&
                     (image->data.F32[row][col] >= image->data.F32[row+1][col-1])) {
-                myPeakClass = PM_PEAK_EDGE;
-                if ( (image->data.F32[row][col] > image->data.F32[row][col-1]) &&
-                        (image->data.F32[row][col] > image->data.F32[row+1][col-1])) {
-                    myPeakClass|= PM_PEAK_LONE;
-                } else {
-                    myPeakClass|= PM_PEAK_FLAT;
+                if (image->data.F32[row][col] > threshold) {
+                    list = MyListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
                 }
-                list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
             }
+
         } else {
-            psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");
-        }
+            psError(PS_ERR_UNKNOWN, true, "peak specified valid column range.");
+        }
+    }
+
+    //
+    // Exit if this image has a single row.
+    //
+    if (image->numRows == 1) {
+        return(list);
     }
 
@@ -531,30 +374,20 @@
         // Step through all local peaks in this row.
         for (psU32 i = 0 ; i < row1->n ; i++ ) {
+            psPeakType myType = PM_PEAK_UNDEF;
             col = row1->data.U32[i];
 
             if (col == 0) {
                 // If col==0, then we can not read col-1 pixels
-                if ((image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >  image->data.F32[row-1][col]) &&
+                if ((image->data.F32[row][col] >  image->data.F32[row-1][col]) &&
                         (image->data.F32[row][col] >= image->data.F32[row-1][col+1]) &&
                         (image->data.F32[row][col] >= image->data.F32[row][col+1]) &&
                         (image->data.F32[row][col] >= image->data.F32[row+1][col]) &&
                         (image->data.F32[row][col] >= image->data.F32[row+1][col+1])) {
-
-                    myPeakClass = PM_PEAK_EDGE;
-                    if ((image->data.F32[row][col] > image->data.F32[row-1][col+1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row][col+1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row+1][col]) &&
-                            (image->data.F32[row][col] > image->data.F32[row+1][col+1])) {
-                        myPeakClass|= PM_PEAK_LONE;
-                    } else {
-                        myPeakClass|= PM_PEAK_FLAT;
-                    }
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
+                    myType = PM_PEAK_EDGE;
+                    list = MyListAddPeak(list, row, col, image->data.F32[row][col], myType);
                 }
             } else if (col < (image->numCols - 1)) {
                 // This is an interior pixel
-                if ((image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >= image->data.F32[row-1][col-1]) &&
+                if ((image->data.F32[row][col] >= image->data.F32[row-1][col-1]) &&
                         (image->data.F32[row][col] >  image->data.F32[row-1][col]) &&
                         (image->data.F32[row][col] >= image->data.F32[row-1][col+1]) &&
@@ -564,22 +397,33 @@
                         (image->data.F32[row][col] >= image->data.F32[row+1][col]) &&
                         (image->data.F32[row][col] >= image->data.F32[row+1][col+1])) {
-
-                    if ((image->data.F32[row][col] > image->data.F32[row-1][col-1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row-1][col+1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row][col+1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row+1][col-1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row+1][col]) &&
-                            (image->data.F32[row][col] > image->data.F32[row+1][col+1])) {
-                        myPeakClass = PM_PEAK_LONE;
-                    } else {
-                        myPeakClass = PM_PEAK_FLAT;
+                    if (image->data.F32[row][col] > threshold) {
+                        if ((image->data.F32[row][col] > image->data.F32[row-1][col-1]) &&
+                                (image->data.F32[row][col] > image->data.F32[row-1][col]) &&
+                                (image->data.F32[row][col] > image->data.F32[row-1][col+1]) &&
+                                (image->data.F32[row][col] > image->data.F32[row][col-1]) &&
+                                (image->data.F32[row][col] > image->data.F32[row][col+1]) &&
+                                (image->data.F32[row][col] > image->data.F32[row+1][col-1]) &&
+                                (image->data.F32[row][col] > image->data.F32[row+1][col]) &&
+                                (image->data.F32[row][col] > image->data.F32[row+1][col+1])) {
+                            myType = PM_PEAK_LONE;
+                        }
+
+                        if ((image->data.F32[row][col] == image->data.F32[row-1][col-1]) ||
+                                (image->data.F32[row][col] == image->data.F32[row-1][col]) ||
+                                (image->data.F32[row][col] == image->data.F32[row-1][col+1]) ||
+                                (image->data.F32[row][col] == image->data.F32[row][col-1]) ||
+                                (image->data.F32[row][col] == image->data.F32[row][col+1]) ||
+                                (image->data.F32[row][col] == image->data.F32[row+1][col-1]) ||
+                                (image->data.F32[row][col] == image->data.F32[row+1][col]) ||
+                                (image->data.F32[row][col] == image->data.F32[row+1][col+1])) {
+                            myType = PM_PEAK_FLAT;
+                        }
+
+                        list = MyListAddPeak(list, row, col, image->data.F32[row][col], myType);
                     }
-
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
                 }
             } else if (col == (image->numCols - 1)) {
                 // If col==numCols - 1, then we can not read col+1 pixels
-                if ((image->data.F32[row][col] > threshold) &&
-                        (image->data.F32[row][col] >= image->data.F32[row-1][col-1]) &&
+                if ((image->data.F32[row][col] >= image->data.F32[row-1][col-1]) &&
                         (image->data.F32[row][col] >  image->data.F32[row-1][col]) &&
                         (image->data.F32[row][col] > image->data.F32[row][col-1]) &&
@@ -587,19 +431,11 @@
                         (image->data.F32[row][col] >= image->data.F32[row+1][col-1]) &&
                         (image->data.F32[row][col] >= image->data.F32[row+1][col])) {
-
-                    myPeakClass = PM_PEAK_EDGE;
-                    if ((image->data.F32[row][col] > image->data.F32[row-1][col-1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row][col+1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row+1][col-1]) &&
-                            (image->data.F32[row][col] > image->data.F32[row+1][col])) {
-                        myPeakClass|= PM_PEAK_LONE;
-                    } else {
-                        myPeakClass|= PM_PEAK_FLAT;
-                    }
-                    list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
+                    myType = PM_PEAK_EDGE;
+                    list = MyListAddPeak(list, row, col, image->data.F32[row][col], myType);
                 }
             } else {
-                psError(PS_ERR_UNKNOWN, true, "peak specified outside valid column range.");
+                psError(PS_ERR_UNKNOWN, true, "peak specified valid column range.");
             }
+
         }
     }
@@ -614,52 +450,29 @@
         col = row1->data.U32[i];
         if (col == 0) {
-            if ( (image->data.F32[row][col] > threshold) &&
-                    (image->data.F32[row][col] >  image->data.F32[row-1][col]) &&
+            if ( (image->data.F32[row][col] >  image->data.F32[row-1][col]) &&
                     (image->data.F32[row][col] >= image->data.F32[row-1][col+1]) &&
                     (image->data.F32[row][col] >  image->data.F32[row][col+1])) {
-
-                myPeakClass = PM_PEAK_EDGE;
-                if (image->data.F32[row][col] > image->data.F32[row-1][col+1]) {
-                    myPeakClass|= PM_PEAK_LONE;
-                } else {
-                    myPeakClass|= PM_PEAK_FLAT;
+                if (image->data.F32[row][col] > threshold) {
+                    list = MyListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
                 }
-
-                list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
             }
         } else if (col < (image->numCols - 1)) {
-            if ( (image->data.F32[row][col] > threshold) &&
-                    (image->data.F32[row][col] >= image->data.F32[row-1][col-1]) &&
+            if ( (image->data.F32[row][col] >= image->data.F32[row-1][col-1]) &&
                     (image->data.F32[row][col] >  image->data.F32[row-1][col]) &&
                     (image->data.F32[row][col] >= image->data.F32[row-1][col+1]) &&
                     (image->data.F32[row][col] >  image->data.F32[row][col-1]) &&
                     (image->data.F32[row][col] >= image->data.F32[row][col+1])) {
-
-                myPeakClass = PM_PEAK_EDGE;
-                if ( (image->data.F32[row][col] > image->data.F32[row-1][col-1]) &&
-                        (image->data.F32[row][col] > image->data.F32[row-1][col+1]) &&
-                        (image->data.F32[row][col] > image->data.F32[row][col+1])) {
-                    myPeakClass|= PM_PEAK_LONE;
-                } else {
-                    myPeakClass|= PM_PEAK_FLAT;
+                if (image->data.F32[row][col] > threshold) {
+                    list = MyListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
                 }
-
-                list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
             }
 
         } else if (col == (image->numCols - 1)) {
-            if ( (image->data.F32[row][col] > threshold) &&
-                    (image->data.F32[row][col] >= image->data.F32[row-1][col-1]) &&
+            if ( (image->data.F32[row][col] >= image->data.F32[row-1][col-1]) &&
                     (image->data.F32[row][col] >  image->data.F32[row-1][col]) &&
                     (image->data.F32[row][col] >  image->data.F32[row][col-1])) {
-
-                myPeakClass = PM_PEAK_EDGE;
-                if (image->data.F32[row][col] > image->data.F32[row-1][col-1]) {
-                    myPeakClass|= PM_PEAK_LONE;
-                } else {
-                    myPeakClass|= PM_PEAK_FLAT;
+                if (image->data.F32[row][col] > threshold) {
+                    list = MyListAddPeak(list, row, col, image->data.F32[row][col], PM_PEAK_EDGE);
                 }
-
-                list = MyListAddPeak(list, col, row, image->data.F32[row][col], myPeakClass);
             }
         } else {
@@ -667,24 +480,34 @@
         }
     }
-
     return(list);
 }
 
-
-/******************************************************************************
-PS_REGION_CHECK(VALID, X, Y): this macro evaluates to TRUE if the coordinate
-(X, Y) is within REGION, otherwise it evaluates to FALSE.
- *****************************************************************************/
-#define PS_REGION_CHECK(VALID, X, Y) \
-(((X) >= (VALID)->x0) && \
- ((X) <= (VALID)->x1) && \
- ((Y) >= (VALID)->y0) && \
- ((Y) <= (VALID)->y1))
-
-
-/******************************************************************************
-psCullPeaks(peaks, maxValue, valid): eliminate peaks from the psList that have
+// XXX: Macro this.
+bool IsItInThisRegion(const psRegion *valid,
+                      psS32 x,
+                      psS32 y)
+{
+
+    if ((x >= valid->x0) &&
+            (x <= valid->x1) &&
+            (y >= valid->y0) &&
+            (y <= valid->y1)) {
+        return(true);
+    }
+
+    return(false);
+}
+
+
+/******************************************************************************
+psCullPeaks(peaks, maxValue, valid): eliminate peaks from the psArray that have
 a peak value above the given maximum, or fall outside the valid region.
-  *****************************************************************************/
+ 
+XXX: Should the sky value be used when comparing the maximum?
+ 
+XXX: warning message if valid is NULL?
+ 
+XXX: changed API to create a NEW output psArray (should change name as well)
+*****************************************************************************/
 psList *pmCullPeaks(psList *peaks,
                     psF32 maxValue,
@@ -692,16 +515,15 @@
 {
     PS_PTR_CHECK_NULL(peaks, NULL);
-    if (valid == NULL) {
-        psLogMsg(__func__, PS_LOG_WARN, "WARNING: psRegion valid is NULL.  Ignoring ...\n");
-    }
+    //    PS_PTR_CHECK_NULL(valid, NULL);
 
     psListElem *tmpListElem = (psListElem *) peaks->head;
     psS32 indexNum = 0;
 
+    //    printf("pmCullPeaks(): list size is %d\n", peaks->size);
     while (tmpListElem != NULL) {
         psPeak *tmpPeak = (psPeak *) tmpListElem->data;
         if ((tmpPeak->counts > maxValue) ||
                 ((valid != NULL) &&
-                 (true == PS_REGION_CHECK(valid, tmpPeak->x, tmpPeak->y)))) {
+                 (true == IsItInThisRegion(valid, tmpPeak->x, tmpPeak->y)))) {
             psListRemoveData(peaks, (psPtr) tmpPeak);
         }
@@ -712,4 +534,28 @@
 
     return(peaks);
+}
+
+// XXX EAM: I changed this to return a new, subset array
+//          rather than alter the existing one
+psArray *pmPeaksSubset(psArray *peaks, psF32 maxValue, const psRegion *valid)
+{
+    PS_PTR_CHECK_NULL(peaks, NULL);
+
+    psArray *output = psArrayAlloc (200);
+    output->n = 0;
+
+    psTrace (".pmObjects.pmCullPeaks", 3, "list size is %d\n", peaks->n);
+
+    for (int i = 0; i < peaks->n; i++) {
+        psPeak *tmpPeak = (psPeak *) peaks->data[i];
+        if (tmpPeak->counts > maxValue)
+            continue;
+        if (valid != NULL) {
+            if (IsItInThisRegion(valid, tmpPeak->x, tmpPeak->y))
+                continue;
+        }
+        psArrayAdd (output, 200, tmpPeak);
+    }
+    return(output);
 }
 
@@ -726,4 +572,6 @@
 psImageStats on that subImage+mask.
  
+XXX: The subImage has width of 1+2*outerRadius.  Verify with IfA.
+ 
 XXX: Use static data structures for:
      subImage
@@ -748,5 +596,5 @@
 XXX: Don't use separate structs for the subimage and mask.  Use the source->
      members.
- *****************************************************************************/
+*****************************************************************************/
 psSource *pmSourceLocalSky(const psImage *image,
                            const psPeak *peak,
@@ -769,10 +617,13 @@
     // these variables should be renamed for clarity (imageCenterRow, etc).
     //
+    // peak->x,y is guaranteed to be on image
     psS32 SubImageCenterRow = peak->y;
     psS32 SubImageCenterCol = peak->x;
-    psS32 SubImageStartRow = PS_MAX(SubImageCenterRow - outerRadiusS32, 0);
-    psS32 SubImageEndRow =   PS_MIN(SubImageCenterRow + outerRadiusS32, image->numRows - 1);
-    psS32 SubImageStartCol = PS_MAX(SubImageCenterCol - outerRadiusS32, 0);
-    psS32 SubImageEndCol =   PS_MIN(SubImageCenterCol + outerRadiusS32, image->numCols - 1);
+
+    // XXX EAM : I added this code to stay on the image. So did George
+    psS32 SubImageStartRow  = PS_MAX (0, SubImageCenterRow - outerRadiusS32);
+    psS32 SubImageEndRow    = PS_MIN (image->numRows - 1, SubImageCenterRow + outerRadiusS32);
+    psS32 SubImageStartCol  = PS_MAX (0, SubImageCenterCol - outerRadiusS32);
+    psS32 SubImageEndCol    = PS_MIN (image->numCols - 1, SubImageCenterCol + outerRadiusS32);
     // AnulusWidth == number of pixels width in the annulus.  We add one since
     // the pixels at the inner AND outher radius are included.
@@ -785,9 +636,12 @@
     //    printf("pmSourceLocalSky(): AnulusWidth is %d\n", AnulusWidth);
 
-    if (SubImageStartRow < 0) {
-        psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n",
-                SubImageStartRow);
-        return(NULL);
-    }
+    // XXX EAM : these tests should not be needed: we can never hit this error because of above
+    # if (1)
+
+        if (SubImageStartRow < 0) {
+            psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n",
+                    SubImageStartRow);
+            return(NULL);
+        }
     if (SubImageEndRow >= image->numRows) {
         psError(PS_ERR_UNKNOWN, true, "Sub image endRow is outside image boundaries (%d).\n",
@@ -805,4 +659,5 @@
         return(NULL);
     }
+    # endif
 
     //
@@ -830,4 +685,5 @@
     //
     // Loop through the subimage, mask off pixels in the inner square.
+    // XXX this uses a static mask value of 1
     //
     for (psS32 row = AnulusWidth; row <= (subImageMask->numRows - AnulusWidth) - 1; row++) {
@@ -873,19 +729,41 @@
 
 /******************************************************************************
-bool PS_RADIUS_CHECK(): a macro which evaluates to TRUE if the (x, y) point is
-within the radius of the specified peak.
-  *****************************************************************************/
-#define PS_RADIUS_CHECK(PEAK, RADIUS, X, Y) \
-(PS_SQR((RADIUS)) >= ((psF32) (PS_SQR((X) - (PEAK)->x) + PS_SQR((Y) - (PEAK)->y))))
-
-
-/******************************************************************************
-bool PS_RADIUS_CHECK22(): a macro which evaluates to TRUE if the (x, y) point
-is within the radius of the specified point.
-  *****************************************************************************/
-#define PS_RADIUS_CHECK2(X_CENTER, Y_CENTER, RADIUS, X, Y) \
-(PS_SQR((RADIUS)) >= ((psF32) (PS_SQR((X) - (X_CENTER)) + PS_SQR((Y) - (Y_CENTER)))))
-
-
+bool CheckRadius(*peak, radius, x, y): private function which simply
+determines if the (x, y) point is within the radius of the specified peak.
+ 
+XXX: macro this for performance.
+*****************************************************************************/
+bool CheckRadius(psPeak *peak,
+                 psF32 radius,
+                 psS32 x,
+                 psS32 y)
+{
+    if (PS_SQR(radius) >= (psF32) (PS_SQR(x - peak->x) + PS_SQR(y - peak->y))) {
+        return(true);
+    }
+
+    return(false);
+}
+
+/******************************************************************************
+bool CheckRadius2(): private function which simply determines if the (x, y)
+point is within the radius of the specified peak.
+ 
+XXX: macro this for performance.
+XXX: this is rather inefficient - at least compute and compare against radius^2
+*****************************************************************************/
+bool CheckRadius2(psF32 xCenter,
+                  psF32 yCenter,
+                  psF32 radius,
+                  psF32 x,
+                  psF32 y)
+{
+    /// XXX EAM should compare with hypot (x,y) for speed
+    if ((PS_SQR(x - xCenter) + PS_SQR(y - yCenter)) < PS_SQR(radius)) {
+        return(true);
+    }
+
+    return(false);
+}
 
 /******************************************************************************
@@ -899,6 +777,8 @@
     psSource->pixels
  
+XXX: The peak calculations are done in image coords, not subImage coords.
+ 
 XXX: mask values?
- *****************************************************************************/
+*****************************************************************************/
 psSource *pmSourceMoments(psSource *source,
                           psF32 radius)
@@ -909,9 +789,10 @@
     PS_FLOAT_COMPARE(0.0, radius, NULL);
 
+    //
+    // XXX: Verify the setting for sky if source->moments == NULL.
+    //
     psF32 sky = 0.0;
     if (source->moments == NULL) {
-        psError(PS_ERR_UNKNOWN, true, "Undefined source->psMoments is NULL");
-        psFree(source);
-        return(NULL);
+        source->moments = pmMomentsAlloc();
     } else {
         sky = source->moments->Sky;
@@ -932,8 +813,14 @@
     psF32 Y2 = 0.0;
     psF32 XY = 0.0;
-    //
+    psF32 x = 0;
+    psF32 y = 0;
+    //
+    // XXX why do I get different results for these two methods of finding Sx?
+    // XXX Sx, Sy would be better measured if we clip pixels close to sky
+    // XXX Sx, Sy can still be imaginary, so we probably need to keep Sx^2?
     // We loop through all pixels in this subimage (source->pixels), and for each
     // pixel that is not masked, AND within the radius of the peak pixel, we
-    // proceed with the moments calculation.
+    // proceed with the moments calculation.  need to do two loops for a
+    // numerically stable result.  first loop: get the sums.
     //
     for (psS32 row = 0; row < source->pixels->numRows ; row++) {
@@ -942,8 +829,8 @@
                 psS32 imgColCoord = col + source->pixels->col0;
                 psS32 imgRowCoord = row + source->pixels->row0;
-                if (PS_RADIUS_CHECK(source->peak,
-                                    radius,
-                                    imgColCoord,
-                                    imgRowCoord)) {
+                if (CheckRadius(source->peak,
+                                radius,
+                                imgColCoord,
+                                imgRowCoord)) {
                     psF32 xDiff = (psF32) (imgColCoord - source->peak->x);
                     psF32 yDiff = (psF32) (imgRowCoord - source->peak->y);
@@ -953,7 +840,8 @@
                     X1+= xDiff * pDiff;
                     Y1+= yDiff * pDiff;
+                    XY+= xDiff * yDiff * pDiff;
+
                     X2+= PS_SQR(xDiff) * pDiff;
                     Y2+= PS_SQR(yDiff) * pDiff;
-                    XY+= xDiff * yDiff * pDiff;
 
                     if (source->pixels->data.F32[row][col] > peakPixel) {
@@ -971,13 +859,84 @@
     // Sxy             = XY / Sum
     //
-    source->moments->x = X1/Sum + ((psF32) source->peak->x);
-    source->moments->y = Y1/Sum + ((psF32) source->peak->y);
-    source->moments->Sx = sqrt(X2/Sum - PS_SQR(X1/Sum));
-    source->moments->Sy = sqrt(Y2/Sum - PS_SQR(Y1/Sum));
+    x = X1/Sum;
+    y = Y1/Sum;
+    source->moments->x = x + ((psF32) source->peak->x);
+    source->moments->y = y + ((psF32) source->peak->y);
+
     source->moments->Sxy = XY/Sum;
+    source->moments->Sum = Sum;
     source->moments->Peak = peakPixel;
     source->moments->nPixels = numPixels;
 
+    // XXX EAM : these values can be negative, so we need to limit the range
+    source->moments->Sx = sqrt(PS_MAX(X2/Sum - PS_SQR(x), 0));
+    source->moments->Sy = sqrt(PS_MAX(Y2/Sum - PS_SQR(y), 0));
     return(source);
+
+    // XXX EAM : the following code should be the same as above, but it is not very stable: ignore it
+    # if (0)
+        //
+        // second loop: get the difference sums
+        //
+        X2 = Y2 = 0;
+    for (psS32 row = 0; row < source->pixels->numRows ; row++) {
+        for (psS32 col = 0; col < source->pixels->numCols ; col++) {
+            if ((source->mask != NULL) && (source->mask->data.U8[row][col] != 0)) {
+                psS32 imgColCoord = col + source->pixels->col0;
+                psS32 imgRowCoord = row + source->pixels->row0;
+                if (CheckRadius(source->peak,
+                                radius,
+                                imgColCoord,
+                                imgRowCoord)) {
+                    psF32 xDiff = (psF32) (imgColCoord - source->peak->x);
+                    psF32 yDiff = (psF32) (imgRowCoord - source->peak->y);
+                    psF32 pDiff = source->pixels->data.F32[row][col] - sky;
+
+                    Sum+= pDiff;
+                    X2+= PS_SQR(xDiff - x) * pDiff;
+                    Y2+= PS_SQR(yDiff - y) * pDiff;
+                }
+            }
+        }
+    }
+
+    //
+    // second moment X = sqrt (X2/Sum)
+    //
+    source->moments->Sx = (X2/Sum);
+    source->moments->Sy = (Y2/Sum);
+    return(source);
+    # endif
+}
+
+// XXX EAM : I used
+int pmComparePeakAscend (const void **a, const void **b)
+{
+    psPeak *A = *(psPeak **)a;
+    psPeak *B = *(psPeak **)b;
+
+    psF32 diff;
+
+    diff = A->counts - B->counts;
+    if (diff < FLT_EPSILON)
+        return (-1);
+    if (diff > FLT_EPSILON)
+        return (+1);
+    return (0);
+}
+
+int pmComparePeakDescend (const void **a, const void **b)
+{
+    psPeak *A = *(psPeak **)a;
+    psPeak *B = *(psPeak **)b;
+
+    psF32 diff;
+
+    diff = A->counts - B->counts;
+    if (diff < FLT_EPSILON)
+        return (+1);
+    if (diff > FLT_EPSILON)
+        return (-1);
+    return (0);
 }
 
@@ -990,80 +949,240 @@
  
 XXX: The sigX and sigY stuff in the SDRS is unclear.
- *****************************************************************************/
-#define SATURATE 0.0
-#define FAINT_SN_LIM 0.0
-#define PSF_SN_LIM 0.0
-#define SATURATE 0.0
-#define SATURATE 0.0
-
-bool pmSourceRoughClass(psArray *source,
-                        psMetadata *metadata)
-{
-    PS_PTR_CHECK_NULL(source, false);
+ 
+XXX: How can this function ever return FALSE?
+*****************************************************************************/
+
+# define NPIX 10
+# define SCALE 0.1
+
+// XXX I am ignore memory freeing issues (EAM)
+bool pmSourceRoughClass(psArray *sources, psMetadata *metadata)
+{
+    PS_PTR_CHECK_NULL(sources, false);
     PS_PTR_CHECK_NULL(metadata, false);
     psBool rc = true;
-
-    for (psS32 i = 0 ; i < source->n ; i++) {
-        psSource *tmpSrc = (psSource *) source->data[i];
-        PS_PTR_CHECK_NULL(tmpSrc->moments, false);
+    psArray *peaks  = NULL;
+    psF32 clumpX = 0.0;
+    psF32 clumpDX = 0.0;
+    psF32 clumpY = 0.0;
+    psF32 clumpDY = 0.0;
+
+    // find the sigmaX, sigmaY clump
+    {
+        psStats *stats  = NULL;
+        psImage *splane = NULL;
+        int binX, binY;
+
+        // construct a sigma-plane image
+        splane = psImageAlloc (NPIX/SCALE, NPIX/SCALE, PS_TYPE_F32);
+
+        // place the sources in the sigma-plane image (ignore 0,0 values?)
+        for (psS32 i = 0 ; i < sources->n ; i++)
+        {
+            psSource *tmpSrc = (psSource *) sources->data[i];
+            PS_PTR_CHECK_NULL(tmpSrc, false); // just skip this one?
+            PS_PTR_CHECK_NULL(tmpSrc->moments, false); // just skip this one?
+
+            // Sx,Sy are limited at 0.  a peak at 0,0 is artificial
+            if ((fabs(tmpSrc->moments->Sx) < FLT_EPSILON) && (fabs(tmpSrc->moments->Sy) < FLT_EPSILON)) {
+                continue;
+            }
+
+            // for the moment, force splane dimensions to be 10x10 image pix
+            binX = tmpSrc->moments->Sx/SCALE;
+            if (binX < 0)
+                continue;
+            if (binX >= splane->numCols)
+                continue;
+
+            binY = tmpSrc->moments->Sy/SCALE;
+            if (binY < 0)
+                continue;
+            if (binY >= splane->numRows)
+                continue;
+
+            splane->data.F32[binY][binX] += 1.0;
+        }
+
+        // find the peak in this image
+        stats = psStatsAlloc (PS_STAT_MAX);
+        stats = psImageStats (stats, splane, NULL, 0);
+        peaks = pmFindImagePeaks (splane, stats[0].max / 2);
+        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump threshold is %f\n", stats[0].max/2);
+
+    }
+
+    // measure statistics on Sx, Sy if Sx, Sy within range of clump
+    {
+        psPeak *clump;
+        psF32 minSx, maxSx;
+        psF32 minSy, maxSy;
+        psVector *tmpSx = NULL;
+        psVector *tmpSy = NULL;
+        psStats *stats  = NULL;
+
+        // XXX EAM : this lets us takes the single highest peak
+        psArraySort (peaks, pmComparePeakDescend);
+        clump = peaks->data[0];
+        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump is at %d, %d\n", clump->x, clump->y);
+
+        // define section window for clump
+        minSx = clump->x * SCALE - 0.2;
+        maxSx = clump->x * SCALE + 0.2;
+        minSy = clump->y * SCALE - 0.2;
+        maxSy = clump->y * SCALE + 0.2;
+
+        tmpSx = psVectorAlloc (sources->n, PS_TYPE_F32);
+        tmpSy = psVectorAlloc (sources->n, PS_TYPE_F32);
+        tmpSx->n = 0;
+        tmpSy->n = 0;
+
+        // XXX clip sources based on flux?
+        // create vectors with Sx, Sy values in window
+        for (psS32 i = 0 ; i < sources->n ; i++)
+        {
+            psSource *tmpSrc = (psSource *) sources->data[i];
+
+            if (tmpSrc->moments->Sx < minSx)
+                continue;
+            if (tmpSrc->moments->Sx > maxSx)
+                continue;
+            if (tmpSrc->moments->Sy < minSy)
+                continue;
+            if (tmpSrc->moments->Sy > maxSy)
+                continue;
+            tmpSx->data.F32[tmpSx->n] = tmpSrc->moments->Sx;
+            tmpSy->data.F32[tmpSy->n] = tmpSrc->moments->Sy;
+            tmpSx->n++;
+            tmpSy->n++;
+            if (tmpSx->n == tmpSx->nalloc) {
+                psVectorRealloc (tmpSx, tmpSx->nalloc + 100);
+                psVectorRealloc (tmpSy, tmpSy->nalloc + 100);
+            }
+        }
+
+        // measures stats of Sx, Sy
+        stats = psStatsAlloc (PS_STAT_CLIPPED_MEAN | PS_STAT_CLIPPED_STDEV);
+
+        stats = psVectorStats (stats, tmpSx, NULL, NULL, 0);
+        clumpX  = stats->clippedMean;
+        clumpDX = stats->clippedStdev;
+
+        stats = psVectorStats (stats, tmpSy, NULL, NULL, 0);
+        clumpY  = stats->clippedMean;
+        clumpDY = stats->clippedStdev;
+
+        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump  X,  Y: %f, %f\n", clumpX, clumpY);
+        psTrace (".pmObjects.pmSourceRoughClass", 2, "clump DX, DY: %f, %f\n", clumpDX, clumpDY);
+        // these values should be pushed on the metadata somewhere
+    }
+
+    int Nsat   = 0;
+    int Ngal   = 0;
+    int Nfaint = 0;
+    int Nstar  = 0;
+    int Npsf   = 0;
+    int Ncr    = 0;
+    psVector *starsn = psVectorAlloc (sources->n, PS_TYPE_F32);
+    starsn->n = 0;
+
+    // XXX allow clump size to be scaled relative to sigmas?
+    // make rough IDs based on clumpX,Y,DX,DY
+    for (psS32 i = 0 ; i < sources->n ; i++) {
+
+        psSource *tmpSrc = (psSource *) sources->data[i];
+
         tmpSrc->peak->class = 0;
 
-        psF32 sigX = 0.0;
-        psF32 sigY = 0.0;
-        // XXX: gleen these from the metadata: keywords GAIN and READ_NOISE.
-        psF32 clumpX = 0.0;
-        psF32 clumpDX = 0.0;
-        psF32 clumpY = 0.0;
-        psF32 clumpDY = 0.0;
-
+        psF32 sigX = tmpSrc->moments->Sx;
+        psF32 sigY = tmpSrc->moments->Sy;
+
+        // check return status value (do these exist?)
+        bool status;
+        psF32 RDNOISE  = psMetadataLookupF32 (&status, metadata, "RDNOISE");
+        psF32 GAIN     = psMetadataLookupF32 (&status, metadata, "GAIN");
+        psF32 SATURATE = psMetadataLookupF32 (&status, metadata, "SATURATE");
+
+        psF32 PSF_SN_LIM   = psMetadataLookupF32 (&status, metadata, "PSF_SN_LIM");
+        psF32 FAINT_SN_LIM = psMetadataLookupF32 (&status, metadata, "FAINT_SN_LIM");
+
+        // saturated object (star or single pixel not distinguished)
         if (tmpSrc->moments->Peak > SATURATE) {
-            tmpSrc->peak->class|= PS_SOURCE_SATURATED;
-        } else {
-            // XXX: gleen these from the metadata: keywords GAIN and READ_NOISE.
-            psF32 gain = 0.0;
-            psF32 readNoise = 0.0;
-            psF32 S = tmpSrc->moments->Sum;
-            psF32 A = PS_PI * tmpSrc->moments->Sx * tmpSrc->moments->Sy;
-            psF32 B = tmpSrc->moments->Sky;
-            psF32 SN = (PS_SQRT_F32(gain) * S) /
-                       PS_SQRT_F32(S + (A * B) + ((A * readNoise * readNoise) / PS_SQRT_F32(gain)));
-            if (SN < FAINT_SN_LIM) {
-                tmpSrc->peak->class|= PS_SOURCE_FAINTSTAR;
-            }
-            if (SN < PSF_SN_LIM) {
-                tmpSrc->peak->class|= PS_SOURCE_FAINTSTAR;
-            }
-            // XXX: The SDRS is not real clear on how to calculate sigX, sigY.
-            if ((fabs(sigX - clumpX) < clumpDX) &&
-                    (fabs(sigY - clumpY) < clumpDY)) {
-                tmpSrc->peak->class|= PS_SOURCE_PSFSTAR;
-            }
-
-            if ((sigX < (clumpX - clumpDX)) &&
-                    (sigY < (clumpY - clumpDY)))
-                tmpSrc->peak->class|= PS_SOURCE_DEFECT;
-        }
-
-        if ((sigX > (clumpX + clumpDX)) &&
-                (sigY > (clumpY + clumpDY))) {
-            tmpSrc->peak->class|= PS_SOURCE_GALAXY;
-        }
-
-        if (tmpSrc->peak->class == 0) {
-            tmpSrc->peak->class|= PS_SOURCE_OTHER;
-        }
-    }
+            tmpSrc->type |= PS_SOURCE_SATURATED;
+            Nsat ++;
+            continue;
+        }
+
+        // too small to be stellar
+        if ((sigX < (clumpX - clumpDX)) || (sigY < (clumpY - clumpDY))) {
+            tmpSrc->type |= PS_SOURCE_DEFECT;
+            Ncr ++;
+            continue;
+        }
+
+        // possible galaxy
+        if ((sigX > (clumpX + clumpDX)) || (sigY > (clumpY + clumpDY))) {
+            tmpSrc->type |= PS_SOURCE_GALAXY;
+            Ngal ++;
+            continue;
+        }
+
+        // the rest are probable stellar objects
+        psF32 S  = tmpSrc->moments->Sum;
+        psF32 A  = PS_PI * sigX * sigY;
+        psF32 B  = tmpSrc->moments->Sky;
+        psF32 RT = PS_SQRT_F32(S + (A * B) + (A * PS_SQR(RDNOISE) / PS_SQRT_F32(GAIN)));
+        psF32 SN = (S * PS_SQRT_F32(GAIN) / RT);
+
+        starsn->data.F32[starsn->n] = SN;
+        starsn->n ++;
+        Nstar ++;
+
+        // faint star
+        if (SN < FAINT_SN_LIM) {
+            tmpSrc->type |= PS_SOURCE_FAINTSTAR;
+            Nfaint ++;
+            continue;
+        }
+
+        // PSF star
+        if (SN > PSF_SN_LIM) {
+            tmpSrc->type |= PS_SOURCE_PSFSTAR;
+            Npsf ++;
+            continue;
+        }
+
+        // random type of star
+        tmpSrc->type |= PS_SOURCE_OTHER;
+    }
+
+    {
+        psStats *stats  = NULL;
+        stats = psStatsAlloc (PS_STAT_MIN | PS_STAT_MAX);
+        stats = psVectorStats (stats, starsn, NULL, NULL, 0);
+        psLogMsg ("pmObjects", 3, "SN range: %f - %f\n", stats[0].min, stats[0].max);
+    }
+
+    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nstar:  %3d\n", Nstar);
+    psTrace (".pmObjects.pmSourceRoughClass", 2, "Npsf:   %3d\n", Npsf);
+    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nfaint: %3d\n", Nfaint);
+    psTrace (".pmObjects.pmSourceRoughClass", 2, "Ngal:   %3d\n", Ngal);
+    psTrace (".pmObjects.pmSourceRoughClass", 2, "Nsat:   %3d\n", Nsat);
+    psTrace (".pmObjects.pmSourceRoughClass", 2, "Ncr:    %3d\n", Ncr);
 
     return(rc);
 }
 
-
-
 /******************************************************************************
 pmSourceSetPixelCircle(source, image, radius)
  
-XXX: Checking source->moments for NULL.  Circle must be centered on the
-     centroid, not peak (from IfA 2005-04-06).
- *****************************************************************************/
+XXX: Why boolean output?
+ 
+XXX: Why are we checking source->moments for NULL?  Should the circle be
+     centered on the centroid or the peak?
+ 
+XXX: The circle will have a diameter of (1+radius).  This is different from
+     the pmSourceSetLocal() function.
+*****************************************************************************/
 bool pmSourceSetPixelCircle(psSource *source,
                             const psImage *image,
@@ -1073,6 +1192,6 @@
     PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
     PS_PTR_CHECK_NULL(source, false);
-    //    PS_PTR_CHECK_NULL(source->moments, false);
-    PS_PTR_CHECK_NULL(source->peak, false);
+    PS_PTR_CHECK_NULL(source->moments, false);
+    // PS_PTR_CHECK_NULL(source->peak, false);
     PS_FLOAT_COMPARE(0.0, radius, false);
 
@@ -1086,15 +1205,19 @@
     psS32 SubImageCenterRow = source->peak->y;
     psS32 SubImageCenterCol = source->peak->x;
-    psS32 SubImageStartRow = SubImageCenterRow - radiusS32;
-    psS32 SubImageEndRow = SubImageCenterRow + radiusS32;
-    psS32 SubImageStartCol = SubImageCenterCol - radiusS32;
-    psS32 SubImageEndCol = SubImageCenterCol + radiusS32;
-
-    if (SubImageStartRow < 0) {
-        psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n",
-                SubImageStartRow);
-        return(false);
-    }
-    if (SubImageEndRow+1 >= image->numRows) {
+    // XXX EAM : for the circle to stay on the image
+    psS32 SubImageStartRow  = PS_MAX (0, SubImageCenterRow - radiusS32);
+    psS32 SubImageEndRow    = PS_MIN (image->numRows - 1, SubImageCenterRow + radiusS32);
+    psS32 SubImageStartCol  = PS_MAX (0, SubImageCenterCol - radiusS32);
+    psS32 SubImageEndCol    = PS_MIN (image->numCols - 1, SubImageCenterCol + radiusS32);
+
+    // XXX EAM : this should not be needed: we can never hit this error
+    # if (1)
+
+        if (SubImageStartRow < 0) {
+            psError(PS_ERR_UNKNOWN, true, "Sub image startRow is outside image boundaries (%d).\n",
+                    SubImageStartRow);
+            return(false);
+        }
+    if (SubImageEndRow >= image->numRows) {
         psError(PS_ERR_UNKNOWN, true, "Sub image endRow is outside image boundaries (%d).\n",
                 SubImageEndRow);
@@ -1106,13 +1229,16 @@
         return(false);
     }
-    if (SubImageEndCol+1 >= image->numCols) {
+    if (SubImageEndCol >= image->numCols) {
         psError(PS_ERR_UNKNOWN, true, "Sub image endCol is outside image boundaries (%d).\n",
                 SubImageEndCol);
         return(false);
     }
+    # endif
 
     // XXX: Must recycle image.
+    // XXX EAM: this message reflects a programming error we know about.
+    //          i am setting it to a trace message which we can take out
     if (source->pixels != NULL) {
-        psLogMsg(__func__, PS_LOG_WARN,
+        psTrace (".psModule.pmObjects.pmSourceSetPixelCircle", 4,
                  "WARNING: pmSourceSetPixelCircle(): image->pixels not NULL.  Freeing and reallocating.\n");
         psFree(source->pixels);
@@ -1121,6 +1247,6 @@
                                    SubImageStartCol,
                                    SubImageStartRow,
-                                   SubImageEndCol+1,
-                                   SubImageEndRow+1);
+                                   SubImageEndCol,
+                                   SubImageEndRow);
 
     // XXX: Must recycle image.
@@ -1128,22 +1254,22 @@
         psFree(source->mask);
     }
-    source->mask = psImageAlloc(1 + 2 * radiusS32,
-                                1 + 2 * radiusS32,
+    source->mask = psImageAlloc(source->pixels->numCols,
+                                source->pixels->numRows,
                                 PS_TYPE_F32);
 
     //
     // Loop through the subimage mask, initialize mask to 0 or 1.
-    //
+    // XXX EAM: valid pixels should have 0, not 1
     for (psS32 row = 0 ; row < source->mask->numRows; row++) {
         for (psS32 col = 0 ; col < source->mask->numCols; col++) {
 
-            if (PS_RADIUS_CHECK2((psF32) radiusS32,
-                                 (psF32) radiusS32,
-                                 radius,
-                                 (psF32) col,
-                                 (psF32) row)) {
+            if (CheckRadius2((psF32) radiusS32,
+                             (psF32) radiusS32,
+                             radius,
+                             (psF32) col,
+                             (psF32) row)) {
+                source->mask->data.U8[row][col] = 0;
+            } else {
                 source->mask->data.U8[row][col] = 1;
-            } else {
-                source->mask->data.U8[row][col] = 0;
             }
         }
@@ -1151,5 +1277,4 @@
     return(true);
 }
-
 
 /******************************************************************************
@@ -1168,5 +1293,5 @@
 image, not subImage coords.  Therefore, the calls to the model evaluation
 functions will be in image, not subImage coords.  Remember this.
- *****************************************************************************/
+*****************************************************************************/
 bool pmSourceModelGuess(psSource *source,
                         const psImage *image,
@@ -1184,48 +1309,35 @@
     source->models = pmModelAlloc(model);
 
+    psVector *params = source->models->params;
+
     switch (model) {
     case PS_MODEL_GAUSS:
-        source->models->params[0] = source->moments->Sky;
-        source->models->params[1] = source->peak->counts - source->moments->Sky;
-        source->models->params[2] = source->moments->x;
-        source->models->params[3] = source->moments->y;
-        source->models->params[4] = sqrt(2.0) / source->moments->Sx;
-        source->models->params[5] = sqrt(2.0) / source->moments->Sy;
-        source->models->params[6] = source->moments->Sxy;
+        params->data.F32[0] = source->moments->Sky;
+        params->data.F32[1] = source->peak->counts - source->moments->Sky;
+        params->data.F32[2] = source->moments->x;
+        params->data.F32[3] = source->moments->y;
+        params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
+        params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
+        params->data.F32[6] = source->moments->Sxy;
         return(true);
 
     case PS_MODEL_PGAUSS:
-        source->models->params[0] = source->moments->Sky;
-        source->models->params[1] = source->peak->counts - source->moments->Sky;
-        source->models->params[2] = source->moments->x;
-        source->models->params[3] = source->moments->y;
-        source->models->params[4] = sqrt(2.0) / source->moments->Sx;
-        source->models->params[5] = sqrt(2.0) / source->moments->Sy;
-        source->models->params[6] = source->moments->Sxy;
+        params->data.F32[0] = source->moments->Sky;
+        params->data.F32[1] = source->peak->counts - source->moments->Sky;
+        params->data.F32[2] = source->moments->x;
+        params->data.F32[3] = source->moments->y;
+        params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
+        params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
+        params->data.F32[6] = source->moments->Sxy;
         return(true);
 
-    case PS_MODEL_TWIST_GAUSS:
-        source->models->params[0] = source->moments->Sky;
-        source->models->params[1] = source->peak->counts - source->moments->Sky;
-        source->models->params[2] = source->moments->x;
-        source->models->params[3] = source->moments->y;
-        // XXX: What are these?
-        // source->models->params[4] = SxInner;
-        // source->models->params[5] = SyInner;
-        // source->models->params[6] = SxyInner;
-        // source->models->params[7] = SxOuter;
-        // source->models->params[8] = SyOuter;
-        // source->models->params[9] = SxyOuter;
-        // source->models->params[10] = N;
-        return(true);
-
     case PS_MODEL_WAUSS:
-        source->models->params[0] = source->moments->Sky;
-        source->models->params[1] = source->peak->counts - source->moments->Sky;
-        source->models->params[2] = source->moments->x;
-        source->models->params[3] = source->moments->y;
-        source->models->params[4] = sqrt(2.0) / source->moments->Sx;
-        source->models->params[5] = sqrt(2.0) / source->moments->Sy;
-        source->models->params[6] = source->moments->Sxy;
+        params->data.F32[0] = source->moments->Sky;
+        params->data.F32[1] = source->peak->counts - source->moments->Sky;
+        params->data.F32[2] = source->moments->x;
+        params->data.F32[3] = source->moments->y;
+        params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
+        params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
+        params->data.F32[6] = source->moments->Sxy;
         // XXX: What are these?
         // source->models->params[7] = B2;
@@ -1233,30 +1345,46 @@
         return(true);
 
+        // XXX EAM : I might drop this model (or rather, replace it)
+    case PS_MODEL_TWIST_GAUSS:
+        params->data.F32[0] = source->moments->Sky;
+        params->data.F32[1] = source->peak->counts - source->moments->Sky;
+        params->data.F32[2] = source->moments->x;
+        params->data.F32[3] = source->moments->y;
+        // XXX: What are these?
+        // params->data.F32[4] = SxInner;
+        // params->data.F32[5] = SyInner;
+        // params->data.F32[6] = SxyInner;
+        // params->data.F32[7] = SxOuter;
+        // params->data.F32[8] = SyOuter;
+        // params->data.F32[9] = SxyOuter;
+        // params->data.F32[10] = N;
+        return(true);
+
     case PS_MODEL_SERSIC:
-        source->models->params[0] = source->moments->Sky;
-        source->models->params[1] = source->peak->counts - source->moments->Sky;
-        source->models->params[2] = source->moments->x;
-        source->models->params[3] = source->moments->y;
-        source->models->params[4] = sqrt(2.0) / source->moments->Sx;
-        source->models->params[5] = sqrt(2.0) / source->moments->Sy;
-        source->models->params[6] = source->moments->Sxy;
+        params->data.F32[0] = source->moments->Sky;
+        params->data.F32[1] = source->peak->counts - source->moments->Sky;
+        params->data.F32[2] = source->moments->x;
+        params->data.F32[3] = source->moments->y;
+        params->data.F32[4] = sqrt(2.0) / source->moments->Sx;
+        params->data.F32[5] = sqrt(2.0) / source->moments->Sy;
+        params->data.F32[6] = source->moments->Sxy;
         // XXX: What are these?
-        //source->models->params[7] = Nexp;
+        //params->data.F32[7] = Nexp;
         return(true);
 
     case PS_MODEL_SERSIC_CORE:
-        source->models->params[0] = source->moments->Sky;
-        source->models->params[1] = source->peak->counts - source->moments->Sky;
-        source->models->params[2] = source->moments->x;
-        source->models->params[3] = source->moments->y;
+        params->data.F32[0] = source->moments->Sky;
+        params->data.F32[1] = source->peak->counts - source->moments->Sky;
+        params->data.F32[2] = source->moments->x;
+        params->data.F32[3] = source->moments->y;
         // XXX: What are these?
-        //source->models->params[4] SxInner;
-        //source->models->params[5] SyInner;
-        //source->models->params[6] SxyInner;
-        //source->models->params[7] Zd;
-        //source->models->params[8] SxOuter;
-        //source->models->params[9] SyOuter;
-        //source->models->params[10] = SxyOuter;
-        //source->models->params[11] = Nexp;
+        // params->data.F32[4] SxInner;
+        // params->data.F32[5] SyInner;
+        // params->data.F32[6] SxyInner;
+        // params->data.F32[7] Zd;
+        // params->data.F32[8] SxOuter;
+        // params->data.F32[9] SyOuter;
+        // params->data.F32[10] = SxyOuter;
+        // params->data.F32[11] = Nexp;
         return(true);
 
@@ -1268,5 +1396,5 @@
 
 /******************************************************************************
-evalModel(src, col, row): a private function which evaluates the
+evalModel(source, level, row): a private function which evaluates the
 source->model function at the specified coords.  The coords are subImage, not
 image coords.
@@ -1274,4 +1402,6 @@
 NOTE: The coords are in subImage source->pixel coords, not image coords.
  
+XXX: reverse order of row,col args?
+ 
 XXX: rename all coords in this file such that their name defines whether
 the coords is in subImage or image space.
@@ -1285,8 +1415,8 @@
 XXX: For a while, the first psVectorAlloc() was generating a seg fault during
 testing.  Try to reproduce that and debug.
- *****************************************************************************/
-psF32 evalModel(psSource *src,
-                psU32 col,
-                psU32 row)
+*****************************************************************************/
+static psF32 evalModel(psSource *src,
+                       psU32 row,
+                       psU32 col)
 {
     PS_PTR_CHECK_NULL(src, false);
@@ -1296,8 +1426,7 @@
     // XXX: The following step will not be necessary if the models->params
     // member is a psVector.  Suggest to IfA.
-    psVector *params = psVectorAlloc(7, PS_TYPE_F32);
-    for (psS32 i = 0 ; i < src->models->Nparams ; i++) {
-        params->data.F32[i] = src->models->params[i];
-    }
+
+    // XXX EAM: done: models->params is now a vector
+    psVector *params = src->models->params;
 
     //
@@ -1332,6 +1461,4 @@
         return(NAN);
     }
-
-    psFree(params);
     psFree(x);
     return(tmpF);
@@ -1339,18 +1466,20 @@
 
 /******************************************************************************
-findValue(source, level, col, row, dir): a private function which determines
+findValue(source, level, row, col, dir): a private function which determines
 the column coordinate of the model function which has the value "level".  If
 dir equals 0, then you loop leftwards from the peak pixel, otherwise,
 rightwards.
  
+XXX: reverse order of row,col args?
+ 
 XXX: Input row/col are in image coords.
  
 XXX: The result is returned in image coords.
- *****************************************************************************/
-psF32 findValue(psSource *source,
-                psF32 level,
-                psU32 col,
-                psU32 row,
-                psU32 dir)
+*****************************************************************************/
+static psF32 findValue(psSource *source,
+                       psF32 level,
+                       psU32 row,
+                       psU32 col,
+                       psU32 dir)
 {
     //
@@ -1370,5 +1499,5 @@
     }
 
-    psF32 oldValue = evalModel(source, subCol, subRow);
+    psF32 oldValue = evalModel(source, subRow, subCol);
     if (oldValue == level) {
         return(((psF32) (subCol + source->pixels->col0)));
@@ -1391,5 +1520,5 @@
 
     while (subCol != lastColumn) {
-        psF32 newValue = evalModel(source, subCol, subRow);
+        psF32 newValue = evalModel(source, subRow, subCol);
         if (oldValue == level) {
             return((psF32) (subCol + source->pixels->col0));
@@ -1422,5 +1551,5 @@
 XXX: What is momde?
 XXX: The top, bottom of the contour is not correctly determined.
- *****************************************************************************/
+*****************************************************************************/
 psArray *pmSourceContour(psSource *source,
                          const psImage *image,
@@ -1451,5 +1580,5 @@
 
         // Starting at peak pixel, search leftwards for the column intercept.
-        psF32 leftIntercept = findValue(source, level, col, row, 0);
+        psF32 leftIntercept = findValue(source, level, row, col, 0);
         if (isnan(leftIntercept)) {
             psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
@@ -1462,5 +1591,5 @@
         // Starting at peak pixel, search rightwards for the column intercept.
 
-        psF32 rightIntercept = findValue(source, level, col, row, 1);
+        psF32 rightIntercept = findValue(source, level, row, col, 1);
         if (isnan(rightIntercept)) {
             psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
@@ -1485,5 +1614,5 @@
 
         // Starting at peak pixel, search leftwards for the column intercept.
-        psF32 leftIntercept = findValue(source, level, col, row, 0);
+        psF32 leftIntercept = findValue(source, level, row, col, 0);
         if (isnan(leftIntercept)) {
             psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
@@ -1495,5 +1624,5 @@
 
         // Starting at peak pixel, search rightwards for the column intercept.
-        psF32 rightIntercept = findValue(source, level, col, row, 1);
+        psF32 rightIntercept = findValue(source, level, row, col, 1);
         if (isnan(rightIntercept)) {
             psError(PS_ERR_UNKNOWN, true, "Could not find contour edge (NAN)");
@@ -1524,7 +1653,7 @@
 psVector *p_pmMinLM_SersicCore_Vec(psImage *deriv, psVector *params, psArray *x);
 
-//XXX: What should these values be?
-#define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 100
-#define PM_SOURCE_FIT_MODEL_TOLERANCE 1.0
+// XXX EAM : these are better starting values, but should be available from metadata?
+#define PM_SOURCE_FIT_MODEL_NUM_ITERATIONS 20
+#define PM_SOURCE_FIT_MODEL_TOLERANCE 0.1
 /******************************************************************************
 pmSourceFitModel(source, image): must create the appropiate arguments to the
@@ -1533,5 +1662,5 @@
 XXX: should there be a mask value?
 XXX: Probably should remove the "image" argument. 
- *****************************************************************************/
+*****************************************************************************/
 bool pmSourceFitModel(psSource *source,
                       const psImage *image)
@@ -1545,7 +1674,11 @@
     PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
     psBool rc;
+
+    // find the number of valid pixels
+    // XXX EAM : this loop and the loop below could just be one pass
+    //           using the psArrayAdd and psVectorExtend functions
     psS32 count = 0;
-    for (psS32 i = 0 ; i < source->pixels->numRows ; i++) {
-        for (psS32 j = 0 ; j < source->pixels->numCols ; j++) {
+    for (psS32 i = 0; i < source->pixels->numRows; i++) {
+        for (psS32 j = 0; j < source->pixels->numCols; j++) {
             if (source->mask->data.U8[i][j] == 0) {
                 count++;
@@ -1553,16 +1686,23 @@
         }
     }
+
+    // construct the coordinate and value entries
     psArray *x = psArrayAlloc(count);
     psVector *y = psVectorAlloc(count, PS_TYPE_F32);
+    psVector *yErr = psVectorAlloc(count, PS_TYPE_F32);
     psS32 tmpCnt = 0;
-    for (psS32 i = 0 ; i < source->pixels->numRows ; i++) {
-        for (psS32 j = 0 ; j < source->pixels->numCols ; j++) {
+    for (psS32 i = 0; i < source->pixels->numRows; i++) {
+        for (psS32 j = 0; j < source->pixels->numCols; j++) {
             if (source->mask->data.U8[i][j] == 0) {
                 psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
                 // XXX: Convert i/j to image space:
-                coord->data.F32[0] = (psF32) (i + source->pixels->row0);
-                coord->data.F32[1] = (psF32) (j + source->pixels->col0);
+                // XXX EAM: coord order is (x,y) == (col,row)
+                coord->data.F32[0] = (psF32) (j + source->pixels->col0);
+                coord->data.F32[1] = (psF32) (i + source->pixels->row0);
                 x->data[tmpCnt] = (psPtr *) coord;
                 y->data.F32[tmpCnt] = source->pixels->data.F32[i][j];
+
+                // XXX EAM : this is approximate: need to apply the gain and rdnoise
+                yErr->data.F32[tmpCnt] = sqrt(PS_MAX(1, source->pixels->data.F32[i][j]));
                 tmpCnt++;
             }
@@ -1573,31 +1713,24 @@
                             PM_SOURCE_FIT_MODEL_TOLERANCE);
 
-    psVector *params = psVectorAlloc(source->models->Nparams, PS_TYPE_F32);
+    psVector *params = source->models->params;
 
     switch (source->models->type) {
     case PS_MODEL_GAUSS:
-
-        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
-                              NULL, (psMinimizeLMChi2Func) p_pmMinLM_Gauss2D_Vec);
+        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Gauss2D);
         break;
     case PS_MODEL_PGAUSS:
-        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
-                              NULL, (psMinimizeLMChi2Func) p_pmMinLM_PsuedoGauss2D_Vec);
+        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_PsuedoGauss2D);
         break;
     case PS_MODEL_TWIST_GAUSS:
-        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
-                              NULL, (psMinimizeLMChi2Func) p_pmMinLM_Wauss2D_Vec);
+        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Wauss2D);
         break;
     case PS_MODEL_WAUSS:
-        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
-                              NULL, (psMinimizeLMChi2Func) p_pmMinLM_TwistGauss2D_Vec);
+        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_TwistGauss2D);
         break;
     case PS_MODEL_SERSIC:
-        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
-                              NULL, (psMinimizeLMChi2Func) p_pmMinLM_Sersic_Vec);
+        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_Sersic);
         break;
     case PS_MODEL_SERSIC_CORE:
-        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y,
-                              NULL, (psMinimizeLMChi2Func) p_pmMinLM_SersicCore_Vec);
+        rc = psMinimizeLMChi2(myMin, NULL, params, NULL, x, y, yErr, pmMinLM_SersicCore);
         break;
     default:
@@ -1605,9 +1738,13 @@
         rc = false;
     }
+    // XXX EAM: we need to do something (give an error?) if rc is false
+    // XXX EAM: save the resulting chisq, nDOF, nIter
+    source->models->chisq = myMin->value;
+    source->models->nDOF  = y->n - params->n;
+    source->models->nIter = myMin->iter;
 
     psFree(x);
     psFree(y);
     psFree(myMin);
-    psFree(params);
     return(rc);
 }
@@ -1626,12 +1763,9 @@
     PS_IMAGE_CHECK_TYPE(image, PS_TYPE_F32, false);
 
-    psVector *params = psVectorAlloc(src->models->Nparams, PS_TYPE_F32);
     psVector *x = psVectorAlloc(2, PS_TYPE_F32);
-    for (psS32 i = 0 ; i < src->models->Nparams ; i++) {
-        params->data.F32[i] = src->models->params[i];
-    }
-
-    for (psS32 i = 0 ; i < src->pixels->numRows ; i++) {
-        for (psS32 j = 0 ; j < src->pixels->numCols ; j++) {
+    psVector *params = src->models->params;
+
+    for (psS32 i = 0; i < src->pixels->numRows; i++) {
+        for (psS32 j = 0; j < src->pixels->numCols; j++) {
             psF32 pixelValue;
             // XXX: Should you be adding the pixels for the entire subImage,
@@ -1667,5 +1801,4 @@
                 psError(PS_ERR_UNKNOWN, true, "Undefined psModelType");
                 psFree(x);
-                psFree(params);
                 return(false);
             }
@@ -1681,5 +1814,4 @@
     }
     psFree(x);
-    psFree(params);
     return(true);
 }
@@ -1716,10 +1848,14 @@
 
 
-/******************************************************************************
-pmMinLM_Gauss2D(*deriv, *params, *x): the argument "x" contains a single "x,
-y" coordinate pair.  This function computes the gaussian, specified by the
-parameters in "params" at that x,y point and returns the value.  The
-derivatives are also caculated and returned in the "deriv" argument.
- 
+/**
+   all of these object representation functions have the same form : func(*deriv, *params, *x)
+ 
+   the argument "x" contains a single "x,y" coordinate pair.  The function computes the object
+   model, based on the parameters in "params" at the x,y point specified by *x, and returns the value.  
+   The derivatives are also caculated and returned in the "deriv" argument.  parameter error checking is 
+   skipped because speed is most important.
+**/
+
+/******************************************************************************
     params->data.F32[0] = So;
     params->data.F32[1] = Zo;
@@ -1729,39 +1865,19 @@
     params->data.F32[5] = sqrt(2.0) / SigmaY;
     params->data.F32[6] = Sxy;
- 
-XXX: Consider getting rid of the parameter checks since this might consume
-a significant fraction of this function CPU time.
- 
-XXX: I added the following.  Must conform with IfA.  If deriv==NULL, then
-we simply don't perform the derivative calculations.
- 
-XXX: It is not clear whether the subImage coords, or the image coords should
-be used when calling these functions.  I don't think it really matters, as
-long as we are consistent.
- *****************************************************************************/
-psF32 pmMinLM_Gauss2D(psVector *deriv,
+*****************************************************************************/
+psF64 pmMinLM_Gauss2D(psVector *deriv,
                       psVector *params,
                       psVector *x)
 {
-    PS_VECTOR_CHECK_NULL(params, NAN);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(params, 7, NAN);
-    PS_VECTOR_CHECK_NULL(x, NAN);
-    PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(x, 2, NAN);
-
-    psF32 X = x->data.F32[0] - params->data.F32[2];
-    psF32 Y = x->data.F32[1] - params->data.F32[3];
+    psF32 X  = x->data.F32[0] - params->data.F32[2];
+    psF32 Y  = x->data.F32[1] - params->data.F32[3];
     psF32 px = params->data.F32[4]*X;
     psF32 py = params->data.F32[5]*Y;
-    psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
-    psF32 r = exp(-z);
-    psF32 f = params->data.F32[1]*r + params->data.F32[0];
+    psF32 z  = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
+    psF32 r  = exp(-z);
+    psF32 q  = params->data.F32[1]*r;
+    psF32 f  = q + params->data.F32[0];
 
     if (deriv != NULL) {
-        PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
-        PS_VECTOR_CHECK_SIZE(deriv, 7, NAN);
-
-        psF32 q = params->data.F32[1]*r;
         deriv->data.F32[0] = +1.0;
         deriv->data.F32[1] = +r;
@@ -1772,49 +1888,6 @@
         deriv->data.F32[6] = -q*X*Y;
     }
-
     return(f);
 }
-
-/******************************************************************************
-p_pmMinLM_Gauss2D_Vec(*deriv, *params, *x): this function wraps the above
-function in a form that is usable in the LM minimization routines.
- *****************************************************************************/
-psVector *p_pmMinLM_Gauss2D_Vec(psImage *deriv,
-                                psVector *params,
-                                psArray *x)
-{
-    PS_IMAGE_CHECK_NULL(deriv, NULL);
-    PS_IMAGE_CHECK_EMPTY(deriv, NULL);
-    PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
-    PS_VECTOR_CHECK_NULL(params, NULL);
-    PS_VECTOR_CHECK_EMPTY(params, NULL);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
-    PS_PTR_CHECK_NULL(x, NULL);
-    if (deriv->numRows != x->n) {
-        psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
-    }
-    psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
-    // XXX: use static memory here.
-    psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
-
-    for (psS32 i = 0 ; i < x->n ; i++) {
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            tmpRow->data.F32[j] = deriv->data.F32[i][j];
-        }
-
-        psVector *tmpVec2 = (psVector *) x->data[i];
-        tmpVec->data.F32[i] = pmMinLM_Gauss2D(tmpRow,
-                                              params,
-                                              tmpVec2);
-
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            deriv->data.F32[i][j] = tmpRow->data.F32[j];
-        }
-    }
-
-    psFree(tmpRow);
-    return(tmpVec);
-}
-
 
 /******************************************************************************
@@ -1826,88 +1899,31 @@
     params->data.F32[5] = sqrt(2) / SigmaY;
     params->data.F32[6] = Sxy;
- *****************************************************************************/
-psF32 pmMinLM_PsuedoGauss2D(psVector *deriv,
+*****************************************************************************/
+psF64 pmMinLM_PsuedoGauss2D(psVector *deriv,
                             psVector *params,
                             psVector *x)
 {
-    PS_VECTOR_CHECK_NULL(params, NAN);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(params, 7, NAN);
-    PS_VECTOR_CHECK_NULL(x, NAN);
-    PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(x, 2, NAN);
-
-    psF32 X = x->data.F32[0] - params->data.F32[2];
-    psF32 Y = x->data.F32[1] - params->data.F32[3];
+    psF32 X  = x->data.F32[0] - params->data.F32[2];
+    psF32 Y  = x->data.F32[1] - params->data.F32[3];
     psF32 px = params->data.F32[4]*X;
     psF32 py = params->data.F32[5]*Y;
-    psF32 z = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
-    psF32 t = 1 + z + 0.5*z*z;
-    psF32 r = 1.0 / (t*(1 + z/3)); /* exp (-Z) */
-    psF32 f = params->data.F32[1]*r + params->data.F32[0];
+    psF32 z  = 0.5*PS_SQR(px) + 0.5*PS_SQR(py) + params->data.F32[6]*X*Y;
+    psF32 t  = 1 + z + 0.5*z*z;
+    psF32 r  = 1.0 / (t*(1 + z/3)); /* exp (-Z) */
+    psF32 f  = params->data.F32[1]*r + params->data.F32[0];
 
     if (deriv != NULL) {
-        PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
-        PS_VECTOR_CHECK_SIZE(deriv, 7, NAN);
-
-        //
         // note difference from a pure gaussian: q = params->data.F32[1]*r
-        //
         psF32 q = params->data.F32[1]*r*r*t;
         deriv->data.F32[0] = +1.0;
         deriv->data.F32[1] = +r;
         deriv->data.F32[2] = q*(2.0*px*params->data.F32[4] + params->data.F32[6]*Y);
-        deriv->data.F32[3] = q *
-                             (2.0*py*params->data.F32[5] + params->data.F32[6]*X);
+        deriv->data.F32[3] = q*(2.0*py*params->data.F32[5] + params->data.F32[6]*X);
         deriv->data.F32[4] = -2.0*q*px*X;
         deriv->data.F32[5] = -2.0*q*py*Y;
         deriv->data.F32[6] = -q*X*Y;
     }
-
     return(f);
 }
-
-/******************************************************************************
-p_pmMinLM_PsuedoGauss2D_Vec(*deriv, *params, *x): this function wraps the
-above function in a form that is usable in the LM minimization routines.
- *****************************************************************************/
-psVector *p_pmMinLM_PsuedoGauss2D_Vec(psImage *deriv,
-                                      psVector *params,
-                                      psArray *x)
-{
-    PS_IMAGE_CHECK_NULL(deriv, NULL);
-    PS_IMAGE_CHECK_EMPTY(deriv, NULL);
-    PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
-    PS_VECTOR_CHECK_NULL(params, NULL);
-    PS_VECTOR_CHECK_EMPTY(params, NULL);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
-    PS_PTR_CHECK_NULL(x, NULL);
-    if (deriv->numRows != x->n) {
-        psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
-    }
-    psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
-    // XXX: use static memory here.
-    psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
-
-    for (psS32 i = 0 ; i < x->n ; i++) {
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            tmpRow->data.F32[j] = deriv->data.F32[i][j];
-        }
-
-        tmpVec->data.F32[i] = pmMinLM_PsuedoGauss2D(tmpRow,
-                              params,
-                              (psVector *) x->data[i]);
-
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            deriv->data.F32[i][j] = tmpRow->data.F32[j];
-        }
-    }
-
-    psFree(tmpRow);
-    return(tmpVec);
-}
-
-
-
 
 /******************************************************************************
@@ -1921,16 +1937,9 @@
     params->data.F32[7] = B2;
     params->data.F32[8] = B3;
- *****************************************************************************/
-psF32 pmMinLM_Wauss2D(psVector *deriv,
+*****************************************************************************/
+psF64 pmMinLM_Wauss2D(psVector *deriv,
                       psVector *params,
                       psVector *x)
 {
-    PS_VECTOR_CHECK_NULL(params, NAN);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(params, 9, NAN);
-    PS_VECTOR_CHECK_NULL(x, NAN);
-    PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(x, 2, NAN);
-
     psF32 X = x->data.F32[0] - params->data.F32[2];
     psF32 Y = x->data.F32[1] - params->data.F32[2];
@@ -1943,10 +1952,5 @@
 
     if (deriv != NULL) {
-        PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
-        PS_VECTOR_CHECK_SIZE(deriv, 9, NAN);
-        //
         // note difference from gaussian: q = params->data.F32[1]*r
-        //
-
         psF32 q = params->data.F32[1]*r*r*(1.0 + params->data.F32[7]*z*(1.0 + params->data.F32[8]*z/2.0));
         deriv->data.F32[0] = +1.0;
@@ -1959,56 +1963,8 @@
         deriv->data.F32[7] = -100.0*params->data.F32[1]*r*r*t;
         deriv->data.F32[8] = -100.0*params->data.F32[1]*r*r*params->data.F32[7]*(z*z*z)/6.0;
-        //
         // The values of 100 dampen the swing of params->data.F32[7,8] */
-        //
-    }
-
+    }
     return(f);
 }
-
-/******************************************************************************
-p_pmMinLM_Wauss2D_Vec(*deriv, *params, *x): this function wraps the above
-function in a form that is usable in the LM minimization routines.
- *****************************************************************************/
-psVector *p_pmMinLM_Wauss2D_Vec(psImage *deriv,
-                                psVector *params,
-                                psArray *x)
-{
-    PS_IMAGE_CHECK_NULL(deriv, NULL);
-    PS_IMAGE_CHECK_EMPTY(deriv, NULL);
-    PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
-    PS_VECTOR_CHECK_NULL(params, NULL);
-    PS_VECTOR_CHECK_EMPTY(params, NULL);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
-    PS_PTR_CHECK_NULL(x, NULL);
-    if (deriv->numRows != x->n) {
-        psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
-    }
-    psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
-    // XXX: use static memory here.
-    psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
-
-    for (psS32 i = 0 ; i < x->n ; i++) {
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            tmpRow->data.F32[j] = deriv->data.F32[i][j];
-        }
-
-        tmpVec->data.F32[i] = pmMinLM_Wauss2D(tmpRow,
-                                              params,
-                                              (psVector *) x->data[i]);
-
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            deriv->data.F32[i][j] = tmpRow->data.F32[j];
-        }
-    }
-
-    psFree(tmpRow);
-    return(tmpVec);
-}
-
-
-
-
-
 
 // XXX: What should these be?
@@ -2027,16 +1983,9 @@
     params->data.F32[9] = SxyOuter;
     params->data.F32[10] = N;
- *****************************************************************************/
-psF32 pmMinLM_TwistGauss2D(psVector *deriv,
+*****************************************************************************/
+psF64 pmMinLM_TwistGauss2D(psVector *deriv,
                            psVector *params,
                            psVector *x)
 {
-    PS_VECTOR_CHECK_NULL(params, NAN);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(params, 11, NAN);
-    PS_VECTOR_CHECK_NULL(x, NAN);
-    PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(x, 2, NAN);
-
     psF32 X = x->data.F32[0] - params->data.F32[2];
     psF32 Y = x->data.F32[1] - params->data.F32[3];
@@ -2049,11 +1998,7 @@
     psF32 r = 1.0 / (1.0 + z1 + pow(z2,params->data.F32[10]));
 
-
     psF32 f = params->data.F32[5]*r + params->data.F32[6];
 
     if (deriv != NULL) {
-        PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
-        PS_VECTOR_CHECK_SIZE(deriv, 11, NAN);
-
         psF32 q1 = params->data.F32[5]*PS_SQR(r);
         psF32 q2 = params->data.F32[5]*PS_SQR(r)*params->data.F32[10]*pow(z2,(params->data.F32[10]-1.0));
@@ -2063,16 +2008,12 @@
         deriv->data.F32[3] = q1*(2.0*py1*params->data.F32[5] + params->data.F32[6]*X) + q2*(2*py2*params->data.F32[8] + params->data.F32[9]*X);
 
-        //
         // These fudge factors impede the growth of params->data.F32[4] beyond
         // params->data.F32[7].
-        //
         psF32 f1 = fabs(params->data.F32[7]) / fabs(params->data.F32[4]);
         psF32 f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0;
         deriv->data.F32[4] = -2.0*q1*px1*X*f2;
 
-        //
         // These fudge factors impede the growth of params->data.F32[5] beyond
         // params->data.F32[8].
-        //
         f1 = fabs(params->data.F32[8]) / fabs(params->data.F32[5]);
         f2 = (f1 < FSCALE) ? 1.0 : FFACTOR*(f1 - FSCALE) + 1.0;
@@ -2087,46 +2028,4 @@
     return(f);
 }
-
-/******************************************************************************
-p_pmMinLM_TwistGauss2D_Vec(*deriv, *params, *x): this function wraps the above
-function in a form that is usable in the LM minimization routines.
- *****************************************************************************/
-psVector *p_pmMinLM_TwistGauss2D_Vec(psImage *deriv,
-                                     psVector *params,
-                                     psArray *x)
-{
-    PS_IMAGE_CHECK_NULL(deriv, NULL);
-    PS_IMAGE_CHECK_EMPTY(deriv, NULL);
-    PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
-    PS_VECTOR_CHECK_NULL(params, NULL);
-    PS_VECTOR_CHECK_EMPTY(params, NULL);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
-    PS_PTR_CHECK_NULL(x, NULL);
-    if (deriv->numRows != x->n) {
-        psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
-    }
-    psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
-    // XXX: use static memory here.
-    psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
-
-    for (psS32 i = 0 ; i < x->n ; i++) {
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            tmpRow->data.F32[j] = deriv->data.F32[i][j];
-        }
-
-        tmpVec->data.F32[i] = pmMinLM_TwistGauss2D(tmpRow,
-                              params,
-                              (psVector *) x->data[i]);
-
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            deriv->data.F32[i][j] = tmpRow->data.F32[j];
-        }
-    }
-
-    psFree(tmpRow);
-    return(tmpVec);
-}
-
-
 
 /******************************************************************************
@@ -2140,62 +2039,11 @@
     params->data.F32[6] = Sxy;
     params->data.F32[7] = Nexp;
- *****************************************************************************/
-psF32 pmMinLM_Sersic(psVector *deriv,
+*****************************************************************************/
+psF64 pmMinLM_Sersic(psVector *deriv,
                      psVector *params,
                      psVector *x)
 {
-    PS_VECTOR_CHECK_NULL(params, NAN);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(params, 8, NAN);
-    PS_VECTOR_CHECK_NULL(x, NAN);
-    PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(x, 2, NAN);
-
-    if (deriv != NULL) {
-        PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
-        PS_VECTOR_CHECK_SIZE(deriv, 8, NAN);
-    }
-
     psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet.");
     return(0.0);
-}
-/******************************************************************************
-p_pmMinLM_Sersic_Vec(*deriv, *params, *x): this function wraps the above
-function in a form that is usable in the LM minimization routines.
- *****************************************************************************/
-psVector *p_pmMinLM_Sersic_Vec(psImage *deriv,
-                               psVector *params,
-                               psArray *x)
-{
-    PS_IMAGE_CHECK_NULL(deriv, NULL);
-    PS_IMAGE_CHECK_EMPTY(deriv, NULL);
-    PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
-    PS_VECTOR_CHECK_NULL(params, NULL);
-    PS_VECTOR_CHECK_EMPTY(params, NULL);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
-    PS_PTR_CHECK_NULL(x, NULL);
-    if (deriv->numRows != x->n) {
-        psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
-    }
-    psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
-    // XXX: use static memory here.
-    psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
-
-    for (psS32 i = 0 ; i < x->n ; i++) {
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            tmpRow->data.F32[j] = deriv->data.F32[i][j];
-        }
-
-        tmpVec->data.F32[i] = pmMinLM_Sersic(tmpRow,
-                                             params,
-                                             (psVector *) x->data[i]);
-
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            deriv->data.F32[i][j] = tmpRow->data.F32[j];
-        }
-    }
-
-    psFree(tmpRow);
-    return(tmpVec);
 }
 
@@ -2214,72 +2062,10 @@
     params->data.F32[10] = SxyOuter;
     params->data.F32[11] = Nexp;
- *****************************************************************************/
-psF32 pmMinLM_SersicCore(psVector *deriv,
+*****************************************************************************/
+psF64 pmMinLM_SersicCore(psVector *deriv,
                          psVector *params,
                          psVector *x)
 {
-    PS_VECTOR_CHECK_NULL(params, NAN);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(params, 12, NAN);
-    PS_VECTOR_CHECK_NULL(x, NAN);
-    PS_VECTOR_CHECK_TYPE(x, PS_TYPE_F32, NAN);
-    PS_VECTOR_CHECK_SIZE(x, 2, NAN);
-
-    if (deriv != NULL) {
-        PS_VECTOR_CHECK_TYPE(deriv, PS_TYPE_F32, NAN);
-        PS_VECTOR_CHECK_SIZE(deriv, 12, NAN);
-    }
-
     psError(PS_ERR_UNKNOWN, true, "This function is not implemented yet.");
     return(0.0);
 }
-/******************************************************************************
-p_pmMinLM_SersicCore_Vec(*deriv, *params, *x): this function wraps the above
-function in a form that is usable in the LM minimization routines.
- *****************************************************************************/
-psVector *p_pmMinLM_SersicCore_Vec(psImage *deriv,
-                                   psVector *params,
-                                   psArray *x)
-{
-    PS_IMAGE_CHECK_NULL(deriv, NULL);
-    PS_IMAGE_CHECK_EMPTY(deriv, NULL);
-    PS_IMAGE_CHECK_TYPE(deriv, PS_TYPE_F32, NULL);
-    PS_VECTOR_CHECK_NULL(params, NULL);
-    PS_VECTOR_CHECK_EMPTY(params, NULL);
-    PS_VECTOR_CHECK_TYPE(params, PS_TYPE_F32, NULL);
-    PS_PTR_CHECK_NULL(x, NULL);
-    if (deriv->numRows != x->n) {
-        psError(PS_ERR_UNKNOWN, true, "deriv must have one row for each coordinate set in x.");
-    }
-    psVector *tmpVec = psVectorAlloc(x->n, PS_TYPE_F32);
-    // XXX: use static memory here.
-    psVector *tmpRow = psVectorAlloc(deriv->numCols, PS_TYPE_F32);
-
-    for (psS32 i = 0 ; i < x->n ; i++) {
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            tmpRow->data.F32[j] = deriv->data.F32[i][j];
-        }
-
-        tmpVec->data.F32[i] = pmMinLM_SersicCore(tmpRow,
-                              params,
-                              (psVector *) x->data[i]);
-
-        for (psS32 j = 0 ; j < tmpRow->n ; j++) {
-            deriv->data.F32[i][j] = tmpRow->data.F32[j];
-        }
-    }
-
-    psFree(tmpRow);
-    return(tmpVec);
-}
-
-
-
-/******************************************************************************
- *****************************************************************************/
-psF32 pmMinLM_PsuedoSersic(psVector *deriv,
-                           psVector *params,
-                           psVector *x)
-{
-    return(0.0);
-}
