Index: trunk/ppSub/src/ppSubSetMasks.c
===================================================================
--- trunk/ppSub/src/ppSubSetMasks.c	(revision 30619)
+++ 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;
+}
+
