Index: trunk/psModules/src/objects/pmSource.c
===================================================================
--- trunk/psModules/src/objects/pmSource.c	(revision 28013)
+++ trunk/psModules/src/objects/pmSource.c	(revision 29004)
@@ -23,13 +23,20 @@
 #include "pmFPA.h"
 #include "pmFPAMaskWeight.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
 #include "pmSpan.h"
+#include "pmFootprintSpans.h"
 #include "pmFootprint.h"
 #include "pmPeaks.h"
 #include "pmMoments.h"
-#include "pmResiduals.h"
-#include "pmGrowthCurve.h"
-#include "pmTrend2D.h"
-#include "pmPSF.h"
+#include "pmModelFuncs.h"
 #include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
 #include "pmSource.h"
 
@@ -98,5 +105,6 @@
     static int id = 1;
     pmSource *source = (pmSource *) psAlloc(sizeof(pmSource));
-    *(int *)&source->id = id++;
+    P_PM_SOURCE_SET_ID(source, id++);
+
     source->seq = -1;
     source->peak = NULL;
@@ -114,4 +122,5 @@
     source->type = PM_SOURCE_TYPE_UNKNOWN;
     source->mode = PM_SOURCE_MODE_DEFAULT;
+    source->mode2 = PM_SOURCE_MODE_DEFAULT;
     source->tmpFlags = 0;
     source->extpars = NULL;
@@ -131,5 +140,6 @@
     source->sky    = NAN;
     source->skyErr = NAN;
-    source->pixWeight = NAN;
+    source->pixWeightNotBad = NAN;
+    source->pixWeightNotPoor = NAN;
 
     source->psfChisq = NAN;
@@ -142,8 +152,56 @@
 
 /******************************************************************************
-pmSourceCopy(): copy the pmSource structure and contents
-XXX : are we OK with incrementing the ID?
+pmSourceCopy(): copy the pmSource, yielding a copy of the source that can be used without
+affecting the original.  This Copy can be used to allow multiple fit attempts on the same
+object.  The pixels, variance, and mask arrays all point to the same original subarrays.  The
+peak and moments point at the original values.
 *****************************************************************************/
 pmSource *pmSourceCopy(pmSource *in)
