Index: /trunk/ippconfig/gpc2/pswarp.config
===================================================================
--- /trunk/ippconfig/gpc2/pswarp.config	(revision 42292)
+++ /trunk/ippconfig/gpc2/pswarp.config	(revision 42293)
@@ -1,2 +1,0 @@
-APPLY.PIXELNAN		BOOL	FALSE		# Apply NAN'ing of pixels underneath masks
-
Index: /trunk/ippconfig/recipes/ppImage.config
===================================================================
--- /trunk/ippconfig/recipes/ppImage.config	(revision 42292)
+++ /trunk/ippconfig/recipes/ppImage.config	(revision 42293)
@@ -21,4 +21,5 @@
 APPLY.BURNTOOL     BOOL    FALSE           # apply burntool coorection
 APPLY.PIXELZERO    BOOL    FALSE           # apply zero'ing of pixels underneath masks
+DETECT.CTE         BOOL    FALSE           # perform object detections in the CTE regions
 VARIANCE.BUILD     BOOL    FALSE           # Build internal variance image
 ADDNOISE           BOOL    FALSE           # Add noise to degrade an MD image to a 3pi image?
Index: /trunk/ippconfig/recipes/pswarp.config
===================================================================
--- /trunk/ippconfig/recipes/pswarp.config	(revision 42292)
+++ /trunk/ippconfig/recipes/pswarp.config	(revision 42293)
@@ -13,4 +13,5 @@
 SOURCES			BOOL	TRUE		# Write source list for warped image?
 APPLY.PIXELNAN		BOOL	FALSE		# Apply NAN'ing of pixels underneath masks
+DETECT.CTE              BOOL    FALSE           # perform object detections in the CTE regions
 
 # as of r41891, dvoImageOverlaps compares the header keyword CERSTD to MAX.CERROR
Index: /trunk/ppImage/src/ppImage.h
===================================================================
--- /trunk/ppImage/src/ppImage.h	(revision 42292)
+++ /trunk/ppImage/src/ppImage.h	(revision 42293)
@@ -156,4 +156,8 @@
 ppImageOptions *ppImageParseCamera(pmConfig *config);
 bool ppImageSetMaskBits (pmConfig *config, ppImageOptions *options);
+bool ppImageMaskSetInMetadata(psImageMaskType *outMaskValue, // Value of MASK.VALUE, returned
+                               psImageMaskType *outMarkValue, // Value of MARK.VALUE, returned
+                               psMetadata *source  // Source of mask bits
+  );
 
 // apply the cell flips to the input data before analysis
Index: /trunk/ppImage/src/ppImageSetMaskBits.c
===================================================================
--- /trunk/ppImage/src/ppImageSetMaskBits.c	(revision 42292)
+++ /trunk/ppImage/src/ppImageSetMaskBits.c	(revision 42293)
@@ -5,9 +5,61 @@
 #include "ppImage.h"
 
