Index: trunk/ppSub/src/ppSub.h
===================================================================
--- trunk/ppSub/src/ppSub.h	(revision 40742)
+++ trunk/ppSub/src/ppSub.h	(revision 41382)
@@ -190,4 +190,17 @@
 void ppSubSetThreads (void);
 
+// ppSubMaskSetInMetadata examines named mask values and set the bits for maskValue and
+// markValue.  Ensures that the below-named mask values are set, and calculates the mask value
+// to catch all of the mask values marked as 'bad'.  Supplies the fallback name if the primary
+// name is not found, or the default values if the fallback name is not found.
+bool ppSubMaskSetInMetadata(psImageMaskType *outMaskValue, // Value of MASK.VALUE, returned
+                               psImageMaskType *outMarkValue, // Value of MARK.VALUE, returned
+                               psMetadata *source  // Source of mask bits
+  );
+
+// lookup an image mask value by name from a psMetadata, without requiring the entry to
+// be of type psImageMaskType, but verifying that it will fit in psImageMaskType
+psImageMaskType psMetadataLookupImageMaskFromGeneric (bool *status, const psMetadata *md, const char *name);
+
 ///@}
 #endif
Index: trunk/ppSub/src/ppSubBackground.c
===================================================================
--- trunk/ppSub/src/ppSubBackground.c	(revision 40742)
+++ trunk/ppSub/src/ppSubBackground.c	(revision 41382)
@@ -33,4 +33,6 @@
     psAssert(psphotRecipe, "Need PSPHOT recipe for binning");
 
+    bool doApplyMaskNaN = psMetadataLookupBool(&mdok, ppSubRecipe, "APPLY.PIXELNAN"); // NaN the pixels underneath masks
+
     psImageMaskType maskBad = pmConfigMaskGet("BLANK", config); // Bits to mask
 
@@ -64,9 +66,11 @@
         for (int x = 0; x < numCols; x++) {
 	    // special case 1: NAN the masked pixels
-            if (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskBad) {
+            if(doApplyMaskNaN) {
+              if (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskBad) {
                 image->data.F32[y][x] = NAN;
 		continue;
-            } 
-	    // special case 1: NAN & mask pixels without a valid background model
+              } 
+            }
+	    // special case 2: NAN & mask pixels without a valid background model
 	    float value = psImageUnbinPixel(x + 0.5, y + 0.5, modelImage, binning); // Background value
 	    if (!isfinite(value)) {
Index: trunk/ppSub/src/ppSubReadoutSubtract.c
===================================================================
--- trunk/ppSub/src/ppSubReadoutSubtract.c	(revision 40742)
+++ trunk/ppSub/src/ppSubReadoutSubtract.c	(revision 41382)
@@ -33,4 +33,5 @@
     bool noConvolve = psMetadataLookupBool(&mdok, recipe, "NOCONVOLVE"); // Do not use convolved images.
     bool addPair = psMetadataLookupBool(&mdok, recipe, "ADD.NOT.SUBTRACT"); // add instead of subtracting
+    bool doApplyMaskNaN = psMetadataLookupBool(&mdok, recipe, "APPLY.PIXELNAN"); // NaN the pixels underneath masks
 
     pmFPAview *view = ppSubViewReadout(); // View to readout
@@ -73,9 +74,11 @@
     // NAN the masked pixels in the diff image (pixels masked in A are not yet NAN'ed in B)
     psImageMaskType maskVal = pmConfigMaskGet("MASK.VALUE", config) | pmConfigMaskGet("BLANK", config); // Bits to mask in inputs
-    for (int iy = 0; iy < outRO->image->numRows; iy++) {
+    if(doApplyMaskNaN) {
+      for (int iy = 0; iy < outRO->image->numRows; iy++) {
 	for (int ix = 0; ix < outRO->image->numCols; ix++) {
 	    if ((outRO->mask->data.PS_TYPE_IMAGE_MASK_DATA[iy][ix] & maskVal) == 0) continue;
 	    outRO->image->data.F32[iy][ix] = NAN;
 	}
+      }
     }
 
Index: trunk/ppSub/src/ppSubSetMasks.c
===================================================================
--- trunk/ppSub/src/ppSubSetMasks.c	(revision 40742)
+++ trunk/ppSub/src/ppSubSetMasks.c	(revision 41382)
@@ -22,20 +22,65 @@
 #include "ppSub.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 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
+    { "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 streak 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 ppSubSetMasks(pmConfig *config)
 {
     psAssert(config, "Require configuration");
 
-    psImageMaskType maskValue, markValue; // Mask values
-    if (!pmConfigMaskSetBits(&maskValue, &markValue, config)) {
-        psError(PPSUB_ERR_CONFIG, false, "Unable to determine mask value.");
-        return false;
-    }
-
-    // Set the mask bits needed by psphot (in psphot recipe)
-    psphotSetMaskRecipe(config, maskValue, markValue);
-
     // Look up recipe values
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
     psAssert(recipe, "We checked this earlier, so it should be here.");
+    bool doApplyMaskNaN = psMetadataLookupBool(NULL, recipe, "APPLY.PIXELNAN"); // NaN the pixels underneath masks
+
+    psImageMaskType maskValue, markValue; // Mask values
+    if(doApplyMaskNaN) {
+      if (!pmConfigMaskSetBits(&maskValue, &markValue, config)) {
+          psError(PPSUB_ERR_CONFIG, false, "Unable to determine mask value.");
+          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 (!ppSubMaskSetInMetadata(&maskValue, &markValue, maskrecipe)) {
+          psError(PPSUB_ERR_CONFIG, false, "Unable to determine mask value.");
+          return false;
+      }
+    }
+
+    // Set the mask bits needed by psphot (in psphot recipe)
+    psphotSetMaskRecipe(config, maskValue, markValue);
+
 
     psImageMaskType satValue = pmConfigMaskGet("SAT", config);
@@ -121,2 +166,69 @@
     return true;
 }
+
+bool ppSubMaskSetInMetadata(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 (skycellmasks) / sizeof (pmConfigMaskInfo);
+
+    for (int i = 0; i < nMasks; i++) {
+        bool mdok;                      // Status of MD lookup
+        psImageMaskType value = psMetadataLookupImageMaskFromGeneric(&mdok, source, skycellmasks[i].badMaskName); // Value of mask
+        if (!mdok) {
+            psWarning ("problem with mask value %s\n", skycellmasks[i].badMaskName);
+        }
+
+        if (!value) {
+            if (skycellmasks[i].fallbackName) {
+                value = psMetadataLookupImageMaskFromGeneric(&mdok, source, skycellmasks[i].fallbackName);
+            }
+            if (!value) {
+                value = skycellmasks[i].defaultMaskValue;
+            }
+            psMetadataAddImageMask(source, PS_LIST_TAIL, skycellmasks[i].badMaskName, PS_META_REPLACE, NULL, value);
+        }
+        if (skycellmasks[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;
+}
+