+{
+    if (in == NULL) {
+        return(NULL);
+    }
+    pmSource *source = pmSourceAlloc ();
+
+    // keep the original ID so we can find map back to the original
+    P_PM_SOURCE_SET_ID(source, in->id);
+
+    // peak has the same values as the original
+    if (in->peak != NULL) {
+        source->peak = pmPeakAlloc (in->peak->x, in->peak->y, in->peak->value, in->peak->type);
+        source->peak->xf = in->peak->xf;
+        source->peak->yf = in->peak->yf;
+        source->peak->flux = in->peak->flux;
+        source->peak->SN = in->peak->SN;
+    }
+
+    // copy the values in the moments structure
+    if (in->moments != NULL) {
+        source->moments  =  pmMomentsAlloc();
+        *source->moments = *in->moments;
+    }
+
+    // These images are all views to the parent.  We want a new view, but pointing at the same
+    // pixels.  Modifying these pixels (ie, subtracting the model) will affect the pixels seen
+    // by all copies.
+    source->pixels   = psImageCopyView(NULL, in->pixels);
+    source->variance   = psImageCopyView(NULL, in->variance);
+    source->maskView = in->maskView ? psImageCopyView(NULL, in->maskView) : NULL;
+
+    // the maskObj is a unique mask array; create a new mask image
+    source->maskObj = in->maskObj ? psImageCopy (NULL, in->maskObj, PS_TYPE_IMAGE_MASK) : NULL;
+
+    source->type = in->type;
+    source->mode = in->mode;
+    source->imageID = in->imageID;
+
+    return(source);
+}
+
+/******************************************************************************
+pmSourceCopyData(): this creates a new, duplicate source with the same parameters as the
+original (but is actually a new source at the same location)
+*****************************************************************************/
+pmSource *pmSourceCopyData(pmSource *in)
 {
     if (in == NULL) {
@@ -482,5 +540,5 @@
         }
         psfClump.X  = stats->clippedMean;
-        psfClump.dX = stats->clippedStdev;
+        psfClump.dX = hypot(stats->clippedStdev, PSF_CLUMP_GRID_SCALE);
 
         if (!psVectorStats (stats, tmpSy, NULL, NULL, 0)) {
@@ -489,5 +547,5 @@
         }
         psfClump.Y  = stats->clippedMean;
-        psfClump.dY = stats->clippedStdev;
+        psfClump.dY = hypot(stats->clippedStdev, PSF_CLUMP_GRID_SCALE);
 
         psTrace ("psModules.objects", 2, "clump  X,  Y: %f, %f\n", psfClump.X, psfClump.Y);
@@ -910,5 +968,6 @@
     bool addNoise = mode & PM_MODEL_OP_NOISE;
 
-    if (source->modelFlux) {
+    // require the use of pmModelAddWithOffset if we are adding noise (because the model size and norm are rescaled)
+    if (!addNoise && source->modelFlux) {
         // add in the pixels from the modelFlux image
         int dX = source->modelFlux->col0 - source->pixels->col0;
@@ -931,8 +990,4 @@
 
         psF32 **target = source->pixels->data.F32;
-        if (addNoise) {
-	    // when adding noise, we assume the shape and Io have been modified
-            target = source->variance->data.F32;
-        }
 
         for (int iy = 0; iy < source->modelFlux->numRows; iy++) {
@@ -949,10 +1004,8 @@
             }
         }
-	if (!addNoise) {
-	    if (add) {
-		source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
-	    } else {
-		source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
-	    }
+	if (add) {
+	    source->tmpFlags &= ~PM_SOURCE_TMPF_SUBTRACTED;
+	} else {
+	    source->tmpFlags |= PM_SOURCE_TMPF_SUBTRACTED;
 	}
         return true;
@@ -973,4 +1026,78 @@
 	}
     }
+
+    return true;
+}
+
+// should we call pmSourceCacheModel if it does not exist?
+bool pmSourceNoiseOp (pmSource *source, pmModelOpMode mode, float FACTOR, float SIZE, bool add, psImageMaskType maskVal, int dx, int dy)
+{
+    assert (mode & PM_MODEL_OP_NOISE);
+    PS_ASSERT_PTR_NON_NULL(source, false);
+    PS_ASSERT_PTR_NON_NULL(source->peak, false);
+
+    if (add) {
+        psTrace ("psphot", 3, "adding noise to object at %f,%f\n", source->peak->xf, source->peak->yf);
+    } else {
+        psTrace ("psphot", 3, "removing noise from object at %f,%f\n", source->peak->xf, source->peak->yf);
+    }
+
+    pmSourceNoiseOpModel (source->modelPSF, source, mode, FACTOR, SIZE, add, maskVal, dx, dy);
+
+    if (source->modelEXT) {
+	pmSourceNoiseOpModel (source->modelEXT, source, mode, FACTOR, SIZE, add, maskVal, dx, dy);
+    }
+
+    return true;
+}
+
+bool pmSourceNoiseOpModel (pmModel *model, pmSource *source, pmModelOpMode mode, float FACTOR, float SIZE, bool add, psImageMaskType maskVal, int dx, int dy) 
+{
+    bool status;
+    psEllipseShape oldshape;
+    psEllipseShape newshape;
+    psEllipseAxes axes;
+
+    if (add) {
+	psTrace ("psphot", 4, "adding noise for object at %f,%f\n", model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS]);
+    } else {
+	psTrace ("psphot", 4, "remove noise for object at %f,%f\n", model->params->data.F32[PM_PAR_XPOS], model->params->data.F32[PM_PAR_YPOS]);
+    }
+
+    psF32 *PAR = model->params->data.F32;
+
+    // save original values
+    float oldI0  = PAR[PM_PAR_I0];
+    oldshape.sx  = PAR[PM_PAR_SXX];
+    oldshape.sy  = PAR[PM_PAR_SYY];
+    oldshape.sxy = PAR[PM_PAR_SXY];
+
+    // XXX can this be done more intelligently?
+    if (oldI0 == 0.0) return false;
+    if (!isfinite(oldI0)) return false;
+
+    // increase size and height of source
+    axes = psEllipseShapeToAxes (oldshape, 20.0);
+    axes.major *= SIZE;
+    axes.minor *= SIZE;
+    newshape = psEllipseAxesToShape (axes);
+    PAR[PM_PAR_I0]  = FACTOR*oldI0;
+    PAR[PM_PAR_SXX] = newshape.sx;
+    PAR[PM_PAR_SYY] = newshape.sy;
+    PAR[PM_PAR_SXY] = newshape.sxy;
+
+    psImage *target = source->variance;
+
+    if (add) {
+	status = pmModelAddWithOffset (target, source->maskObj, model, mode, maskVal, dx, dy);
+    } else {
+	status = pmModelSubWithOffset (target, source->maskObj, model, mode, maskVal, dx, dy);
+    }
+
+    // restore original values
+    PAR[PM_PAR_I0]  = oldI0;
+    PAR[PM_PAR_SXX] = oldshape.sx;
+    PAR[PM_PAR_SYY] = oldshape.sy;
+    PAR[PM_PAR_SXY] = oldshape.sxy;
 
     return true;
