Index: trunk/psphot/src/Makefile.am
===================================================================
--- trunk/psphot/src/Makefile.am	(revision 18471)
+++ trunk/psphot/src/Makefile.am	(revision 18555)
@@ -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: trunk/psphot/src/psphot.h
===================================================================
--- trunk/psphot/src/psphot.h	(revision 18471)
+++ trunk/psphot/src/psphot.h	(revision 18555)
@@ -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: trunk/psphot/src/psphotApResid.c
===================================================================
--- trunk/psphot/src/psphotApResid.c	(revision 18471)
+++ trunk/psphot/src/psphotApResid.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotBlendFit.c
===================================================================
--- trunk/psphot/src/psphotBlendFit.c	(revision 18471)
+++ trunk/psphot/src/psphotBlendFit.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotChoosePSF.c
===================================================================
--- trunk/psphot/src/psphotChoosePSF.c	(revision 18471)
+++ trunk/psphot/src/psphotChoosePSF.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotExtendedSourceFits.c
===================================================================
--- trunk/psphot/src/psphotExtendedSourceFits.c	(revision 18471)
+++ trunk/psphot/src/psphotExtendedSourceFits.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotFitSourcesLinear.c
===================================================================
--- trunk/psphot/src/psphotFitSourcesLinear.c	(revision 18471)
+++ trunk/psphot/src/psphotFitSourcesLinear.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotGuessModels.c
===================================================================
--- trunk/psphot/src/psphotGuessModels.c	(revision 18471)
+++ trunk/psphot/src/psphotGuessModels.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotMagnitudes.c
===================================================================
--- trunk/psphot/src/psphotMagnitudes.c	(revision 18471)
+++ trunk/psphot/src/psphotMagnitudes.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotMaskReadout.c
===================================================================
--- trunk/psphot/src/psphotMaskReadout.c	(revision 18471)
+++ trunk/psphot/src/psphotMaskReadout.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotModelTest.c
===================================================================
--- trunk/psphot/src/psphotModelTest.c	(revision 18471)
+++ trunk/psphot/src/psphotModelTest.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotMosaicChip.c
===================================================================
--- trunk/psphot/src/psphotMosaicChip.c	(revision 18471)
+++ trunk/psphot/src/psphotMosaicChip.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotPSFConvModel.c
===================================================================
--- trunk/psphot/src/psphotPSFConvModel.c	(revision 18471)
+++ trunk/psphot/src/psphotPSFConvModel.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotParseCamera.c
===================================================================
--- trunk/psphot/src/psphotParseCamera.c	(revision 18471)
+++ trunk/psphot/src/psphotParseCamera.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotRadiusChecks.c
===================================================================
--- trunk/psphot/src/psphotRadiusChecks.c	(revision 18471)
+++ trunk/psphot/src/psphotRadiusChecks.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotSourceFits.c
===================================================================
--- trunk/psphot/src/psphotSourceFits.c	(revision 18471)
+++ trunk/psphot/src/psphotSourceFits.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotSourceStats.c
===================================================================
--- trunk/psphot/src/psphotSourceStats.c	(revision 18471)
+++ trunk/psphot/src/psphotSourceStats.c	(revision 18555)
@@ -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: trunk/psphot/src/psphotTestPSF.c
===================================================================
--- trunk/psphot/src/psphotTestPSF.c	(revision 18471)
+++ trunk/psphot/src/psphotTestPSF.c	(revision 18555)
@@ -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
