Index: /branches/eam_branch_20080706/ppImage/src/Makefile.am
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/Makefile.am	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/Makefile.am	(revision 18472)
@@ -29,4 +29,5 @@
 	ppImageReplaceBackground.c \
 	ppImageDefineFile.c \
+	ppImageSetMaskBits.c \
 	ppImageFileCheck.c \
 	ppImageVersion.c \
@@ -58,4 +59,5 @@
 	ppImageReplaceBackground.c \
 	ppImageDefineFile.c \
+	ppImageSetMaskBits.c \
 	ppImageFileCheck.c \
 	ppImageVersion.c \
Index: /branches/eam_branch_20080706/ppImage/src/ppImage.h
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImage.h	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImage.h	(revision 18472)
@@ -56,4 +56,5 @@
     // make values for abstract concepts of masking
     psMaskType maskValue;               // apply this bit-mask to choose masked bits
+    psMaskType markValue;               // apply this bit-mask to choose masked bits
     psMaskType satMask;                 // Mask value to give saturated pixels
     psMaskType badMask;                 // Mask value to give bad pixels
@@ -101,4 +102,5 @@
 // Determine what type of camera, and initialise
 ppImageOptions *ppImageParseCamera(pmConfig *config);
+bool ppImageSetMaskBits (pmConfig *config, ppImageOptions *options);
 
 // Loop over the input
@@ -134,4 +136,6 @@
 bool ppImageMosaicFPA (pmConfig *config, const ppImageOptions *options,
                        const char *outFile, const char *inFile);
+
+bool ppImageSetMaskBits (pmConfig *config, ppImageOptions *options);
 
 void ppImageFileCheck (pmConfig *config);