+// Structure to hold the properties of a mask value
+typedef struct {
+    char *badMaskName;                  // name for "bad" (i.e., mask me please) pixels
+    char *fallbackName;                 // Fallback name in case a bad mask name is not defined
+    psImageMaskType defaultMaskValue;   // Default value in case a bad mask name and its fallback are not defined
+    bool isBad; // include this value as part of the MASK.VALUE entry (generically bad)
+} pmConfigMaskInfo;
+
+static pmConfigMaskInfo ppimagemasks[] = {
+    // Features of the detector
+    { "DETECTOR",  NULL,       0x01, true }, // Something is wrong with the detector
+    { "FLAT",      "DETECTOR", 0x01, true }, // Pixel doesn't flat-field properly
+    { "DARK",      "DETECTOR", 0x01, true }, // Pixel doesn't dark-subtract properly
+    { "BLANK",     "DETECTOR", 0x01, true }, // Pixel doesn't contain valid data
+    { "CTE",       "DETECTOR", 0x01, false }, // Pixel has poor CTE
+    { "BURNTOOL",  NULL,       0x04, false }, // Pixel has been touched by burntool
+    // Invalid signal ranges
+    { "SAT",       NULL,       0x02, true  }, // Pixel is saturated or non-linear
+    { "LOW",       "SAT",      0x02, true  }, // Pixel is low
+    { "SUSPECT",   NULL,       0x04, false }, // Pixel is suspected of being bad
+    // Non-astronomical structures
+    { "CR",        NULL,       0x08, true  }, // Pixel contains a cosmic ray
+    { "SPIKE",     NULL,       0x08, false  }, // Pixel contains a diffraction spike
+    { "GHOST",     NULL,       0x08, false  }, // Pixel contains an optical ghost
+    { "STREAK",    NULL,       0x08, false  }, // Pixel contains a streak
+    { "CROSSTALK", NULL,       0x08, false  }, // Pixel contains crosstalk data
+    { "STARCORE",  NULL,       0x08, false  }, // Pixel contains a bright star core
+    // Effects of convolution and interpolation
+    { "CONV.BAD",  NULL,       0x02, true  }, // Pixel is bad after convolution with a bad pixel
+    { "CONV.POOR", NULL,       0x04, false }, // Pixel is poor after convolution with a bad pixel
+};
+
 bool ppImageSetMaskBits (pmConfig *config, ppImageOptions *options) {
 
-    if (!pmConfigMaskSetBits(&options->maskValue, &options->markValue, config)) {
-        psError (PS_ERR_UNKNOWN, true, "Unable to define the mask bit values");
-        return false;
+
+    // Look up recipe values
+    psMetadata *pprecipe = psMetadataLookupMetadata(NULL, config->recipes, RECIPE_NAME);
+
+    psAssert(pprecipe, "We checked this earlier, so it should be here.");
+    bool doDetectCTE = psMetadataLookupBool(NULL, pprecipe, "DETECT.CTE"); // Do detections on pixels underneath CTE masks
+
+    // this function sets the required single-image mask bits
+    if(!doDetectCTE) {
+      if (!pmConfigMaskSetBits (&options->maskValue, &options->markValue, config)) {
+          psError (PS_ERR_UNKNOWN, true, "Unable to define the mask bit values");
+          return false;
+      }
+    } else {
+      psMetadata *maskrecipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
+      if (!maskrecipe) {
+          psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
+          return false;
+      }
+      if (!ppImageMaskSetInMetadata(&options->maskValue, &options->markValue, maskrecipe)) {
+          psError (PS_ERR_UNKNOWN, true, "Unable to determine the mask value");
+          return false;
+      }
     }
 
@@ -63,2 +115,70 @@
     return true;
 }
+
+
+bool ppImageMaskSetInMetadata(psImageMaskType *outMaskValue, // Value of MASK.VALUE, returned
+                               psImageMaskType *outMarkValue, // Value of MARK.VALUE, returned
+                               psMetadata *source  // Source of mask bits
+    )
+{
+    PS_ASSERT_METADATA_NON_NULL(source, false);
+
+    // Ensure all the bad mask names exist, and set the value to catch all bad pixels
+    psImageMaskType maskValue = 0;           // Value to mask to catch all the bad pixels
+    psImageMaskType allMasks = 0;            // Value to mask to catch all masked bits (to set MARK)
+
+    int nMasks = sizeof (ppimagemasks) / sizeof (pmConfigMaskInfo);
+
+    for (int i = 0; i < nMasks; i++) {
+        bool mdok;                      // Status of MD lookup
+        psImageMaskType value = psMetadataLookupImageMaskFromGeneric(&mdok, source, ppimagemasks[i].badMaskName); // Value of mask
+        if (!mdok) {
+            psWarning ("problem with mask value %s\n", ppimagemasks[i].badMaskName);
+        }
+
+        if (!value) {
+            if (ppimagemasks[i].fallbackName) {
+                value = psMetadataLookupImageMaskFromGeneric(&mdok, source, ppimagemasks[i].fallbackName);
+            }
+            if (!value) {
+                value = ppimagemasks[i].defaultMaskValue;
+            }
+            psMetadataAddImageMask(source, PS_LIST_TAIL, ppimagemasks[i].badMaskName, PS_META_REPLACE, NULL, value);
+        }
+        if (ppimagemasks[i].isBad) {
+            maskValue |= value;
+        }
+        allMasks |= value;
+    }
+
+    // search for an unset bit to use for MARK:
+    psImageMaskType markValue = 0x00;
+    psImageMaskType markTrial = 0x01;
+
+    int nBits = sizeof(psImageMaskType) * 8;
+    for (int i = 0; !markValue && (i < nBits); i++) {
+        if (allMasks & markTrial) {
+            markTrial <<= 1;
+        } else {
+            markValue = markTrial;
+        }
+    }
+    if (!markValue) {
+        psError (PS_ERR_UNKNOWN, true, "Unable to define the MARK bit mask: all bits taken!");
+        return false;
+    }
+
+    // update the list with the results
+    psMetadataAddImageMask(source, PS_LIST_TAIL, "MASK.VALUE", PS_META_REPLACE, NULL, maskValue);
+    psMetadataAddImageMask(source, PS_LIST_TAIL, "MARK.VALUE", PS_META_REPLACE, NULL, markValue);
+
+    if (outMaskValue) {
+        *outMaskValue = maskValue;
+    }
+    if (outMarkValue) {
+        *outMarkValue = markValue;
+    }
+
+    return true;
+}
+
Index: /trunk/ppSub/src/ppSubSetMasks.c
===================================================================
--- /trunk/ppSub/src/ppSubSetMasks.c	(revision 42292)
+++ /trunk/ppSub/src/ppSubSetMasks.c	(revision 42293)
@@ -32,7 +32,7 @@
 static pmConfigMaskInfo skycellmasks[] = {
     // Features of the detector
-    { "DETECTOR",  NULL,       0x01, false }, // Something is wrong with the detector
-    { "FLAT",      "DETECTOR", 0x01, false }, // Pixel doesn't flat-field properly
-    { "DARK",      "DETECTOR", 0x01, false }, // Pixel doesn't dark-subtract properly
+    { "DETECTOR",  NULL,       0x01, true }, // Something is wrong with the detector
+    { "FLAT",      "DETECTOR", 0x01, true }, // Pixel doesn't flat-field properly
+    { "DARK",      "DETECTOR", 0x01, true }, // Pixel doesn't dark-subtract properly
     { "BLANK",     "DETECTOR", 0x01, true }, // Pixel doesn't contain valid data
     { "CTE",       "DETECTOR", 0x01, false }, // Pixel has poor CTE
Index: /trunk/psModules/src/objects/pmSourceMasks.h
===================================================================
--- /trunk/psModules/src/objects/pmSourceMasks.h	(revision 42292)
+++ /trunk/psModules/src/objects/pmSourceMasks.h	(revision 42293)
@@ -72,4 +72,5 @@
     PM_SOURCE_MODE2_ON_GHOST      	  = 0x00800000, ///< > 25% of (PSF-weighted) pixels land on ghost
     PM_SOURCE_MODE2_ON_CROSSTALK      	  = 0x01000000, ///< peaks land on electronic crostalk
+    PM_SOURCE_MODE2_ON_CTE      	  = 0x02000000, ///< peaks land on CTE region
 
     
Index: /trunk/psModules/src/objects/pmSourcePhotometry.c
===================================================================
--- /trunk/psModules/src/objects/pmSourcePhotometry.c	(revision 42292)
+++ /trunk/psModules/src/objects/pmSourcePhotometry.c	(revision 42293)
@@ -53,12 +53,13 @@
 
 // make this a bit more clever and dynamic
-static psImageMaskType maskSuspect  = 0;
-static psImageMaskType maskSpike    = 0;
-static psImageMaskType maskStarCore = 0;
-static psImageMaskType maskBurntool = 0;
-static psImageMaskType maskConvPoor = 0;
-static psImageMaskType maskGhost    = 0;
-static psImageMaskType maskGlint    = 0;
-static psImageMaskType maskCrosstalk    = 0;
+static psImageMaskType maskSuspect   = 0;
+static psImageMaskType maskSpike     = 0;
+static psImageMaskType maskStarCore  = 0;
+static psImageMaskType maskBurntool  = 0;
+static psImageMaskType maskConvPoor  = 0;
+static psImageMaskType maskGhost     = 0;
+static psImageMaskType maskGlint     = 0;
+static psImageMaskType maskCrosstalk = 0;
+static psImageMaskType maskCTE       = 0;
 
 bool pmSourceMagnitudesInit (pmConfig *config, psMetadata *recipe)
@@ -69,12 +70,13 @@
     // we are going to test specially against these poor values
     if (config) {
-	maskSpike    = pmConfigMaskGet("SPIKE", config);
-	maskStarCore = pmConfigMaskGet("STARCORE", config);
-	maskBurntool = pmConfigMaskGet("BURNTOOL", config);
-	maskConvPoor = pmConfigMaskGet("CONV.POOR", config);
-	maskGhost    = pmConfigMaskGet("GHOST", config);
-	maskGlint    = pmConfigMaskGet("GHOST", config);
-	maskCrosstalk    = pmConfigMaskGet("CROSSTALK", config);
-	maskSuspect  = maskSpike | maskStarCore | maskBurntool | maskConvPoor;
+	maskSpike     = pmConfigMaskGet("SPIKE", config);
+	maskStarCore  = pmConfigMaskGet("STARCORE", config);
+	maskBurntool  = pmConfigMaskGet("BURNTOOL", config);
+	maskConvPoor  = pmConfigMaskGet("CONV.POOR", config);
+	maskGhost     = pmConfigMaskGet("GHOST", config);
+	maskGlint     = pmConfigMaskGet("GHOST", config);
+	maskCrosstalk = pmConfigMaskGet("CROSSTALK", config);
+	maskCTE       = pmConfigMaskGet("CTE", config);
+	maskSuspect   = maskSpike | maskStarCore | maskBurntool | maskConvPoor;
     }
 
@@ -440,4 +442,5 @@
     float convpoorSum = 0;
     float ghostSum = 0;
+    float cteSum = 0;
 
     int Xo, Yo, dP;
@@ -534,4 +537,9 @@
 		convpoorSum += value;
 	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskCTE) {
+		cteSum += value;
+	    }
+
         }
     }
