Index: /branches/pap/ippconfig/recipes/ppStatsFromMetadata.config
===================================================================
--- /branches/pap/ippconfig/recipes/ppStatsFromMetadata.config	(revision 23579)
+++ /branches/pap/ippconfig/recipes/ppStatsFromMetadata.config	(revision 23580)
@@ -50,4 +50,5 @@
   ENTRY  VAL  ROBUST_MEDIAN    	  F32  ROBUST_STDEV      -bg_mean_stdev      
   ENTRY  VAL  ROBUST_STDEV     	  F32  RMS               -bg_stdev           
+  ENTRY  VAL  QUALITY             BOOL CONSTANT          -quality
 END
 
@@ -168,4 +169,5 @@
   ENTRY  VAL  IQ_M2S_L            F32  SAMPLE_MEAN      -iq_m2s_lq            
   ENTRY  VAL  IQ_M2S_U            F32  SAMPLE_MEAN      -iq_m2s_uq            
+  ENTRY  VAL  QUALITY             BOOL CONSTANT          -quality
 END
 
@@ -253,4 +255,5 @@
   ENTRY  VAL  RANGE.YMAX          S32  CONSTANT          -ymax          
   ENTRY  VAL  ACCEPT              BOOL CONSTANT          -accept
+  ENTRY  VAL  QUALITY             BOOL CONSTANT          -quality
 END
 
@@ -279,4 +282,5 @@
   ENTRY  VAL  NUM_SOURCES         S32  SUM               -sources                       
   ENTRY  VAL  GOOD_PIXEL_FRAC     F32  MEAN              -good_frac                     
+  ENTRY  VAL  QUALITY             BOOL CONSTANT          -quality
 END
 
@@ -301,4 +305,5 @@
   ENTRY  VAL  NUM_SOURCES           S32  SUM               -sources        
   ENTRY  VAL  GOOD_PIXEL_FRAC       F32  MEAN              -good_frac      
+  ENTRY  VAL  QUALITY               BOOL CONSTANT          -quality
 END
 
Index: /branches/pap/ppImage/src/ppImage.h
===================================================================
--- /branches/pap/ppImage/src/ppImage.h	(revision 23579)
+++ /branches/pap/ppImage/src/ppImage.h	(revision 23580)
@@ -40,5 +40,5 @@
     bool doAstromMosaic;                // full-mosaic Astrometry
     bool doStats;                       // call ppStats on the image
-    bool checkCTE;			// measure pixel-based variance
+    bool checkCTE;                      // measure pixel-based variance
 
     // output files requested
@@ -88,5 +88,5 @@
     float remnanceThresh;               // Threshold for remnance detection
 
-    char *normClass;			// class to use for per-class normalization 
+    char *normClass;                    // class to use for per-class normalization
 } ppImageOptions;
 
@@ -146,7 +146,7 @@
 bool ppImageRebinChip (pmConfig *config, pmFPAview *view, ppImageOptions *options, char *outName);
 
-bool ppImagePhotom (pmConfig *config, pmFPAview *view);
-bool ppImageAstrom (pmConfig *config);
-bool ppImageAddstar (pmConfig *config);
+bool ppImagePhotom(psMetadata *stats, pmConfig *config, pmFPAview *view);
+bool ppImageAstrom(pmConfig *config);
+bool ppImageAddstar(pmConfig *config);
 
 // Subtract background from the chip-mosaicked image