Index: /branches/eam_branch_20080706/ppImage/src/ppImageDetrendReadout.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageDetrendReadout.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageDetrendReadout.c	(revision 18472)
@@ -74,5 +74,5 @@
     if (options->doShutter) {
         pmReadout *shutter = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.SHUTTER");
-        if (!pmShutterCorrectionApply(input, shutter, pmConfigMask("FLAT", config))) {
+        if (!pmShutterCorrectionApply(input, shutter, pmConfigMaskGet("FLAT", config))) {
             return false;
         }
Index: /branches/eam_branch_20080706/ppImage/src/ppImageLoop.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageLoop.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageLoop.c	(revision 18472)
@@ -65,5 +65,6 @@
 		// XXX set the options->*Mask values here (after the mask images have been loaded
 		// and before any of the value are used)
-		ppImageSetMaskBits (config, options);
+		if (!ppImageSetMaskBits (config, options)) 
+		    ESCAPE ("Unable to set bit masks");
 
                 // perform the detrend analysis
Index: /branches/eam_branch_20080706/ppImage/src/ppImageMetadataStats.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageMetadataStats.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageMetadataStats.c	(revision 18472)
@@ -13,7 +13,4 @@
 	return true;
     }
-
-    // XXX should this be just options->maskValue?? I think so...
-    psMaskType maskVal = options->satMask | options->badMask | options->maskValue;
 
     // Extract statistics from the last output fpa
@@ -51,5 +48,5 @@
     pmFPAview *view = pmFPAviewAlloc(0);
 
-    if (!ppStatsMetadata(stats, output->fpa, view, maskVal, config)) {
+    if (!ppStatsMetadata(stats, output->fpa, view, options->maskValue, config)) {
 	psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate stats for image.");
 	psFree(view);
Index: /branches/eam_branch_20080706/ppImage/src/ppImageMosaic.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageMosaic.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageMosaic.c	(revision 18472)
@@ -32,7 +32,6 @@
             in->name, out->name, in->xBin, in->yBin, out->xBin, out->yBin);
 
-    // XXX mosaic the chip, making a deep copy.  this has the side effect of making the
-    // output image products pure trimmed images, but also increases the memory footprint.
-    // XXX I think we should be using options->maskValue
+    // Mosaic the chip, making a deep copy.  This has the side effect of making the output
+    // image products pure trimmed images, but also increases the memory footprint.
     status = pmChipMosaic(outChip, inChip, true, options->blankMask);
     return status;
Index: /branches/eam_branch_20080706/ppImage/src/ppImageOptions.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageOptions.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageOptions.c	(revision 18472)
@@ -50,9 +50,10 @@
 
     // default flags for various activities
-    options->maskValue       = 0x00;    // Default mask value
-    options->satMask         = 0x00;    // Saturated pixels
-    options->badMask         = 0x00;    // Bad pixels
-    options->flatMask        = 0x00;    // Bad flat pixels
-    options->blankMask       = 0x00;    // Blank (no data, cell gap) pixels
+    options->maskValue       = 0x00;    // Default mask value (used to skip / ignore pixels)
+    options->satMask         = 0x00;    // Saturated pixels (supplied to pmReadoutGenerateMask)
+    options->badMask         = 0x00;    // Bad (low) pixels (supplied to pmReadoutGenerateMask)
+    options->flatMask        = 0x00;    // Bad flat pixels (supplied to pmFlatField)
+    options->blankMask       = 0x00;    // Blank (no data, cell gap) pixels (supplied to pmChipMosaic, pmFPAMosaic)
+    options->markValue       = 0x00;    // A safe bit for internal marking
 
     // Non-linearity default options
@@ -190,19 +191,6 @@
     options->doWeightBuild = psMetadataLookupBool(NULL, recipe, "WEIGHT.BUILD");
 
-    // Mask recipe options
-    // XXX we cannot set these values here; wait until just before ppImageDetrend
+    // Mask recipe options (note that mask bit values are set in ppImageSetMaskBits.c)
     options->doMask = psMetadataLookupBool(NULL, recipe, "MASK");
-
-# if (0)    
-    const char *masks = psMetadataLookupStr(&status, recipe, "MASK.VALUE");
-    if (status) {
-        options->maskValue = pmConfigMask(masks, config);
-    }
-    options->satMask = pmConfigMask("SAT", config);
-    options->badMask = pmConfigMask("BAD", config);
-    options->flatMask = pmConfigMask("FLAT", config);
-    options->blankMask = pmConfigMask("BLANK", config);
-    // XXX should it be an error for these to not exist?
-# endif
 
     options->doBias = psMetadataLookupBool(NULL, recipe, "BIAS");
Index: /branches/eam_branch_20080706/ppImage/src/ppImagePixelStats.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImagePixelStats.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImagePixelStats.c	(revision 18472)
@@ -9,7 +9,4 @@
 
     bool mdok;              // Status of MD lookup
-
-    // XXX should this be just options->maskValue?? I think so...
-    psMaskType maskVal = options->satMask | options->badMask | options->maskValue;
 
     // loop over the cells/readouts for this chip
@@ -49,5 +46,5 @@
 	}
 
-	if (!ppStatsPixels(stats, output->fpa, view, maskVal, config)) {
+	if (!ppStatsPixels(stats, output->fpa, view, options->maskValue, config)) {
 	    psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate stats for image.");
 	    psFree (view);
Index: /branches/eam_branch_20080706/ppImage/src/ppImageReplaceBackground.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageReplaceBackground.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageReplaceBackground.c	(revision 18472)
@@ -40,7 +40,7 @@
     psAssert (replaceSkyMode != MODE_NONE, "replace sky mode not defined");
 
-    // define the mask value to be used in ppImage
-    // XXX should this be just options->maskValue?? I think so...  (but it should certainly include flat!)
-    psMaskType maskVal  = options->satMask | options->badMask | options->flatMask | options->blankMask;
+    // XXX Should this be options->maskValue or & ~options->satMask? the latter will leave saturated pixels high
+    // psMaskType maskVal  = options->maskValue & ~options->satMask;
+    psMaskType maskVal  = options->maskValue;
 
     pmFPAfile *modelFile = NULL;
Index: /branches/eam_branch_20080706/ppImage/src/ppImageSetMaskBits.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageSetMaskBits.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageSetMaskBits.c	(revision 18472)
@@ -7,30 +7,37 @@
 bool ppImageSetMaskBits (pmConfig *config, ppImageOptions *options) {
 
-    // Mask recipe options
-    const char *masks = psMetadataLookupStr(&status, recipe, "MASK.VALUE");
-    if (status) {
-        options->maskValue = pmConfigMask(masks, config);
+    if (!pmConfigMaskSetBits (&options->maskValue, &options->markValue, config)) {
+	psError (PS_ERR_UNKNOWN, true, "Unable to define the mask bit values");
+	return false;
     }
 
-    darkMask           = pmConfigMask("DARK", 	  config);
-    options->flatMask  = pmConfigMask("FLAT", 	  config);
-    options->blankMask = pmConfigMask("BLANK",	  config);
-    detectorMask       = pmConfigMask("DETECTOR", config);
+    // at this point we know we have valid values for required entries SAT, BAD, FLAT, BLANK:
 
-    options->satMask   = pmConfigMask("SAT",      config);
-    options->badMask   = pmConfigMask("BAD",      config);
+    // mask for non-linear flat corrections
+    options->flatMask = pmConfigMaskGet("FLAT", config); 
+    psAssert (options->flatMask, "flat mask not set");
 
-    rangeMask          = pmConfigMask("RANGE",    config);
+    // mask for non-existent data  (default to DETECTOR if not defined)
+    options->blankMask = pmConfigMaskGet("BLANK", config); 
+    psAssert (options->blankMask, "blank mask not set");
 
-    crMask             = pmConfigMask("CR",       config);
-    ghostMask          = pmConfigMask("GHOST",    config);
+    // mask for saturated data  (default to RANGE if not defined)
+    options->satMask = pmConfigMaskGet("SAT", config);
+    psAssert (options->satMask, "sat mask not set");
+    
+    // mask for below-range data  (default to RANGE if not defined)
+    options->badMask = pmConfigMaskGet("BAD", config);
+    psAssert (options->badMask, "bad mask not set");
 
-    // XXX it should be an error for these to not exist
-    if (!options->flatMask) {
-      psWarning ("FLAT MASK is not set");
+    // save MASK and MARK on the PSPHOT recipe
+    psMetadata *recipe = psMetadataLookupPtr (NULL, config->recipes, PSPHOT_RECIPE);
+    if (!recipe) {
+        psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSPHOT_RECIPE);
+        return false;
     }
-    if (!options->flatMask) {
-      psWarning ("FLAT MASK is not set");
-    }
+
+    // set maskValue and markValue in the psphot recipe
+    psMetadataAddU8 (recipe, PS_LIST_TAIL, "MASK.PSPHOT", PS_META_REPLACE, "user-defined mask", options->maskValue);
+    psMetadataAddU8 (recipe, PS_LIST_TAIL, "MARK.PSPHOT", PS_META_REPLACE, "user-defined mask", options->markValue);
 
     return true;
Index: /branches/eam_branch_20080706/ppImage/src/ppImageStats.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageStats.c	(revision 18471)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageStats.c	(revision 18472)
@@ -57,7 +57,5 @@
 	    }
 
-	    if (!ppStatsFPA(stats, output->fpa, view,
-			 options->satMask | options->badMask | options->maskValue,
-			 config)) {
+	    if (!ppStatsFPA(stats, output->fpa, view, options->maskValue, config)) {
 		psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate stats for image.");
 		psFree(view);
Index: /branches/eam_branch_20080706/psModules/src/camera/pmFPAMaskWeight.h
===================================================================
--- /branches/eam_branch_20080706/psModules/src/camera/pmFPAMaskWeight.h	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/camera/pmFPAMaskWeight.h	(revision 18472)
@@ -5,6 +5,6 @@
  * @author Eugene Magnier, IfA
  *
- * @version $Revision: 1.13 $ $Name: not supported by cvs2svn $
- * @date $Date: 2008-05-17 02:42:01 $
+ * @version $Revision: 1.13.8.1 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2008-07-11 18:35:04 $
  * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
  */
@@ -32,5 +32,4 @@
     PM_MASK_MARK     = 0x80,            ///< The pixel is marked as temporarily ignored
 } pmMaskValue;
-#else
 #define PM_MASK_MARK 0x80            ///< The pixel is marked as temporarily ignored
 #define PM_MASK_SAT  0x04            ///< The pixel is saturated in the image of interest
@@ -43,6 +42,6 @@
 /// iterating using pmReadoutReadNext, in which case the HDU can't be generated.
 bool pmReadoutSetMask(pmReadout *readout, ///< Readout for which to set mask
-                      psMaskType sat,   ///< Mask value to give saturated pixels
-                      psMaskType bad    ///< Mask value to give bad (low) pixels
+                      psMaskType satMask, ///< Mask value to give saturated pixels
+                      psMaskType badMask  ///< Mask value to give bad (low) pixels
     );
 
Index: /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileFitsIO.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileFitsIO.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileFitsIO.c	(revision 18472)
@@ -7,4 +7,5 @@
 
 #include "pmConfig.h"
+#include "pmConfigMask.h"
 #include "pmDetrendDB.h"
 
@@ -496,4 +497,13 @@
     }
 
+    // whenever we write out a mask image, we should define the bits which represent mask concepts
+    if (file->type == PM_FPA_FILE_MASK) {
+	assert (phu->header);
+	if (!pmConfigMaskWriteHeader (config, phu->header)) {
+	    psError(PS_ERR_UNKNOWN, false, "failed to set the bitmask names in the PHU header for Image %s (%s)\n", file->filename, file->name);
+	    return false;
+	}
+    }
+
     switch (file->fileLevel) {
       case PM_FPA_LEVEL_FPA:
Index: /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileIO.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileIO.c	(revision 18472)
@@ -9,4 +9,5 @@
 
 #include "pmConfig.h"
+#include "pmConfigMask.h"
 #include "pmDetrendDB.h"
 
@@ -428,4 +429,13 @@
             }
             pmConfigConformHeader(hdu->header, file->format);
+
+	    // whenever we write out a mask image, we should define the bits which represent mask concepts
+	    if (file->type == PM_FPA_FILE_MASK) {
+		assert (hdu->header);
+		if (!pmConfigMaskWriteHeader (config, hdu->header)) {
+		    psError(PS_ERR_UNKNOWN, false, "failed to set the bitmask names in the PHU header for Image %s (%s)\n", file->filename, file->name);
+		    return false;
+		}
+	    }
         }
 
Index: /branches/eam_branch_20080706/psModules/src/camera/pmHDUUtils.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/camera/pmHDUUtils.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/camera/pmHDUUtils.c	(revision 18472)
@@ -12,21 +12,21 @@
 pmHDU *pmHDUGetFirst (const pmFPA *fpa) {
 
-  // XXX we probably should have an indicator in pmFPA about the depths.
+    // XXX we probably should have an indicator in pmFPA about the depths.
 
-  if (!fpa) return NULL;
-  if (fpa->hdu) return fpa->hdu;
+    if (!fpa) return NULL;
+    if (fpa->hdu) return fpa->hdu;
 
-  for (int i = 0; i < fpa->chips->n; i++) {
-    pmChip *chip = fpa->chips[i];
-    if (!chip) continue;
-    if (chip->hdu) return chip->hdu;
-    if (!chip->cells) continue;
-    for (int j = 0; j < chip->cells->n; j++) {
-      pmCell *cell = chip->cells[j];
-      if (!cell) continue;
-      if (cell->hdu) return cell->hdu;
+    for (int i = 0; i < fpa->chips->n; i++) {
+	pmChip *chip = fpa->chips->data[i];
+	if (!chip) continue;
+	if (chip->hdu) return chip->hdu;
+	if (!chip->cells) continue;
+	for (int j = 0; j < chip->cells->n; j++) {
+	    pmCell *cell = chip->cells->data[j];
+	    if (!cell) continue;
+	    if (cell->hdu) return cell->hdu;
+	}
     }
-  }
-  return NULL;
+    return NULL;
 }
 
Index: /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.c	(revision 18472)
@@ -9,5 +9,5 @@
 #include "pmConfigMask.h"
 
-psMaskType pmConfigMask(const char *masks, const pmConfig *config)
+psMaskType pmConfigMaskGet(const char *masks, const pmConfig *config)
 {
     assert (config);
@@ -40,7 +40,27 @@
 }
 
+bool pmConfigMaskSet(const pmConfig *config, const char *maskName, psMaskType maskValue)
+{
+    assert (config);
+    PS_ASSERT_STRING_NON_EMPTY(maskName, false);
+
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
+    if (!recipe) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
+        return false;
+    }
+
+    psMetadataAddU8 (recipe, PS_LIST_TAIL, maskName, PS_META_REPLACE, "user-defined mask", maskValue);
+
+    return true;
+}
+
 // replace the named masks in the recipe with values in the header:
 // replace only the names in the header in the recipe
-void pmConfigMasksReadHeader (pmConfig *config, psMetadata *header) {
+bool pmConfigMaskReadHeader (pmConfig *config, psMetadata *header) {
+
+    bool status = false;
+    char namekey[80];
+    char valuekey[80];
 
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
@@ -68,8 +88,8 @@
 	psMetadataItem *item = psMetadataLookup (header, name);
 	if (!item) {
-	  psWarning("mask recipe entry %s not in recipe\n", name);
-	  psMetadataAddU8 (recipe, PS_LIST_TAIL, name, 0, "Bitmask bit value", bit);
+	    psWarning("mask recipe entry %s not in recipe\n", name);
+	    psMetadataAddU8 (recipe, PS_LIST_TAIL, name, 0, "Bitmask bit value", bit);
 	} else {
-	  item->data.U8 = bit;
+	    item->data.U8 = bit;
 	}
     }
@@ -79,5 +99,8 @@
 
 // write the named mask bits to the header
-bool pmConfigMasksWriteHeader (pmConfig *config, psMetadata *header) {
+bool pmConfigMaskWriteHeader (pmConfig *config, psMetadata *header) {
+
+    char namekey[80];
+    char valuekey[80];
 
     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
@@ -110,2 +133,108 @@
     return true;
 }
+
+// examine named mask values in mask recipe and set the bits for maskValue and markValue
+// this function sets an appropriate value for the following required named mask concepts: 
+// FLAT (used to mark out-of-range corrections in the flat-fielding)
+// BLANK (used to mark non-existent pixels)
+// SAT (used to mark pixels with values out-of-range on the high end)
+// BAD (used to mark pixels with values out-of-range on the low end)
+// If there is no explicit value for the above, the 'DETECTOR' and 'RANGE' bits are used
+// If these latter do not exist, the value 0x01 is used.
+// The values actually used for these names are written back to the config file
+bool pmConfigMaskSetBits (psMaskType *outMaskValue, psMaskType *outMarkValue, pmConfig *config) {
+
+    psMaskType maskValue = 0;
+
+    // mask for generic detector defect
+    psMaskType detectorMask = pmConfigMaskGet("DETECTOR", config); 
+    maskValue |= detectorMask;
+
+    // mask for dark structures
+    psMaskType darkMask = pmConfigMaskGet("DARK", config);
+    maskValue |= darkMask;
+
+    // mask for non-linear flat regions (default to DETECTOR if not defined)
+    psMaskType flatMask = pmConfigMaskGet("FLAT", config); 
+    if (!flatMask) {
+	flatMask = detectorMask;
+	pmConfigMaskSet (config, "FLAT", flatMask);
+    }
+    if (!flatMask) {
+	flatMask = 0x01;
+	pmConfigMaskSet (config, "FLAT", flatMask);
+    }
+    maskValue |= flatMask;
+
+    // mask for non-existent data  (default to DETECTOR if not defined)
+    psMaskType blankMask = pmConfigMaskGet("BLANK", config); 
+    if (!blankMask) {
+	blankMask = detectorMask;
+	pmConfigMaskSet (config, "BLANK", blankMask);
+    }
+    if (!blankMask) {
+	blankMask = 0x01;
+	pmConfigMaskSet (config, "BLANK", blankMask);
+    }
+    maskValue |= blankMask;
+
+    // mask for generic data range errors
+    psMaskType rangeMask = pmConfigMaskGet("RANGE", config);
+    maskValue |= rangeMask;
+
+    // mask for saturated data  (default to RANGE if not defined)
+    psMaskType satMask = pmConfigMaskGet("SAT", config);
+    if (!satMask) {
+	satMask = rangeMask;
+	pmConfigMaskSet (config, "SAT", satMask);
+    }
+    if (!satMask) {
+	satMask = 0x01;
+	pmConfigMaskSet (config, "SAT", satMask);
+    }
+    maskValue |= satMask;
+    
+    // mask for below-range data  (default to RANGE if not defined)
+    psMaskType badMask = pmConfigMaskGet("BAD", config);
+    if (!badMask) {
+	badMask = rangeMask;
+	pmConfigMaskSet (config, "BAD", badMask);
+    }
+    if (!badMask) {
+	badMask = 0x01;
+	pmConfigMaskSet (config, "BAD", badMask);
+    }
+    maskValue |= badMask;
+
+    // XXX not sure what to do with these
+    psMaskType crMask = pmConfigMaskGet("CR", config);
+    maskValue |= crMask;
+
+    psMaskType ghostMask = pmConfigMaskGet("GHOST", config);
+    maskValue |= ghostMask;
+
+    // search for an unset bit to use for MARK:
+    psMaskType markValue = 0x80;
+
+    int nBits = sizeof(psMaskType) * 8;
+    for (int i = 0; !markValue && (i < nBits); i++) {
+	if (maskValue & markValue) {
+	    markValue >>= 1;
+	} else {
+	    markValue = markValue;
+	}
+    }
+    if (!markValue) {
+	psError (PS_ERR_UNKNOWN, true, "Unable to define the MARK bit mask: all bits taken!");
+	return false;
+    }
+
+    // update the config table
+    pmConfigMaskSet (config, "MASK.VALUE", maskValue);
+    pmConfigMaskSet (config, "MARK.VALUE", markValue);
+
+    *outMaskValue = maskValue;
+    *outMarkValue = markValue;
+
+    return true;
+}
Index: /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.h
===================================================================
--- /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.h	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.h	(revision 18472)
@@ -4,6 +4,6 @@
  *  @author Paul Price, IfA
  *
- *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-03-05 01:06:37 $
+ *  @version $Revision: 1.2.14.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-07-11 18:35:04 $
  *  Copyright 2007 Institute for Astronomy, University of Hawaii
  */
@@ -23,7 +23,18 @@
 ///
 /// The mask values are derived from the MASKS recipe
-psMaskType pmConfigMask(const char *masks, ///< List of symbolic names, space/comma delimited
+psMaskType pmConfigMaskGet(const char *masks, ///< List of symbolic names, space/comma delimited
                         const pmConfig *config ///< Configuration
                         );
 
+bool pmConfigMaskSet(const pmConfig *config, const char *maskName, psMaskType maskValue);
+
+// replace the named masks in the recipe with values in the header:
+// replace only the names in the header in the recipe
+bool pmConfigMaskReadHeader (pmConfig *config, psMetadata *header);
+
+// write the named mask bits to the header
+bool pmConfigMaskWriteHeader (pmConfig *config, psMetadata *header);
+
+bool pmConfigMaskSetBits (psMaskType *outMaskValue, psMaskType *outMarkValue, pmConfig *config);
+
 #endif
Index: /branches/eam_branch_20080706/psModules/src/detrend/pmMaskBadPixels.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/detrend/pmMaskBadPixels.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/detrend/pmMaskBadPixels.c	(revision 18472)
@@ -123,10 +123,11 @@
     psTrace ("psModules.detrend", 3, "suspect: %f +/- %f\n", median, stdev);
 
+    // XXX this loop could result in pixels with suspect = 0.0 but no valid input pixels (all
+    // masked).  need to track the number of good as well as suspect pixels?
     for (int y = 0; y < image->numRows; y++) {
         for (int x = 0; x < image->numCols; x++) {
-            if (fabs((image->data.F32[y][x] - median) / stdev) >= rej &&
-		(!mask || !(mask->data.PS_TYPE_MASK_DATA[y][x] & maskVal))) {
-                suspect->data.F32[y][x] += 1.0;
-            }
+            if (fabs((image->data.F32[y][x] - median) / stdev) < rej) continue;
+	    if (mask && (mask->data.PS_TYPE_MASK_DATA[y][x] & maskVal)) continue;
+	    suspect->data.F32[y][x] += 1.0;
         }
     }
@@ -140,4 +141,5 @@
 }
 
+// the maskVal supplied here is the value SET for this mask (ie, it is not used to avoid pixels)
 bool pmMaskIdentifyBadPixels(pmReadout *output, psMaskType maskVal, float thresh, pmMaskIdentifyMode mode)
 {
Index: /branches/eam_branch_20080706/psModules/src/objects/pmPSF.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/objects/pmPSF.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/objects/pmPSF.c	(revision 18472)
@@ -6,6 +6,6 @@
  *  @author EAM, IfA
  *
- *  @version $Revision: 1.35 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-01-02 20:41:55 $
+ *  @version $Revision: 1.35.18.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-07-11 18:35:04 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -404,5 +404,5 @@
 
 // we generate the growth curve for the center of the image with the specified psf model
-bool pmGrowthCurveGenerate (pmReadout *readout, pmPSF *psf, bool ignore, psMaskType maskVal, psMaskType mark)
+bool pmGrowthCurveGenerate (pmReadout *readout, pmPSF *psf, bool ignore, psMaskType maskVal, psMaskType markVal)
 {
     PS_ASSERT_PTR_NON_NULL(readout, false);
@@ -416,4 +416,7 @@
     // create template model
     pmModel *modelRef = pmModelAlloc(psf->type);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // use the center of the center pixel of the image
@@ -465,5 +468,5 @@
 
         // mask the given aperture and measure the apMag
-        psImageKeepCircle (mask, xc, yc, radius, "OR", mark);
+        psImageKeepCircle (mask, xc, yc, radius, "OR", markVal);
         if (!pmSourcePhotometryAper (&apMag, model, image, mask, maskVal)) {
             psError(PM_ERR_PHOTOM, false, "Measuring apMag for radius == %g", radius);
@@ -473,7 +476,5 @@
             break;
         }
-
-        // XXX since we re-mask on each pass, this could be dropped.
-        psImageKeepCircle (mask, xc, yc, radius, "AND", PS_NOT_U8(mark));
+        psImageKeepCircle (mask, xc, yc, radius, "AND", PS_NOT_U8(markVal));
 
         // the 'ignore' mode is for testing
Index: /branches/eam_branch_20080706/psModules/src/objects/pmPSFtry.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/objects/pmPSFtry.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/objects/pmPSFtry.c	(revision 18472)
@@ -5,6 +5,6 @@
  *  @author EAM, IfA
  *
- *  @version $Revision: 1.56 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-06-10 01:32:15 $
+ *  @version $Revision: 1.56.8.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-07-11 18:35:04 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -98,5 +98,5 @@
 
 // generate a pmPSFtry with a copy of the test PSF sources
-pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psMaskType maskVal, psMaskType mark)
+pmPSFtry *pmPSFtryModel (const psArray *sources, const char *modelName, pmPSFOptions *options, psMaskType maskVal, psMaskType markVal)
 {
     bool status;
@@ -116,4 +116,7 @@
         return NULL;
     }
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // stage 1:  fit an EXT model to all candidates PSF sources
@@ -129,9 +132,12 @@
         }
 
-        // set object mask to define valid pixels -- XXX not unset?
-        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "OR", mark);
+        // set object mask to define valid pixels
+        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "OR", markVal);
 
         // fit model as EXT, not PSF
         status = pmSourceFitModel (source, source->modelEXT, PM_SOURCE_FIT_EXT, maskVal);
+
+	// clear object mask to define valid pixels
+        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_U8(markVal));
 
         // exclude the poor fits
@@ -170,6 +176,6 @@
         source->modelPSF->radiusFit = options->radius;
 
-        // set object mask to define valid pixels -- XXX not unset?
-        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "OR", mark);
+        // set object mask to define valid pixels
+        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "OR", markVal);
 
         // fit the PSF model to the source
