Index: trunk/ppStack/src/ppStack.h
===================================================================
--- trunk/ppStack/src/ppStack.h	(revision 23172)
+++ trunk/ppStack/src/ppStack.h	(revision 23190)
@@ -10,8 +10,9 @@
 // Mask values for inputs
 typedef enum {
-    PPSTACK_MASK_MATCH  = 0x01,         // PSF-matching failed
-    PPSTACK_MASK_CHI2   = 0x02,         // Chi^2 too deviant
-    PPSTACK_MASK_REJECT = 0x04,         // Rejection failed
-    PPSTACK_MASK_BAD    = 0x08,         // Bad image (too many pixels rejected)
+    PPSTACK_MASK_CAL    = 0x01,         // Photometric calibration failed
+    PPSTACK_MASK_MATCH  = 0x02,         // PSF-matching failed
+    PPSTACK_MASK_CHI2   = 0x04,         // Chi^2 too deviant
+    PPSTACK_MASK_REJECT = 0x08,         // Rejection failed
+    PPSTACK_MASK_BAD    = 0x10,         // Bad image (too many pixels rejected)
     PPSTACK_MASK_ALL    = 0xff          // All errors
 } ppStackMask;
@@ -161,4 +162,5 @@
 /// Corrects the source PSF photometry to a common system.  Return the sum of the exposure times.
 float ppStackSourcesTransparency(const psArray *sourceLists, // Sources for each input
+                                 psVector *inputMask, // Indicates bad input
                                  const pmFPAview *view, // View to readout
                                  const pmConfig *config // Configuration
Index: trunk/ppStack/src/ppStackLoop.c
===================================================================
--- trunk/ppStack/src/ppStackLoop.c	(revision 23172)
+++ trunk/ppStack/src/ppStackLoop.c	(revision 23190)
@@ -257,4 +257,6 @@
     pmPSF *targetPSF = NULL;            // Target PSF
     float sumExposure = NAN;            // Sum of exposure times
+    psVector *inputMask = psVectorAlloc(num, PS_TYPE_VECTOR_MASK); // Mask for inputs
+    psVectorInit(inputMask, 0);
     if (psMetadataLookupBool(NULL, config->arguments, "HAVE.PSF")) {
         pmFPAfileActivate(config->files, false, NULL);
@@ -283,4 +285,5 @@
                 psFree(fileIter);
                 psFree(psfs);
+                psFree(inputMask);
                 return false;
             }
@@ -299,4 +302,5 @@
                 psFree(fileIter);
                 psFree(psfs);
+                psFree(inputMask);
                 return false;
             }
@@ -324,5 +328,6 @@
                     psFree(sourceLists);
                     psFree(targetPSF);
-                    return false;
+                    psFree(inputMask);
+                   return false;
                 }
 
@@ -333,4 +338,5 @@
                     psFree(sourceLists);
                     psFree(targetPSF);
+                    psFree(inputMask);
                     return false;
                 }
@@ -340,4 +346,5 @@
                     psFree(sourceLists);
                     psFree(targetPSF);
+                    psFree(inputMask);
                     return false;
                 }
@@ -351,9 +358,10 @@
 
         // Zero point calibration
-        sumExposure = ppStackSourcesTransparency(sourceLists, view, config);
+        sumExposure = ppStackSourcesTransparency(sourceLists, inputMask, view, config);
         if (!isfinite(sumExposure) || sumExposure <= 0) {
             psError(PS_ERR_UNKNOWN, false, "Unable to calculate transparency differences");
             psFree(sourceLists);
             psFree(targetPSF);
+            psFree(inputMask);
             return false;
         }
@@ -366,4 +374,5 @@
             psFree(sourceLists);
             psFree(view);
+            psFree(inputMask);
             return false;
         }
@@ -409,6 +418,4 @@
     int numGood = 0;                    // Number of good frames
     int numCols = 0, numRows = 0;       // Size of image
-    psVector *inputMask = psVectorAlloc(num, PS_TYPE_VECTOR_MASK); // Mask for inputs
-    psVectorInit(inputMask, 0);
     psVector *matchChi2 = psVectorAlloc(num, PS_TYPE_F32); // chi^2 for stamps when matching
     psVectorInit(matchChi2, NAN);