@@ -555,4 +563,7 @@
     if ((convpoorSum/modelSum) > 0.25) {
 	source->mode2 |= PM_SOURCE_MODE2_ON_CONVPOOR;
+    }
+    if ((cteSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_CTE;
     }
 
@@ -614,4 +625,5 @@
     float convpoorSum = 0;
     float ghostSum = 0;
+    float cteSum = 0;
 
     int Xo, Yo, dP;
@@ -683,4 +695,8 @@
 		convpoorSum += 1.;
 	    }
+	    // count pixels which are masked with an mask bit (bad or poor)
+            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[my][mx] & maskCTE) {
+                cteSum += 1.;
+            }
         }
     }
@@ -701,4 +717,7 @@
     if ((convpoorSum/modelSum) > 0.25) {
 	source->mode2 |= PM_SOURCE_MODE2_ON_CONVPOOR;
+    }
+    if ((cteSum/modelSum) > 0.25) {
+	source->mode2 |= PM_SOURCE_MODE2_ON_CTE;
     }
 
Index: /trunk/psastro/src/psastroConvert.c
===================================================================
--- /trunk/psastro/src/psastroConvert.c	(revision 42292)
+++ /trunk/psastro/src/psastroConvert.c	(revision 42293)
@@ -18,5 +18,5 @@
 # define PHOT_SOURCE_MASK (PM_SOURCE_MODE_FAIL | PM_SOURCE_MODE_BLEND | PM_SOURCE_MODE_BADPSF | \
                            PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT | \
-                           PM_SOURCE_MODE_POOR) // Mask to apply to sources for rejection
+                           PM_SOURCE_MODE_POOR ) // Mask to apply to sources for rejection
 
 static psArray *chooseStars(psArray *inStars, char *listName, psArray *sources, psVector *index, int nMax, float iMagMin, float iMagMax, pmSourceMode skip);
@@ -193,4 +193,5 @@
     int nBrightSkip = 0;
     int nInfSkip = 0;
+    int nCTESkip = 0;
 
     for (int i = 0; (i < inStars->n) && (j < rawStars->n); i++) {
@@ -217,4 +218,10 @@
           continue;
         }
+	//Also kick out stars that touch the CTE region
+        if (source->mode2 & PM_SOURCE_MODE2_ON_CTE) {
+            nCTESkip ++;
+            continue;
+        }
+	
         mMin = PS_MIN (mMin, source->psfMag);
         mMax = PS_MAX (mMax, source->psfMag);
@@ -225,5 +232,5 @@
 
     psLogMsg ("psastro", 4, "loaded %ld %ssources, using %ld of %ld good sources (inst mag: %f to %f)\n", sources->n, listName, rawStars->n, inStars->n, mMin, mMax);
-    psLogMsg ("psastro", 4, "skip reasons: mode: %d, faint: %d, bright: %d, inf: %d\n", nModeSkip, nFaintSkip, nBrightSkip, nInfSkip);
+    psLogMsg ("psastro", 4, "skip reasons: mode: %d, faint: %d, bright: %d, inf: %d, CTE: %d\n", nModeSkip, nFaintSkip, nBrightSkip, nInfSkip,nCTESkip);
 
     return rawStars;