@@ -178,4 +184,5 @@
         // skip poor fits
         if (!status) {
+	    psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_U8(markVal));
             psfTry->mask->data.U8[i] = PSFTRY_MASK_PSF_FAIL;
             psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : failed PSF fit\n", i, source->peak->x, source->peak->y);
@@ -183,11 +190,14 @@
         }
 
-        // XXX : use a different aperture radius from the fit radius?
-        status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal, mark);
+        status = pmSourceMagnitudes (source, psfTry->psf, PM_SOURCE_PHOT_INTERP, maskVal);
 	if (!status || isnan(source->apMag)) {
+	    psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_U8(markVal));
             psfTry->mask->data.U8[i] = PSFTRY_MASK_BAD_PHOT;
             psTrace ("psModules.objects", 4, "dropping %d (%d,%d) : poor photometry\n", i, source->peak->x, source->peak->y);
             continue;
         }
+
+	// clear object mask to define valid pixels
+        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->radius, "AND", PS_NOT_U8(markVal));
 
         psfTry->fitMag->data.F32[i] = source->psfMag;
Index: /branches/eam_branch_20080706/psModules/src/objects/pmSource.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/objects/pmSource.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/objects/pmSource.c	(revision 18472)
@@ -6,6 +6,6 @@
  *  @author EAM, IfA: significant modifications.
  *