Index: /branches/pap/ppImage/src/ppImageLoop.c
===================================================================
--- /branches/pap/ppImage/src/ppImageLoop.c	(revision 23579)
+++ /branches/pap/ppImage/src/ppImageLoop.c	(revision 23580)
@@ -13,7 +13,12 @@
 bool ppImageLoop(pmConfig *config, ppImageOptions *options)
 {
-    psMetadata *stats = options->doStats ? psMetadataAlloc() : NULL; // Statistics to output
+    psMetadata *stats = NULL;           // Statistics to output
     float timeDetrend = 0;              // Amount of time spent in detrend
     float timePhot = 0;                 // Amount of time spent in photometry
+
+    if (options->doStats) {
+        stats = psMetadataAlloc();
+        psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", 0, "No problems", 0);
+    }
 
     bool status;                        // Status of MD lookup
@@ -139,5 +144,5 @@
         psTimerStart(TIMER_PHOT);
         if (options->doPhotom) {
-            if (!ppImagePhotom(config, view)) {
+            if (!ppImagePhotom(stats, config, view)) {
                 ESCAPE("error running photometry.");
             }
Index: /branches/pap/ppImage/src/ppImagePhotom.c
===================================================================
--- /branches/pap/ppImage/src/ppImagePhotom.c	(revision 23579)
+++ /branches/pap/ppImage/src/ppImagePhotom.c	(revision 23580)
@@ -6,5 +6,5 @@
 
 // In this function, we perform the psphot analysis routine for the chip-mosaicked images
-bool ppImagePhotom (pmConfig *config, pmFPAview *view) {
+bool ppImagePhotom(psMetadata *stats, pmConfig *config, pmFPAview *view) {
 
     bool status;
@@ -12,5 +12,5 @@
     pmReadout *readout;
 
-    psphotInit ();
+    psphotInit();
 
     // find or define a pmFPAfile PSPHOT.INPUT
@@ -37,14 +37,22 @@
             // run the actual photometry analysis
             if (!psphotReadout (config, view)) {
-                psError(psErrorCodeLast(), false, "failure in psphotReadout for chip %d, cell %d, readout %d\n", view->chip, view->cell, view->readout);
-                return false;
+                // This is likely a data quality issue
+                // XXX Split into multiple cases using error codes?
+                psErrorStackPrint("Unable to perform photometry on image");
+                psWarning("Unable to perform photometry on image --- suspect bad data quality.");
+                if (stats && psMetadataLookupS32(NULL, stats, "QUALITY") == 0) {
+                    psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE,
+                                     "Unable to perform photometry on image", psErrorCodeLast());
+                }
+                psErrorClear();
+                psphotFilesActivate(config, false);
             }
 
-	    // we want to save the MASK as modified by psphot, but not the data or weight
-	    // free the old mask and replace with a memory copy of the new mask
-	    pmReadout *oldReadout = pmFPAviewThisReadout (view, input->src);
-	    pmReadout *newReadout = pmFPAviewThisReadout (view, input->fpa);
-	    psFree (oldReadout->mask);
-	    oldReadout->mask = psMemIncrRefCounter (newReadout->mask);
+            // we want to save the MASK as modified by psphot, but not the data or weight
+            // free the old mask and replace with a memory copy of the new mask
+            pmReadout *oldReadout = pmFPAviewThisReadout(view, input->src);
+            pmReadout *newReadout = pmFPAviewThisReadout(view, input->fpa);
+            psFree (oldReadout->mask);
+            oldReadout->mask = psMemIncrRefCounter(newReadout->mask);
         }
     }
Index: /branches/pap/ppStack/src/ppStackPhotometry.c
===================================================================
--- /branches/pap/ppStack/src/ppStackPhotometry.c	(revision 23579)
+++ /branches/pap/ppStack/src/ppStackPhotometry.c	(revision 23580)
@@ -69,8 +69,14 @@
 
     if (!psphotReadoutKnownSources(config, photView, inSources)) {
-        // Clear the error, so that the output files are written.
-        psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry on stacked image.");
-        psFree(photView);
-        return false;
+        // This is likely a data quality issue
+        // XXX Split into multiple cases using error codes?
+        psErrorStackPrint("Unable to perform photometry on image");
+        psWarning("Unable to perform photometry on image --- suspect bad data quality.");
+        if (stats && psMetadataLookupS32(NULL, stats, "QUALITY") == 0) {
+            psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE,
+                             "Unable to perform photometry on image", psErrorCodeLast());
+        }
+        psErrorClear();
+        psphotFilesActivate(config, false);
     }
 
Index: /branches/pap/ppStack/src/ppStackSetup.c
===================================================================
--- /branches/pap/ppStack/src/ppStackSetup.c	(revision 23579)
+++ /branches/pap/ppStack/src/ppStackSetup.c	(revision 23580)
@@ -34,4 +34,5 @@
         psFree(resolved);
         options->stats = psMetadataAlloc();
+        psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", 0, "No problems", 0);
     }
 