@@ -419,4 +426,7 @@
     psArray *covariances = psArrayAlloc(num); // Covariance matrices
     for (int i = 0; i < num; i++) {
+        if (inputMask->data.U8[i]) {
+            continue;
+        }
         psTrace("ppStack", 2, "Convolving input %d of %d to target PSF....\n", i, num);
         pmFPAfileActivate(config->files, false, NULL);
Index: trunk/ppStack/src/ppStackSources.c
===================================================================
--- trunk/ppStack/src/ppStackSources.c	(revision 23172)
+++ trunk/ppStack/src/ppStackSources.c	(revision 23190)
@@ -13,11 +13,55 @@
 #define FAKE_ROWS 4913
 
-float ppStackSourcesTransparency(const psArray *sourceLists, const pmFPAview *view, const pmConfig *config)
+#ifdef TESTING
+// Dump matches to a file
+static void dumpMatches(const char *filename, // File to which to dump
+                        int num,        // Number of inputs
+                        psArray *matches, // Star matches
+                        psVector *zp,   // Zero points
+                        psVector *trans // Transparencies
+                        )
+{
+    FILE *outMatches = fopen(filename, "w"); // Output matches
+    psVector *mag = psVectorAlloc(num, PS_TYPE_F32); // Magnitudes for each star
+    psVector *magErr = psVectorAlloc(num, PS_TYPE_F32); // Errors for each star
+    for (int i = 0; i < matches->n; i++) {
+        pmSourceMatch *match = matches->data[i]; // Match of interest
+        psVectorInit(mag, NAN);
+        psVectorInit(magErr, NAN);
+        for (int j = 0; j < match->num; j++) {
+            if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j]) {
+                continue;
+            }
+            int index = match->image->data.U32[j]; // Image index
+            mag->data.F32[index] = match->mag->data.F32[j] - zp->data.F32[index];
+            if (trans) {
+                mag->data.F32[index] -= trans->data.F32[index];
+            }
+            magErr->data.F32[index] = match->magErr->data.F32[j];
+        }
+        for (int j = 0; j < num; j++) {
+            fprintf(outMatches, "%f (%f) ", mag->data.F32[j], magErr->data.F32[j]);
+        }
+        fprintf(outMatches, "\n");
+    }
+    psFree(mag);
+    psFree(magErr);
+    fclose(outMatches);
+    return;
+}
+#endif
+
+
+float ppStackSourcesTransparency(const psArray *sourceLists, psVector *inputMask,
+                                 const pmFPAview *view, const pmConfig *config)
 {
     PS_ASSERT_ARRAY_NON_NULL(sourceLists, NAN);
+    PS_ASSERT_VECTOR_NON_NULL(inputMask, NAN);
+    PS_ASSERT_VECTOR_TYPE(inputMask, PS_TYPE_U8, NAN);
+    PS_ASSERT_VECTOR_SIZE(inputMask, sourceLists->n, NAN);
     PS_ASSERT_PTR_NON_NULL(view, NAN);
     PS_ASSERT_PTR_NON_NULL(config, NAN);
 
-#ifdef TESTING
+#if defined(TESTING) && 0
     {
         // Deliberately induce a major transparency difference
@@ -63,5 +107,5 @@
         pmCell *cell = pmFPAviewThisCell(view, file->fpa); // Cell of interest
 
-#ifdef TESTING
+#if defined(TESTING) && 0
         pmReadout *fake = pmReadoutAlloc(NULL); // Fake readout
         pmPSF *psf = psMetadataLookupPtr(NULL, config->arguments, "PSF.TARGET"); // PSF for fake image
@@ -114,35 +158,25 @@
         return NAN;
     }
+
+#ifdef TESTING
+    dumpMatches("source_match.dat", num, matches, zp, NULL);
+#endif
+
     psVector *trans = pmSourceMatchRelphot(matches, zp, iter, tol, starLimit, transIter, transRej,
                                            transThresh, starRej, starSys); // Transparencies for each image
-
-#ifdef TESTING
-    {
-        // Dump the corrected magnitudes
-        FILE *outMatches = fopen("source_match.dat", "w"); // Output matches
-        psVector *mag = psVectorAlloc(num, PS_TYPE_F32); // Magnitudes for each star
-        psVector *magErr = psVectorAlloc(num, PS_TYPE_F32); // Errors for each star
-        for (int i = 0; i < matches->n; i++) {
-            pmSourceMatch *match = matches->data[i]; // Match of interest
-            psVectorInit(mag, NAN);
-            psVectorInit(magErr, NAN);
-            for (int j = 0; j < match->num; j++) {
-                if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j]) {
-                    continue;
-                }
-                int index = match->image->data.U32[j]; // Image index
-                mag->data.F32[index] = match->mag->data.F32[j] - zp->data.F32[index] - trans->data.F32[index];
-                magErr->data.F32[index] = match->magErr->data.F32[j];
-            }
-            for (int j = 0; j < num; j++) {
-                fprintf(outMatches, "%f (%f) ", mag->data.F32[j], magErr->data.F32[j]);
-            }
-            fprintf(outMatches, "\n");
-        }
-        psFree(mag);
-        psFree(magErr);
-        fclose(outMatches);
-    }
-#endif
+    if (!trans) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to measure transparencies");
+        return NAN;
+    }
+
+#ifdef TESTING
+    dumpMatches("source_mags.dat", num, matches, zp, trans);
+#endif
+
+    for (int i = 0; i < trans->n; i++) {
+        if (!isfinite(trans->data.F32[i])) {
+            inputMask->data.U8[i] = PPSTACK_MASK_CAL;
+        }
+    }
 
     // Save best matches SOMEWHERE for future photometry