- *  @version $Revision: 1.54 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-06-10 02:26:17 $
+ *  @version $Revision: 1.54.8.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-07-11 18:35:04 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -838,6 +838,5 @@
 
 // should we call pmSourceCacheModel if it does not exist?
-bool pmSourceOp (pmSource *source, pmModelOpMode mode, bool add,
-                 psMaskType maskVal, int dx, int dy)
+bool pmSourceOp (pmSource *source, pmModelOpMode mode, bool add, psMaskType maskVal, int dx, int dy)
 {
     PS_ASSERT_PTR_NON_NULL(source, false);
Index: /branches/eam_branch_20080706/psModules/src/objects/pmSourcePhotometry.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/objects/pmSourcePhotometry.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/objects/pmSourcePhotometry.c	(revision 18472)
@@ -3,6 +3,6 @@
  *  @author EAM, IfA; GLG, MHPCC
  *
- *  @version $Revision: 1.42 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-06-09 00:43:46 $
+ *  @version $Revision: 1.42.8.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-07-11 18:35:04 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -64,6 +64,5 @@
 
 // XXX masked region should be (optionally) elliptical
-bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode,
-                         psMaskType maskVal, psMaskType mark)
+bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psMaskType maskVal)
 {
     PS_ASSERT_PTR_NON_NULL(source, false);
@@ -230,18 +229,13 @@
         mask = source->maskObj;
     }
-    // set aperture mask circle to model radius
-    // XXX use a different radius for apertures and fits...
-    // XXX can I remove this?  the source should have the mask defined when it is constructed or
-    // when the fit / aperture radius is changed...
-    psImageKeepCircle (source->maskObj, x, y, model->radiusFit, "OR", mark);
 
     // measure the weight of included pixels
     // XXX is this supposed to use the weight or the flux?
     if (mode & PM_SOURCE_PHOT_WEIGHT) {
-        pmSourcePixelWeight (&source->pixWeight, model, source->pixels, source->maskObj, maskVal | mark);
+        pmSourcePixelWeight (&source->pixWeight, model, source->pixels, source->maskObj, maskVal);
     }
 
     // measure object aperture photometry
-    status = pmSourcePhotometryAper  (&source->apMag, model, flux, mask, maskVal | mark);
+    status = pmSourcePhotometryAper  (&source->apMag, model, flux, mask, maskVal);
     if (!status) {
         psTrace ("psModules.objects", 3, "fail mag : bad Ap Mag");
@@ -264,8 +258,4 @@
         psFree(mask);
     }
-
-    // unmask aperture
-    // XXX can I remove this?  this will probably break things downstream...
-    psImageKeepCircle (source->maskObj, x, y, model->radiusFit, "AND", PS_NOT_U8(mark));
 
     // if source was originally subtracted, re-subtract object, leave local sky
@@ -308,6 +298,5 @@
 
 // return source aperture magnitude