@@ -509,4 +516,6 @@
   float myPltScale = fabs(pltScale[chipID]);
 
+  psLogMsg ("psastro.correctKH", PS_LOG_INFO, "applying KH correction to %s (%d)\n", chipName, chipID);
+
   // apply the correction to the detections
   for (int i = 0; i < inStars->n; i++) {
Index: /trunk/pswarp/src/pswarpSetMaskBits.c
===================================================================
--- /trunk/pswarp/src/pswarpSetMaskBits.c	(revision 42292)
+++ /trunk/pswarp/src/pswarpSetMaskBits.c	(revision 42293)
@@ -20,4 +20,5 @@
  * updated in the config metadata.
  */
+ 
 bool pswarpSetMaskBits (pmConfig *config)
 {
@@ -26,10 +27,27 @@
     psImageMaskType maskOut = 0x00;                     // mask for the output image
 
+    // Look up recipe values
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PSWARP_RECIPE); // Recipe for ppSim
+    psAssert(recipe, "We checked this earlier, so it should be here.");
+    bool doDetectCTE = psMetadataLookupBool(NULL, recipe, "DETECT.CTE"); // Do detections on pixels underneath CTE masks
+
     // this function sets the required single-image mask bits
-    if (!pmConfigMaskSetBits (&maskIn, &markIn, config)) {
-        psError (psErrorCodeLast(), false, "Unable to define the mask bit values");
-        return false;
+    if(!doDetectCTE) {
+      if (!pmConfigMaskSetBits (&maskIn, &markIn, config)) {
+          psError (psErrorCodeLast(), false, "Unable to define the mask bit values");
+          return false;
+      }
+    } else {
+      psMetadata *maskrecipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
+      if (!maskrecipe) {
+          psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
+          return false;
+      }
+      if (!pswarpMaskSetInMetadata(&maskIn, &markIn, maskrecipe)) {
+          psError (psErrorCodeLast(), false, "Unable to determine the mask value");
+          return false;
+      }
     }
-
+    
     // mask for non-linear flat regions (default to DETECTOR if not defined)
     psImageMaskType badMask = pmConfigMaskGet("CONV.BAD", config);