Index: /branches/pap/ppSub/src/ppSubMakePSF.c
===================================================================
--- /branches/pap/ppSub/src/ppSubMakePSF.c	(revision 23579)
+++ /branches/pap/ppSub/src/ppSubMakePSF.c	(revision 23580)
@@ -83,6 +83,14 @@
     psArray *sources = psMetadataLookupPtr(&mdok, minuend->analysis, "PSPHOT.SOURCES");
     if (!psphotReadoutFindPSF(config, view, sources)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry on subtracted image.");
-        return false;
+        // This is likely a data quality issue
+        // XXX Split into multiple cases using error codes?
+        psErrorStackPrint("Unable to determine PSF");
+        psWarning("Unable to determine PSF --- suspect bad data quality.");
+        if (stats && psMetadataLookupS32(NULL, stats, "QUALITY") == 0) {
+            psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE,
+                             "Unable to determine PSF", psErrorCodeLast());
+        }
+        psErrorClear();
+        psphotFilesActivate(config, false);
     }
 
@@ -98,21 +106,2 @@
     return true;
 }
-
-// XXX we used to need this, is it still needed?
-
-// pmCell *photCell = pmFPAfileThisCell(config->files, view, "PSPHOT.INPUT");
-// pmCellFreeReadouts(photCell);
-
-// if (!pmFPAfileDropInternal(config->files, "PSPHOT.BACKMDL") ||
-//     !pmFPAfileDropInternal (config->files, "PSPHOT.BACKMDL.STDEV") ||
-//     !pmFPAfileDropInternal (config->files, "PSPHOT.BACKGND")) {
-//     psError(PS_ERR_UNKNOWN, false, "Unable to drop PSPHOT internal files.");
-//     return false;
-// }
-
-// Blow away the sources psphot found --- they're irrelevant for the subtraction
-// XXX is this still needed?  These are now probably not being set
-// pmReadout *photRO = pmFPAviewThisReadout(view, photFile->fpa); // Readout with sources
-// psMetadataRemoveKey(photRO->analysis, "PSPHOT.SOURCES");
-// psMetadataRemoveKey(photRO->analysis, "PSPHOT.HEADER");
-
Index: /branches/pap/ppSub/src/ppSubReadoutPhotometry.c
===================================================================
--- /branches/pap/ppSub/src/ppSubReadoutPhotometry.c	(revision 23579)
+++ /branches/pap/ppSub/src/ppSubReadoutPhotometry.c	(revision 23580)
@@ -45,6 +45,11 @@
     pmPSF *psf = psMetadataLookupPtr(NULL, psfInputChip->analysis, "PSPHOT.PSF"); // PSF for photometry
     if (!psf) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find PSF from psphot");
-        return false;
+        psWarning("No PSF available --- suspect bad data quality.");
+        if (stats && psMetadataLookupBool(NULL, stats, "QUALITY")) {
+            psError(PS_ERR_UNEXPECTED_NULL, false, "Bad or unset QUALITY flag");
+            return false;
+        }
+        psErrorClear();
+        psphotFilesActivate(config, false);
     }
     psMetadataAddPtr(psfLoadChip->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_DATA_UNKNOWN | PS_META_REPLACE,
@@ -86,7 +91,14 @@
 
     if (!psphotReadoutMinimal(config, view)) {
-        psWarning("Unable to perform photometry on subtracted image.");
-        psErrorStackPrint(stderr, "Error stack from photometry:");
+        // This is likely a data quality issue
+        // XXX Split into multiple cases using error codes?
+        psErrorStackPrint("Unable to perform photometry on image");
+        psWarning("Unable to perform photometry on image --- suspect bad data quality.");
+        if (stats && psMetadataLookupS32(NULL, stats, "QUALITY") == 0) {
+            psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE,
+                             "Unable to perform photometry on image", psErrorCodeLast());
+        }
         psErrorClear();
+        psphotFilesActivate(config, false);
     }
 #if 1