-bool pmSourcePhotometryAper (float *apMag, pmModel *model, psImage *image, psImage *mask,
-                             psMaskType maskVal)
+bool pmSourcePhotometryAper (float *apMag, pmModel *model, psImage *image, psImage *mask, psMaskType maskVal)
 {
     PS_ASSERT_PTR_NON_NULL(apMag, false);
@@ -347,6 +336,5 @@
 
 // return source aperture magnitude
-bool pmSourcePixelWeight (float *pixWeight, pmModel *model, psImage *image, psImage *mask,
-                          psMaskType maskVal)
+bool pmSourcePixelWeight (float *pixWeight, pmModel *model, psImage *image, psImage *mask, psMaskType maskVal)
 {
     PS_ASSERT_PTR_NON_NULL(pixWeight, false);
Index: /branches/eam_branch_20080706/psModules/src/objects/pmSourcePhotometry.h
===================================================================
--- /branches/eam_branch_20080706/psModules/src/objects/pmSourcePhotometry.h	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/objects/pmSourcePhotometry.h	(revision 18472)
@@ -4,6 +4,6 @@
  * @author EAM, IfA; GLG, MHPCC
  *
- * @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-06-20 02:22:26 $
+ * @version $Revision: 1.10.34.1 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2008-07-11 18:35:04 $
  * Copyright 2004 Maui High Performance Computing Center, University of Hawaii
  */
@@ -50,5 +50,5 @@
 
 bool pmSourceMagnitudesInit (psMetadata *config);
-bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psMaskType maskVal, psMaskType mark);
+bool pmSourceMagnitudes (pmSource *source, pmPSF *psf, pmSourcePhotometryMode mode, psMaskType maskVal);
 bool pmSourcePixelWeight (float *pixWeight, pmModel *model, psImage *image, psImage *mask, psMaskType maskVal);
 bool pmSourceChisq (pmModel *model, psImage *image, psImage *mask, psImage *weight, psMaskType maskVal);
Index: /branches/eam_branch_20080706/psModules/src/objects/pmSourcePlotMoments.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/objects/pmSourcePlotMoments.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/objects/pmSourcePlotMoments.c	(revision 18472)
@@ -5,6 +5,6 @@
  *  @author EAM, IfA
  *
- *  @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2007-11-10 01:09:20 $
+ *  @version $Revision: 1.10.20.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-07-11 18:35:04 $
  *
  *  Copyright 2006 IfA, University of Hawaii
@@ -95,6 +95,6 @@
     graphdata.xmin = -0.05;
     graphdata.ymin = -0.05;
-    graphdata.xmax = +2.05;
-    graphdata.ymax = +2.05;
+    graphdata.xmax = +4.05;
+    graphdata.ymax = +4.05;
     KapaSetLimits (kapa, &graphdata);
 
Index: /branches/eam_branch_20080706/psModules/src/objects/pmSourceSky.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/objects/pmSourceSky.c	(revision 18471)
+++ /branches/eam_branch_20080706/psModules/src/objects/pmSourceSky.c	(revision 18472)
@@ -6,6 +6,6 @@
  *  @author EAM, IfA: significant modifications.
  *
- *  @version $Revision: 1.16 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2008-01-02 20:39:04 $
+ *  @version $Revision: 1.16.18.1 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2008-07-11 18:35:04 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -42,4 +42,6 @@
 
 The source.pixels and source.mask must already exist
+
+This function modifies the source mask; it should only be called before the object aperture is defined
 *****************************************************************************/
 
@@ -49,5 +51,5 @@
     psF32 Radius,
     psMaskType maskVal,
-    psMaskType mark)
+    psMaskType markVal)
 {
     psTrace("psModules.objects", 3, "---- %s() begin ----\n", __func__);
@@ -69,15 +71,18 @@
     psRegion srcRegion;
 
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
     srcRegion = psRegionForSquare(peak->x, peak->y, Radius);
     srcRegion = psRegionForImage(mask, srcRegion);
 
-    psImageMaskRegion(mask, srcRegion, "OR", mark);
+    psImageMaskRegion(mask, srcRegion, "OR", markVal);
     psStats *myStats = psStatsAlloc(statsOptions);
-    if (!psImageStats(myStats, image, mask, maskVal | mark)) {
+    if (!psImageStats(myStats, image, mask, maskVal)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n");
         psFree(myStats);
         return false;
     }
-    psImageMaskRegion(mask, srcRegion, "AND", PS_NOT_U8(mark));
+    psImageMaskRegion(mask, srcRegion, "AND", PS_NOT_U8(markVal));
     double value = psStatsGetValue(myStats, statistic);
     psFree(myStats);
@@ -101,5 +106,5 @@
     psF32 Radius,
     psMaskType maskVal,
-    psMaskType mark
+    psMaskType markVal
 )
 {
@@ -110,4 +115,7 @@
     PS_ASSERT_PTR_NON_NULL(source->peak, false);
     PS_ASSERT_INT_POSITIVE(Radius, false);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     psStatsOptions statistic = psStatsSingleOption(statsOptions);
@@ -125,12 +133,12 @@
     srcRegion = psRegionForImage(mask, srcRegion);
 
-    psImageMaskRegion(mask, srcRegion, "OR", mark);
+    psImageMaskRegion(mask, srcRegion, "OR", markVal);
     psStats *myStats = psStatsAlloc(statsOptions);
-    if (!psImageStats(myStats, image, mask, maskVal | mark)) {
+    if (!psImageStats(myStats, image, mask, maskVal)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n");
         psFree(myStats);
         return false;
     }
-    psImageMaskRegion(mask, srcRegion, "AND", PS_NOT_U8(mark));
+    psImageMaskRegion(mask, srcRegion, "AND", PS_NOT_U8(markVal));
     double value = psStatsGetValue(myStats, statistic);
     psFree(myStats);
Index: /branches/eam_branch_20080706/psphot/doc/notes.txt
===================================================================
--- /branches/eam_branch_20080706/psphot/doc/notes.txt	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/doc/notes.txt	(revision 18472)
@@ -1,2 +1,10 @@
+
+2008.06.25
+
+ timing : footprints
+
+ on GPC1, with FFT: 
+    pass 1 :     convolved with grow disc: 17.558344 sec
+    pass 2 :     convolved with grow disc: 8.915036 sec
 
 2008.01.31
Index: /branches/eam_branch_20080706/psphot/src/Makefile.am
===================================================================
--- /branches/eam_branch_20080706/psphot/src/Makefile.am	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/Makefile.am	(revision 18472)
@@ -15,4 +15,5 @@
 	psphotImageLoop.c	\
 	psphotMosaicChip.c	\
+	psphotSetMaskBits.c	\
 	psphotParseCamera.c
 
@@ -85,4 +86,6 @@
 	psphotAddNoise.c
 
+# dropped? psphotGrowthCurve.c
+
 include_HEADERS = \
 	psphot.h \
Index: /branches/eam_branch_20080706/psphot/src/psphot.h
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphot.h	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphot.h	(revision 18472)
@@ -25,4 +25,5 @@
 bool            psphotReadoutCleanup (pmConfig *config, pmReadout *readout, psMetadata *recipe, pmDetections *detections, pmPSF *psf, psArray *sources);
 bool            psphotDefineFiles (pmConfig *config, pmFPAfile *input);
+bool            psphotSetMaskBits (pmConfig *config);
 
 // XXX test functions
@@ -70,8 +71,8 @@
 // functions to set the correct source pixels
 bool            psphotInitRadiusPSF (const psMetadata *recipe, const pmModelType type);
-bool            psphotCheckRadiusPSF (pmReadout *readout, pmSource *source, pmModel *model);
-bool            psphotCheckRadiusPSFBlend (pmReadout *readout, pmSource *source, pmModel *model, float dR);
+bool            psphotCheckRadiusPSF (pmReadout *readout, pmSource *source, pmModel *model, psMaskType markVal);
+bool            psphotCheckRadiusPSFBlend (pmReadout *readout, pmSource *source, pmModel *model, psMaskType markVal, float dR);
 bool            psphotInitRadiusEXT (psMetadata *recipe, pmModelType type);
-bool            psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model);
+bool            psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psMaskType markVal);
 
 // output functions
@@ -91,9 +92,9 @@
 bool            psphotInitLimitsPSF (psMetadata *recipe, pmReadout *readout);
 bool            psphotInitLimitsEXT (psMetadata *recipe);
-bool            psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, psMaskType maskVal);
-bool            psphotFitBlob (pmReadout *readout, pmSource *source, psArray *sources, pmPSF *psf, psMaskType maskVal);
-bool            psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, psMaskType maskVal);
-pmModel        *psphotFitEXT (pmReadout *readout, pmSource *source, pmModelType modelType, psMaskType maskVal);
-psArray        *psphotFitDBL (pmReadout *readout, pmSource *source, psMaskType maskVal);
+bool            psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, psMaskType maskVal, psMaskType markVal);
+bool            psphotFitBlob (pmReadout *readout, pmSource *source, psArray *sources, pmPSF *psf, psMaskType maskVal, psMaskType markVal);
+bool            psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, psMaskType maskVal, psMaskType markVal);
+pmModel        *psphotFitEXT (pmReadout *readout, pmSource *source, pmModelType modelType, psMaskType maskVal, psMaskType markVal);
+psArray        *psphotFitDBL (pmReadout *readout, pmSource *source, psMaskType maskVal, psMaskType markVal);
 
 // functions to support simultaneous multi-source fitting
@@ -124,5 +125,5 @@
 bool            psphotMakeResiduals (psArray *sources, psMetadata *recipe, pmPSF *psf, psMaskType maskVal);
 
-pmModel        *psphotPSFConvModel (pmReadout *readout, pmSource *source, pmModelType modelType, psMaskType maskVal, int psfSize);
+pmModel        *psphotPSFConvModel (pmReadout *readout, pmSource *source, pmModelType modelType, psMaskType maskVal, psMaskType markVal, int psfSize);
 
 psKernel       *psphotKernelFromPSF (pmSource *source, int nPix);
Index: /branches/eam_branch_20080706/psphot/src/psphotApResid.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotApResid.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotApResid.c	(revision 18472)
@@ -25,11 +25,14 @@
     }
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    // bit-masks to test for good/bad pixels
+    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT");
     assert (maskVal);
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType mark = psMetadataLookupU8(&status, recipe, "MASK.MARK"); // Mask value for bad pixels
-    assert (mark);
+    // bit-mask to mark pixels not used in analysis
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // S/N limit to perform full non-linear fits
@@ -65,5 +68,5 @@
     psf->growth = pmGrowthCurveAlloc (PSF_FIT_PAD, 100.0, REF_RADIUS);
 