@@ -154,15 +188,15 @@
     int minMatches = PS_MAX (2, 0.5*num);
     for (int i = 0; i < matches->n; i++) {
-	pmSourceMatch *match = matches->data[i]; // Match of interest
-	if (match->num < minMatches) continue;
-
-	// We need to grab a single instance of this source: just take the first available
-	int nImage = match->image->data.S32[0];
-	int nIndex = match->index->data.S32[0];
-	psArray *sources = sourceLists->data[nImage];
-	pmSource *source = sources->data[nIndex];
-	
-	// stick this sample source on sourcesBest
-	psArrayAdd (sourcesBest, 100, source);
+        pmSourceMatch *match = matches->data[i]; // Match of interest
+        if (match->num < minMatches) continue;
+
+        // We need to grab a single instance of this source: just take the first available
+        int nImage = match->image->data.S32[0];
+        int nIndex = match->index->data.S32[0];
+        psArray *sources = sourceLists->data[nImage];
+        pmSource *source = sources->data[nIndex];
+
+        // stick this sample source on sourcesBest
+        psArrayAdd (sourcesBest, 100, source);
     }
     psMetadataAdd (sourcesCell->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY | PS_META_REPLACE, "psphot sources", sourcesBest);
@@ -171,8 +205,4 @@
 
     psFree(matches);
-    if (!trans) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to measure transparencies");
-        return NAN;
-    }
 
     // M = m + c0 + c1 * airmass - 2.5log(t) + transparency
@@ -182,4 +212,7 @@
     // We don't need to know the magnitude zero point for the filter, since it cancels out
     for (int i = 0; i < num; i++) {
+        if (!isfinite(trans->data.F32[i])) {
+            continue;
+        }
         psArray *sources = sourceLists->data[i]; // Sources of interest
         float magCorr = airmassTerm - 2.5*log10(sumExpTime) - zp->data.F32[i] - trans->data.F32[i];
Index: trunk/ppStack/src/ppStackThread.c
===================================================================
--- trunk/ppStack/src/ppStackThread.c	(revision 23172)
+++ trunk/ppStack/src/ppStackThread.c	(revision 23190)
@@ -36,7 +36,13 @@
     psFree(stack->threads);
     for (int i = 0; i < stack->imageFits->n; i++) {
-        psFitsClose(stack->imageFits->data[i]);
-        psFitsClose(stack->maskFits->data[i]);
-        psFitsClose(stack->varianceFits->data[i]);
+        if (stack->imageFits->data[i]) {
+            psFitsClose(stack->imageFits->data[i]);
+        }
+        if (stack->maskFits->data[i]) {
+            psFitsClose(stack->maskFits->data[i]);
+        }
+        if (stack->varianceFits->data[i]) {
+            psFitsClose(stack->varianceFits->data[i]);
+        }
         stack->imageFits->data[i] = stack->maskFits->data[i] = stack->varianceFits->data[i] = NULL;
     }
