Index: trunk/psModules/src/objects/pmSourcePhotometry.c
===================================================================
--- trunk/psModules/src/objects/pmSourcePhotometry.c	(revision 38872)
+++ trunk/psModules/src/objects/pmSourcePhotometry.c	(revision 41705)
@@ -60,4 +60,5 @@
 static psImageMaskType maskGhost    = 0;
 static psImageMaskType maskGlint    = 0;
+static psImageMaskType maskCrosstalk    = 0;
 
 bool pmSourceMagnitudesInit (pmConfig *config, psMetadata *recipe)
@@ -74,4 +75,5 @@
 	maskGhost    = pmConfigMaskGet("GHOST", config);
 	maskGlint    = pmConfigMaskGet("GHOST", config);
+	maskCrosstalk    = pmConfigMaskGet("CROSSTALK", config);
 	maskSuspect  = maskSpike | maskStarCore | maskBurntool | maskConvPoor;
     }
@@ -437,4 +439,5 @@
     float burntoolSum = 0;
     float convpoorSum = 0;
+    float ghostSum = 0;
 
     int Xo, Yo, dP;
@@ -520,4 +523,8 @@
 	    }
 	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskGhost) {
+		ghostSum += value;
+	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
             if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskBurntool) {
 		burntoolSum += value;
@@ -539,4 +546,7 @@
     if ((starcoreSum/modelSum) > 0.25) {
 	source->mode2 |= PM_SOURCE_MODE2_ON_STARCORE;
+    }
+    if ((ghostSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_GHOST;
     }
     if ((burntoolSum/modelSum) > 0.25) {
@@ -582,4 +592,146 @@
 	    source->mode |= PM_SOURCE_MODE_ON_SPIKE;
 	}
+	if (maskValue & maskCrosstalk) {
+	    source->mode2 |= PM_SOURCE_MODE2_ON_CROSSTALK;
+	}
+    }
+    return (true);
+}
+
+// return source aperture magnitude
+bool pmSourceMaskEval (pmSource *source, psImage *mask, psImageMaskType maskVal)
+{
+    PS_ASSERT_PTR_NON_NULL(source, false);
+    source->pixWeightNotBad = NAN;
+    source->pixWeightNotPoor = NAN;
+
+    PS_ASSERT_PTR_NON_NULL(mask, false);
+
+    float modelSum = 0;
+    float spikeSum = 0;
+    float starcoreSum = 0;
+    float burntoolSum = 0;
+    float convpoorSum = 0;
+    float ghostSum = 0;
+
+    int Xo, Yo, dP;
+    int dX, DX, NX;
+    int dY, DY, NY;
+
+    float radius=10.;
+    float radius2 = PS_SQR(radius);
+
+    // the model function returns the source flux at a position
+    psVector *coord = psVectorAlloc(2, PS_TYPE_F32);
+
+    Xo = source->peak->x;
+    Yo = source->peak->y;
+
+    dX = Xo - mask->col0;
+    dP = mask->numCols - dX;
+    DX = PS_MAX(dX, dP);
+    NX = mask->numCols;
+
+    dY = Yo - mask->row0;
+    dP = mask->numRows - dY;
+    DY = PS_MAX(dY, dP);
+    NY = mask->numRows;
+
+    psImageMaskType maskBad = maskVal;
+    maskBad &= ~maskSuspect;
+
+    // were not by an edge; ie, if the source is cut in half by an image edge, we correctly
+    // count the virtual pixels off the edge in normalizing the value of the pixWeight
+
+    // we skip any pixels [real or virtual] outside of the specified radius (nominally the aperture radius)
+    for (int ix = -DX; ix < DX + 1; ix++) {
+	if (ix > radius) continue;
+        int mx = ix + dX;
+        for (int iy = -DY; iy < DY + 1; iy++) {
+	    if (iy > radius) continue;
+	    if (ix*ix + iy*iy > radius2) continue;
+            int my = iy + dY;
+
+            coord->data.F32[0] = (psF32) (ix + Xo);
+            coord->data.F32[1] = (psF32) (iy + Yo);
+
+            modelSum += 1.;
+            // include count only the unmasked pixels within the image area
+            if (mx < 0) continue;
+            if (my < 0) continue;
+            if (mx >= NX) continue;
+            if (my >= NY) continue;
+
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskSpike) {
+		spikeSum += 1.;
+	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskStarCore) {
+		starcoreSum += 1.;
+	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskGhost) {
+		ghostSum += 1.;
+	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskBurntool) {
+		burntoolSum += 1.;
+	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskConvPoor) {
+		convpoorSum += 1.;
+	    }
+        }
+    }
+    psFree (coord);
+
+    if ((spikeSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_SPIKE;
+    }
+    if ((starcoreSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_STARCORE;
+    }
+    if ((ghostSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_GHOST;
+    }
+    if ((burntoolSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_BURNTOOL;
+    }
+    if ((convpoorSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_CONVPOOR;
+    }
+
+    // Check that if the peak is on/off a ghost, glint, or diffraction spike.  In regular IPP
+    // processing, these values are only set in the image mask after the 'camera' stage
+
+    // need to access the parent if we are looking at a subimage (likely)
+    psImage *chipImage = (source->pixels == NULL) ? source->pixels : (psImage *) source->pixels->parent;
+
+    bool onChip = true;
+    onChip &= (Xo >= 0);
+    onChip &= (Xo < chipImage->numCols);
+    onChip &= (Yo >= 0);
+    onChip &= (Yo < chipImage->numRows);
+    if (!onChip) {
+	// if the source is off the edge of the chip, raise a different bit?
+	source->mode |= PM_SOURCE_MODE_OFF_CHIP;
+    } else {
+	int xMask = Xo - mask->col0;
+	int yMask = Yo - mask->row0;
+	psImageMaskType maskValue = mask->data.PS_TYPE_IMAGE_MASK_DATA[yMask][xMask];
+	if (maskValue & maskGhost) {
+	    source->mode |= PM_SOURCE_MODE_ON_GHOST;
+	}
+	pmSourceMode PM_SOURCE_MODE_ON_GLINT = PM_SOURCE_MODE_ON_GHOST;
+	if (maskValue & maskGlint) {
+	    source->mode |= PM_SOURCE_MODE_ON_GLINT;
+	}
+	if (maskValue & maskCrosstalk) {
+	    source->mode2 |= PM_SOURCE_MODE2_ON_CROSSTALK;
+	}
+	if (maskValue & maskSpike) {
+	    source->mode |= PM_SOURCE_MODE_ON_SPIKE;
+	}
     }
     return (true);