-    if (!pmGrowthCurveGenerate (readout, psf, IGNORE_GROWTH, maskVal, mark)) {
+    if (!pmGrowthCurveGenerate (readout, psf, IGNORE_GROWTH, maskVal, markVal)) {
         psError(PSPHOT_ERR_APERTURE, false, "Fitting aperture corrections");
         psFree(psf->growth); psf->growth = NULL;
@@ -92,5 +95,5 @@
         // get growth-corrected, apTrend-uncorrected magnitudes in scaled apertures
         // will fail if below S/N threshold or model is missing
-        if (!pmSourceMagnitudes (source, psf, photMode, maskVal, mark)) {
+        if (!pmSourceMagnitudes (source, psf, photMode, maskVal)) {
             Nskip ++;
 	    psTrace ("psphot", 3, "skip : bad source mag");
Index: /branches/eam_branch_20080706/psphot/src/psphotBlendFit.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotBlendFit.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotBlendFit.c	(revision 18472)
@@ -12,7 +12,14 @@
     psTimerStart ("psphot");
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    // bit-masks to test for good/bad pixels
+    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT");
     assert (maskVal);
+
+    // bit-mask to mark pixels not used in analysis
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // source analysis is done in S/N order (brightest first)
@@ -81,5 +88,5 @@
 	// I should try EXT if the source size measurement says it is large
 	if (source->mode & PM_SOURCE_MODE_EXT_LIMIT) {
-	    if (psphotFitBlob (readout, source, sources, psf, maskVal)) {
+	    if (psphotFitBlob (readout, source, sources, psf, maskVal, markVal)) {
 		source->type = PM_SOURCE_TYPE_EXTENDED;
 		psTrace ("psphot", 5, "source at %7.1f, %7.1f is ext", source->moments->x, source->moments->y);
@@ -88,5 +95,5 @@
 	    }
 	} else {
-	    if (psphotFitBlend (readout, source, psf, maskVal)) {
+	    if (psphotFitBlend (readout, source, psf, maskVal, markVal)) {
 		source->type = PM_SOURCE_TYPE_STAR;
 		psTrace ("psphot", 5, "source at %7.1f, %7.1f is psf", source->moments->x, source->moments->y);
Index: /branches/eam_branch_20080706/psphot/src/psphotChoosePSF.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotChoosePSF.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotChoosePSF.c	(revision 18472)
@@ -8,11 +8,14 @@
     psTimerStart ("psphot");
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    // bit-masks to test for good/bad pixels
+    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT");
     assert (maskVal);
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType mark = psMetadataLookupU8(&status, recipe, "MASK.MARK"); // Mask value for bad pixels
-    assert (mark);
+    // bit-mask to mark pixels not used in analysis
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // examine PSF sources in S/N order (brightest first)
@@ -147,5 +150,5 @@
     for (int i = 0; i < modelNames->n; i++) {
         char *modelName = modelNames->data[i];
-        pmPSFtry *try = pmPSFtryModel (stars, modelName, options, maskVal, mark); // Attempt at fit
+        pmPSFtry *try = pmPSFtryModel (stars, modelName, options, maskVal, markVal); // Attempt at fit
         if (!try) {
             // No big deal --- we'll try another model
@@ -321,7 +324,7 @@
             // use pmModelSub because modelFlux has not been generated
             assert (source->maskObj);
-            psImageKeepCircle (source->maskObj, x, y, options->radius, "OR", PM_MASK_MARK);
+            psImageKeepCircle (source->maskObj, x, y, options->radius, "OR", markVal);
             pmModelSub (source->pixels, source->maskObj, source->modelPSF, PM_MODEL_OP_FULL, maskVal);
-            psImageKeepCircle (source->maskObj, x, y, options->radius, "AND", PS_NOT_U8(PM_MASK_MARK));
+            psImageKeepCircle (source->maskObj, x, y, options->radius, "AND", PS_NOT_U8(markVal));
         }
 
Index: /branches/eam_branch_20080706/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotExtendedSourceFits.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotExtendedSourceFits.c	(revision 18472)
@@ -15,4 +15,10 @@
     psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
     assert (maskVal);
+
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT"); // Mask value for bad pixels
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // perform full extended source non-linear fits?
@@ -155,5 +161,5 @@
 	  pmModel *modelFit = NULL;
 	  if (convolved) {
-	      modelFit = psphotPSFConvModel (readout, source, modelType, maskVal, psfSize);
+	      modelFit = psphotPSFConvModel (readout, source, modelType, maskVal, markVal, psfSize);
 	      if (!modelFit) {
 		  psTrace ("psphot", 5, "failed to fit psf-conv model for object at %f, %f", source->moments->x, source->moments->y);
@@ -168,5 +174,5 @@
 	      psFree (source->modelFlux);
 	      source->modelFlux = NULL;
-	      modelFit = psphotFitEXT (readout, source, modelType, maskVal);
+	      modelFit = psphotFitEXT (readout, source, modelType, maskVal, markVal);
 	      if (!modelFit) {
 		  psTrace ("psphot", 5, "failed to fit plain model for object at %f, %f", source->moments->x, source->moments->y);
Index: /branches/eam_branch_20080706/psphot/src/psphotFitSourcesLinear.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotFitSourcesLinear.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotFitSourcesLinear.c	(revision 18472)
@@ -10,5 +10,5 @@
 // the analysis is performed wrt the simulated pixel values
 
-static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, int SKY_FIT_ORDER);
+static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, int SKY_FIT_ORDER, psMaskType markVal);
 
 bool psphotFitSourcesLinear (pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, bool final) {
@@ -22,7 +22,14 @@
     psTimerStart ("psphot");
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    // bit-masks to test for good/bad pixels
+    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT");
     assert (maskVal);
+
+    // bit-mask to mark pixels not used in analysis
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // source analysis is done in spatial order
@@ -157,5 +164,5 @@
 
     // set the sky, sky_x, sky_y components of border matrix
-    SetBorderMatrixElements (border, readout, fitSources, CONSTANT_PHOTOMETRIC_WEIGHTS, SKY_FIT_ORDER);
+    SetBorderMatrixElements (border, readout, fitSources, CONSTANT_PHOTOMETRIC_WEIGHTS, SKY_FIT_ORDER, markVal);
     psLogMsg ("psphot.ensemble", PS_LOG_MINUTIA, "set border: %f (%d elements)\n", psTimerMark ("psphot"), sparse->Nelem);
 
@@ -221,5 +228,5 @@
 // on the pixels which correspond to all of the sources of interest.  These elements fill in
 // the border matrix components in the sparse matrix equation.
-static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, int SKY_FIT_ORDER) {
+static bool SetBorderMatrixElements (psSparseBorder *border, pmReadout *readout, psArray *sources, bool constant_weights, int SKY_FIT_ORDER, psMaskType markVal) {
 
     // generate the image-wide weight terms
@@ -227,5 +234,5 @@
     psRegion fullArray = psRegionSet (0, 0, 0, 0);
     fullArray = psRegionForImage (readout->mask, fullArray);
-    psImageMaskRegion (readout->mask, fullArray, "OR", PM_MASK_MARK);
+    psImageMaskRegion (readout->mask, fullArray, "OR", markVal);
     psLogMsg ("psphot.ensemble", PS_LOG_INFO, "step 1: %f sec\n", psTimerMark ("psphot"));
 
@@ -237,5 +244,5 @@
         float x = model->params->data.F32[PM_PAR_XPOS];
         float y = model->params->data.F32[PM_PAR_YPOS];
-        psImageMaskCircle (source->maskView, x, y, model->radiusFit, "AND", PS_NOT_U8(PM_MASK_MARK));
+        psImageMaskCircle (source->maskView, x, y, model->radiusFit, "AND", PS_NOT_U8(markVal));
     }
     psLogMsg ("psphot.ensemble", PS_LOG_INFO, "step 2: %f sec\n", psTimerMark ("psphot"));
@@ -279,5 +286,5 @@
 
     // turn off MARK for all image pixels
-    psImageMaskRegion (readout->mask, fullArray, "AND", PS_NOT_U8(PM_MASK_MARK));
+    psImageMaskRegion (readout->mask, fullArray, "AND", PS_NOT_U8(markVal));
     psLogMsg ("psphot.ensemble", PS_LOG_INFO, "step 4: %f sec\n", psTimerMark ("psphot"));
 
Index: /branches/eam_branch_20080706/psphot/src/psphotGuessModels.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotGuessModels.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotGuessModels.c	(revision 18472)
@@ -23,7 +23,14 @@
     psTimerStart ("psphot");
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    // bit-masks to test for good/bad pixels
+    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT");
     assert (maskVal);
+
+    // bit-mask to mark pixels not used in analysis
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // setup the PSF fit radius details
@@ -85,5 +92,5 @@
 	// XXX need to define the guess flux?
 	// set the fit radius based on the object flux limit and the model
-	psphotCheckRadiusPSF (readout, source, modelPSF);
+	psphotCheckRadiusPSF (readout, source, modelPSF, markVal);
 
 	// set the source PSF model
Index: /branches/eam_branch_20080706/psphot/src/psphotMagnitudes.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotMagnitudes.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotMagnitudes.c	(revision 18472)
@@ -8,11 +8,14 @@
     psTimerStart ("psphot");
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    // bit-masks to test for good/bad pixels
+    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT");
     assert (maskVal);
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType mark = psMetadataLookupU8(&status, recipe, "MASK.MARK"); // Mask value for bad pixels
-    assert (mark);
+    // bit-mask to mark pixels not used in analysis
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     pmSourceMagnitudesInit (recipe);
@@ -35,5 +38,5 @@
     for (int i = 0; i < sources->n; i++) {
         pmSource *source = (pmSource *) sources->data[i];
-        status = pmSourceMagnitudes (source, psf, photMode, maskVal, mark);
+        status = pmSourceMagnitudes (source, psf, photMode, maskVal);
         if (status) Nap ++;
 
Index: /branches/eam_branch_20080706/psphot/src/psphotMaskReadout.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotMaskReadout.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotMaskReadout.c	(revision 18472)
@@ -7,27 +7,10 @@
 
     // ** Interpret the mask values:
-
-    // single-bit named masks
-    psMaskType maskMark = pmConfigMask("MARK",     config); // Mask value for marking
-    psMetadataAddU8 (recipe, PS_LIST_TAIL, "MASK.MARK", PS_META_REPLACE, "user-defined mask", maskMark);
-
-    psMaskType maskSat  = pmConfigMask("SAT", 	   config); // Mask value for saturated pixels
+    // XXX drop the write to recipe and move config into psphotRoughClass?
+    psMaskType maskSat  = pmConfigMaskGet("SAT", config); // Mask value for saturated pixels
     psMetadataAddU8 (recipe, PS_LIST_TAIL, "MASK.SAT", PS_META_REPLACE, "user-defined mask", maskSat);
 
-    psMaskType maskBad  = pmConfigMask("BAD", 	   config); // Mask value for bad pixels
+    psMaskType maskBad  = pmConfigMaskGet("BAD", config); // Mask value for bad pixels
     psMetadataAddU8 (recipe, PS_LIST_TAIL, "MASK.BAD", PS_META_REPLACE, "user-defined mask", maskBad);
-
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "PSPHOT"); // Mask value for bad pixels
-    if (!maskVal) {
-      const char *maskValStr = psMetadataLookupStr(NULL, recipe, "MASKVAL"); // String with mask names
-      if (!maskValStr) {
-        psError(PSPHOT_ERR_CONFIG, false, "Missing recipe item: MASKVAL(STR)");
-        return false;
-      }
-      maskVal = pmConfigMask(maskValStr, config); // Mask values to mask against
-      psMetadataAddU8 (recipe, PS_LIST_TAIL, "MASK.PSPHOT", PS_META_REPLACE, "user-defined mask", maskVal);
-      assert (maskVal);
-    }
 
     // generate mask & weight images if they don't already exit
Index: /branches/eam_branch_20080706/psphot/src/psphotModelTest.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotModelTest.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotModelTest.c	(revision 18472)
@@ -12,9 +12,14 @@
     pmSourceFitMode fitMode;
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
-    psMaskType mark    = psMetadataLookupU8(&status, recipe, "MASK.MARK"); // Mask value for bad pixels
+    // bit-masks to test for good/bad pixels
+    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT");
     assert (maskVal);
-    assert (mark);
+
+    // bit-mask to mark pixels not used in analysis
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // run model fitting tests on a single source?
@@ -130,5 +135,5 @@
 
     // find the local sky
-    status = pmSourceLocalSky (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, mark);
+    status = pmSourceLocalSky (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
     if (!status) psAbort("pmSourceLocalSky error");
 
@@ -195,5 +200,5 @@
 
     // define the pixels used for the fit
-    psImageKeepCircle (source->maskObj, xObj, yObj, RADIUS, "OR", mark);
+    psImageKeepCircle (source->maskObj, xObj, yObj, RADIUS, "OR", markVal);
     psphotSaveImage (NULL, source->maskObj, "mask1.fits");
 
@@ -213,5 +218,5 @@
 	assert (status);
 
-        model = psphotPSFConvModel (readout, source, modelType, maskVal, psfSize);
+        model = psphotPSFConvModel (readout, source, modelType, maskVal, markVal, psfSize);
         params = model->params->data.F32;
     } else {
Index: /branches/eam_branch_20080706/psphot/src/psphotMosaicChip.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotMosaicChip.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotMosaicChip.c	(revision 18472)
@@ -25,8 +25,10 @@
     }
 
+    psMaskType blankMask = pmConfigMaskGet("BLANK", config);
+
     // mosaic the chip, forcing a deep copy (resulting images are not subimages)
     psTrace("pmChipMosaic", 5, "mosaic chip %s to %s (xbin,ybin: %d,%d to %d,%d)\n",
             in->name, out->name, in->xBin, in->yBin, out->xBin, out->yBin);
-    status = pmChipMosaic(outChip, inChip, true, pmConfigMask("BLANK", config));
+    status = pmChipMosaic(outChip, inChip, true, blankMask);
     return status;
 }
Index: /branches/eam_branch_20080706/psphot/src/psphotPSFConvModel.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotPSFConvModel.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotPSFConvModel.c	(revision 18472)
@@ -9,6 +9,9 @@
 // modelConv to contain the fitted parameters, and the modelFlux to contain the 
 // convolved model image.
-pmModel *psphotPSFConvModel (pmReadout *readout, pmSource *source, pmModelType modelType, psMaskType maskVal, int psfSize) {
+pmModel *psphotPSFConvModel (pmReadout *readout, pmSource *source, pmModelType modelType, psMaskType maskVal, psMaskType markVal, int psfSize) {
     
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
     // make sure we save a cached copy of the psf flux
     pmSourceCachePSF (source, maskVal);
@@ -65,5 +68,5 @@
     psVector *dparams = modelConv->dparams;
 
-    psphotCheckRadiusEXT (readout, source, modelConv);
+    psphotCheckRadiusEXT (readout, source, modelConv, markVal);
 
     // create the minimization constraints
Index: /branches/eam_branch_20080706/psphot/src/psphotParseCamera.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotParseCamera.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotParseCamera.c	(revision 18472)
@@ -17,10 +17,28 @@
     // if MASK or WEIGHT was supplied on command line, bind files to 'load'
     // the mask and weight will be mosaicked with the image
-    pmFPAfileBindFromArgs (&status, load, config, "PSPHOT.MASK",   "MASK");
+    pmFPAfile *mask = pmFPAfileBindFromArgs (&status, load, config, "PSPHOT.MASK", "MASK");
     if (!status) {
 	psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
 	return NULL;
     }
-
+    if (mask) {
+	// XXX need to load the mask bit names from one of the headers
+	// this grabs the first available hdu : no guarantee that it will be valid, though
+	pmHDU *hdu = pmHDUGetFirst (mask->fpa);
+	if (!hdu) {
+	    psError(PS_ERR_IO, true, "no valid HDU for PSPHOT.MASK");
+	    return NULL;
+	}
+	// XXX should this be done in pmFPAfileIO.c read functions?
+	if (!pmConfigMaskReadHeader (config, hdu->header)) {
+	    psError(PS_ERR_IO, false, "error in mask bits");
+	    return NULL;
+	}
+    }
+    if (!psphotSetMaskBits (config)) {
+	psError (PS_ERR_UNKNOWN, false, "failed to set mask bit values");
+	return NULL;
+    }
+    
     pmFPAfileBindFromArgs (&status, load, config, "PSPHOT.WEIGHT", "WEIGHT");
     if (!status) {
Index: /branches/eam_branch_20080706/psphot/src/psphotRadiusChecks.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotRadiusChecks.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotRadiusChecks.c	(revision 18472)
@@ -7,7 +7,6 @@
 					// and a per-object radius is calculated)
 
-bool psphotInitRadiusPSF(const psMetadata *recipe,
-			 const pmModelType type)
-{
+bool psphotInitRadiusPSF(const psMetadata *recipe, const pmModelType type) {
+
     bool status = true;
 
@@ -20,5 +19,5 @@
 
 // call this function whenever you (re)-define the PSF model
-bool psphotCheckRadiusPSF (pmReadout *readout, pmSource *source, pmModel *model)
+bool psphotCheckRadiusPSF (pmReadout *readout, pmSource *source, pmModel *model, psMaskType markVal)
 {
     psF32 *PAR = model->params->data.F32;
@@ -47,9 +46,9 @@
 
     // set the mask to flag the excluded pixels
-    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", PM_MASK_MARK);
+    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     return status;
 }
 
-bool psphotCheckRadiusPSFBlend (pmReadout *readout, pmSource *source, pmModel *model, float dR) {
+bool psphotCheckRadiusPSFBlend (pmReadout *readout, pmSource *source, pmModel *model, psMaskType markVal, float dR) {
 
     psF32 *PAR = model->params->data.F32;
@@ -69,5 +68,5 @@
 
     // set the mask to flag the excluded pixels
-    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", PM_MASK_MARK);
+    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     return status;
 }
@@ -87,5 +86,5 @@
 
 // call this function whenever you (re)-define the EXT model
-bool psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model) {
+bool psphotCheckRadiusEXT (pmReadout *readout, pmSource *source, pmModel *model, psMaskType markVal) {
 
     psF32 *PAR = model->params->data.F32;
@@ -102,5 +101,5 @@
 
     // set the mask to flag the excluded pixels
-    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", PM_MASK_MARK);
+    psImageKeepCircle (source->maskObj, PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], model->radiusFit, "OR", markVal);
     return status;
 }
Index: /branches/eam_branch_20080706/psphot/src/psphotSourceFits.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotSourceFits.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotSourceFits.c	(revision 18472)
@@ -21,11 +21,14 @@
 }
 
-bool psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, psMaskType maskVal) {
+bool psphotFitBlend (pmReadout *readout, pmSource *source, pmPSF *psf, psMaskType maskVal, psMaskType markVal) {
 
     float x, y, dR;
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // if this source is not a possible blend, just fit as PSF
     if ((source->blends == NULL) || (source->mode & PM_SOURCE_MODE_SATSTAR)) {
-        bool status = psphotFitPSF (readout, source, psf, maskVal);
+        bool status = psphotFitPSF (readout, source, psf, maskVal, markVal);
         return status;
     }
@@ -80,5 +83,5 @@
 
     // extend source radius as needed
-    psphotCheckRadiusPSFBlend (readout, source, PSF, dR);
+    psphotCheckRadiusPSFBlend (readout, source, PSF, markVal, dR);
 
     // fit PSF model (set/unset the pixel mask)
@@ -139,7 +142,10 @@
 }
 
-bool psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, psMaskType maskVal) {
+bool psphotFitPSF (pmReadout *readout, pmSource *source, pmPSF *psf, psMaskType maskVal, psMaskType markVal) {
 
     double chiTrend;
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     NfitPSF ++;
@@ -150,5 +156,5 @@
 
     // extend source radius as needed
-    psphotCheckRadiusPSF (readout, source, PSF);
+    psphotCheckRadiusPSF (readout, source, PSF, markVal);
 
     // fit PSF model (set/unset the pixel mask)
@@ -197,5 +203,5 @@
 }
 
-bool psphotFitBlob (pmReadout *readout, pmSource *source, psArray *sources, pmPSF *psf, psMaskType maskVal) {
+bool psphotFitBlob (pmReadout *readout, pmSource *source, psArray *sources, pmPSF *psf, psMaskType maskVal, psMaskType markVal) {
 
     bool okEXT, okDBL;
@@ -215,14 +221,15 @@
     psTrace ("psphot", 5, "trying blob...\n");
 
-    // psTraceSetLevel("psModules.objects.pmSourceFitSet", 5);
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // this temporary source is used as a place-holder by the psphotEval functions below
     pmSource *tmpSrc = pmSourceAlloc ();
 
-    pmModel *EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal);
+    pmModel *EXT = psphotFitEXT (readout, source, modelTypeEXT, maskVal, markVal);
     okEXT = psphotEvalEXT (tmpSrc, EXT);
     chiEXT = EXT->chisq / EXT->nDOF;
 
-    psArray *DBL = psphotFitDBL (readout, source, maskVal);
+    psArray *DBL = psphotFitDBL (readout, source, maskVal, markVal);
     okDBL  = psphotEvalDBL (tmpSrc, DBL->data[0]);
     okDBL &= psphotEvalDBL (tmpSrc, DBL->data[1]);
@@ -306,5 +313,5 @@
 
 // fit a double PSF source to an extended blob
-psArray *psphotFitDBL (pmReadout *readout, pmSource *source, psMaskType maskVal) {
+psArray *psphotFitDBL (pmReadout *readout, pmSource *source, psMaskType maskVal, psMaskType markVal) {
 
     float dx, dy;
@@ -317,4 +324,7 @@
     NfitDBL ++;
 
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
+
     // make a guess at the position of the two sources
     moments.x2 = source->moments->Sx;
@@ -329,5 +339,5 @@
     // save the PSF model from the Ensemble fit
     PSF = source->modelPSF;
-    psphotCheckRadiusPSFBlend (readout, source, PSF, 8.0);
+    psphotCheckRadiusPSFBlend (readout, source, PSF, markVal, 8.0);
     if (isnan(PSF->params->data.F32[1])) psAbort("nan in dbl fit");
 
@@ -351,7 +361,10 @@
 }
 
-pmModel *psphotFitEXT (pmReadout *readout, pmSource *source, pmModelType modelType, psMaskType maskVal) {
+pmModel *psphotFitEXT (pmReadout *readout, pmSource *source, pmModelType modelType, psMaskType maskVal, psMaskType markVal) {
 
     NfitEXT ++;
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // use the source moments, etc to guess basic model parameters
@@ -361,5 +374,5 @@
     // if (isnan(EXT->params->data.F32[1])) psAbort("nan in ext fit");
 
-    psphotCheckRadiusEXT (readout, source, EXT);
+    psphotCheckRadiusEXT (readout, source, EXT, markVal);
 
     if ((source->moments->Sx < 1e-3) || (source->moments->Sx < 1e-3)) {
Index: /branches/eam_branch_20080706/psphot/src/psphotSourceStats.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotSourceStats.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotSourceStats.c	(revision 18472)
@@ -9,11 +9,14 @@
     psTimerStart ("psphot");
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
+    // bit-masks to test for good/bad pixels
+    psMaskType maskVal = psMetadataLookupU8(&status, recipe, "MASK.PSPHOT");
     assert (maskVal);
 
-    // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
-    psMaskType mark = psMetadataLookupU8(&status, recipe, "MASK.MARK"); // Mask value for bad pixels
-    assert (mark);
+    // bit-mask to mark pixels not used in analysis
+    psMaskType markVal = psMetadataLookupU8(&status, recipe, "MARK.PSPHOT");
+    assert (markVal);
+
+    // maskVal is used to test for rejected pixels, and must include markVal
+    maskVal |= markVal;
 
     // determine properties (sky, moments) of initial sources
@@ -67,5 +70,5 @@
         // measure a local sky value
         // the local sky is now ignored; kept here for reference only
-        status = pmSourceLocalSky (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, mark);
+        status = pmSourceLocalSky (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
         if (!status) {
           psFree (source);
@@ -77,5 +80,5 @@
         // measure the local sky variance (needed if noise is not sqrt(signal))
         // XXX EAM : this should use ROBUST not SAMPLE median, but it is broken
-        status = pmSourceLocalSkyVariance (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, mark);
+        status = pmSourceLocalSkyVariance (source, PS_STAT_SAMPLE_MEDIAN, INNER, maskVal, markVal);
         if (!status) {
           psFree (source);
Index: /branches/eam_branch_20080706/psphot/src/psphotTestPSF.c
===================================================================
--- /branches/eam_branch_20080706/psphot/src/psphotTestPSF.c	(revision 18471)
+++ /branches/eam_branch_20080706/psphot/src/psphotTestPSF.c	(revision 18472)
@@ -109,7 +109,7 @@
         // set temporary object mask and fit object
         // fit model as EXT, not PSF
-        psImageKeepCircle (source->mask, x, y, RADIUS, "OR", PM_MASK_MARK);
+        psImageKeepCircle (source->mask, x, y, RADIUS, "OR", markVal);
         status = pmSourceFitModel (source, model, PM_SOURCE_FIT_EXT);
-        psImageKeepCircle (source->mask, x, y, RADIUS, "AND", PS_NOT_U8(PM_MASK_MARK));
+        psImageKeepCircle (source->mask, x, y, RADIUS, "AND", PS_NOT_U8(markVal));
 
 	// write fitted parameters to file