Index: /branches/pap/psphot/src/psphot.h
===================================================================
--- /branches/pap/psphot/src/psphot.h	(revision 23579)
+++ /branches/pap/psphot/src/psphot.h	(revision 23580)
@@ -31,4 +31,6 @@
 bool            psphotReadoutCleanup (pmConfig *config, pmReadout *readout, psMetadata *recipe, pmDetections *detections, pmPSF *psf, psArray *sources);
 bool            psphotDefineFiles (pmConfig *config, pmFPAfile *input);
+void            psphotFilesActivate(pmConfig *config, bool state);
+
 bool            psphotSetMaskBits (pmConfig *config);
 bool            psphotSetMaskRecipe (pmConfig *config, psImageMaskType maskValue, psImageMaskType markValue);
Index: /branches/pap/psphot/src/psphotDefineFiles.c
===================================================================
--- /branches/pap/psphot/src/psphotDefineFiles.c	(revision 23579)
+++ /branches/pap/psphot/src/psphotDefineFiles.c	(revision 23580)
@@ -1,3 +1,9 @@
 # include "psphotInternal.h"
+
+// List of output files
+static const char *outputFiles = { "PSPHOT.OUTPUT", "PSPHOT.RESID", "PSPHOT.BACKMDL", "PSPHOT.BACKMDL.STDEV",
+                                   "PSPHOT.BACKGND", "PSPHOT.BACKSUB", "PSPHOT.PSF.SAVE",
+                                   "SOURCE.PLOT.MOMENTS", "SOURCE.PLOT.PSFMODEL", "SOURCE.PLOT.APRESID",
+                                   NULL };
 
 // XXX we need to be able to distinguish several cases:
@@ -133,2 +139,13 @@
     return true;
 }
+
+void psphotFilesActivate(pmConfig *config, bool state)
+{
+    for (int i = 0; outputFiles[i]; i++) {
+        if (!pmFPAfileActivate(config->files, state, outputFiles[i])) {
+            psErrorClear();
+        }
+    }
+
+    return;
+}
Index: /branches/pap/pswarp/src/pswarpLoop.c
===================================================================
--- /branches/pap/pswarp/src/pswarpLoop.c	(revision 23579)
+++ /branches/pap/pswarp/src/pswarpLoop.c	(revision 23580)
@@ -142,4 +142,5 @@
         psFree(resolved);
         stats = psMetadataAlloc();
+        psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", 0, "No problems", 0);
     }
 
@@ -364,6 +365,6 @@
     fileActivation(config, independentFiles, false);
 
-    // We need a new PSF model for the warped frame.  It would be good to generate this analytically, but that's going to be tricky.
-    // We have a list of sources, so we use those to redetermine the PSF model.
+    // We need a new PSF model for the warped frame.  It would be good to generate this analytically, but
+    // that's going to be tricky.  We have a list of sources, so we use those to redetermine the PSF model.
 
     if (psMetadataLookupBool(&mdok, config->arguments, "PSF")) {
@@ -394,6 +395,14 @@
         // measure the PSF using these sources
         if (!psphotReadoutFindPSF(config, view, sources)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to determine PSF for warped image.");
-            return false;
+            // This is likely a data quality issue
+            // XXX Split into multiple cases using error codes?
+            psErrorStackPrint("Unable to determine PSF");
+            psWarning("Unable to determine PSF --- suspect bad data quality.");
+            if (stats && psMetadataLookupS32(NULL, stats, "QUALITY") == 0) {
+                psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", PS_META_REPLACE,
+                                 "Unable to determine PSF", psErrorCodeLast());
+            }
+            psErrorClear();
+            psphotFilesActivate(config, false);
         }
 
