Index: trunk/ppStack/src/ppStack.h
===================================================================
--- trunk/ppStack/src/ppStack.h	(revision 20426)
+++ trunk/ppStack/src/ppStack.h	(revision 20427)
@@ -82,4 +82,12 @@
     );
 
+// Re-do photometry on input sources
+//
+// Photometry for the sources is replaced by what is measured
+bool ppStackInputPhotometry(const pmReadout *ro, // Readout
+                            const psArray *sources, // Sources to photometer
+                            const pmConfig *config // Configuration
+    );
+
 // Perform stacking on a readout
 //
Index: trunk/ppStack/src/ppStackLoop.c
===================================================================
--- trunk/ppStack/src/ppStackLoop.c	(revision 20426)
+++ trunk/ppStack/src/ppStackLoop.c	(revision 20427)
@@ -318,4 +318,36 @@
                 }
                 indSources->data[index] = psMemIncrRefCounter(sources);
+
+
+                // Calculate zero points if we don't trust the source lists
+                if (psMetadataLookupBool(NULL, recipe, "ZP")) {
+                    psTrace("ppStack", 2, "Photometering input %d of %d....\n", index, num);
+                    pmFPAfileActivate(config->files, false, NULL);
+                    fileActivationSingle(config, convolveFiles, true, index);
+                    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPSTACK.INPUT",
+                                                            index);// File of interest
+                    pmFPAview *view = filesIterateDown(config);
+                    if (!view) {
+                        psFree(globalSources);
+                        psFree(indSources);
+                        psFree(targetPSF);
+                        return false;
+                    }
+
+                    pmReadout *ro = pmFPAviewThisReadout(view, file->fpa); // Readout of interest
+
+                    if (!ppStackInputPhotometry(ro, sources, config)) {
+                        psError(PS_ERR_UNKNOWN, false, "Unable to do photometry on input sources");
+                        psFree(globalSources);
+                        psFree(indSources);
+                        psFree(targetPSF);
+                        return false;
+                    }
+
+                    psFree(view);
+                    filesIterateUp(config);
+                }
+
+
 #ifdef TESTING
                 ppStackSourcesPrint(sources);
Index: trunk/ppStack/src/ppStackPhotometry.c
===================================================================
--- trunk/ppStack/src/ppStackPhotometry.c	(revision 20426)
+++ trunk/ppStack/src/ppStackPhotometry.c	(revision 20427)
@@ -9,4 +9,105 @@
 
 #include "ppStack.h"
+
+#define PHOT_SOURCE_MASK (PM_SOURCE_MODE_FAIL | PM_SOURCE_MODE_SATSTAR | PM_SOURCE_MODE_BLEND | \
+                          PM_SOURCE_MODE_BADPSF | PM_SOURCE_MODE_DEFECT | PM_SOURCE_MODE_SATURATED | \
+                          PM_SOURCE_MODE_CR_LIMIT | PM_SOURCE_MODE_EXT_LIMIT) // Mask to apply to sources
+
+bool ppStackInputPhotometry(const pmReadout *ro, const psArray *sources, const pmConfig *config)
+{
+    PM_ASSERT_READOUT_NON_NULL(ro, false);
+    PS_ASSERT_ARRAY_NON_NULL(sources, false);
+
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
+    psAssert(recipe, "We've thrown an error on this before.");
+
+    bool mdok;                          // Status of MD lookup
+
+    float zpRadius = psMetadataLookupS32(&mdok, recipe, "ZP.RADIUS"); // Radius for ZP measurement
+    if (!mdok) {
+        psError(PS_ERR_UNKNOWN, true, "Unable to find ZP.RADIUS in recipe");
+        return false;
+    }
+    float zpSigma = psMetadataLookupF32(&mdok, recipe, "ZP.SIGMA"); // Gaussian sigma for photometry
+    if (!mdok) {
+        psError(PS_ERR_UNKNOWN, true, "Unable to find ZP.SIGMA in recipe");
+        return false;
+    }
+    float zpFrac = psMetadataLookupF32(&mdok, recipe, "ZP.FRAC"); // Fraction of good pixels for photometry
+    if (!mdok) {
+        psError(PS_ERR_UNKNOWN, true, "Unable to find ZP.FRAC in recipe");
+        return false;
+    }
+
+    psString maskValStr = psMetadataLookupStr(&mdok, recipe, "MASK.VAL"); // Name of bits to mask going in
+    if (!mdok || !maskValStr) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to find MASK.VAL in recipe");
+        return false;
+    }
+    psMaskType maskVal = pmConfigMaskGet(maskValStr, config); // Bits to mask
+
+    psImage *image = ro->image, *mask = ro->mask; // Image and mask from readout
+
+    // Measure background
+    psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, 0); // Random number generator
+    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics
+    if (!psImageBackground(stats, NULL, image, mask, maskVal, rng)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to measure background for image");
+        psFree(stats);
+        psFree(rng);
+        return false;
+    }
+    float bg = stats->robustMedian; // Background level
+    psFree(stats);
+    psFree(rng);
+
+    // Photometer sources
+    int numCols = image->numCols, numRows = image->numRows; // Size of image
+    int numSources = sources->n; // Number of sources
+    int numGood = 0;            // Number of good sources
+    float maxMag = -INFINITY;   // Maximum magnitude
+    for (int j = 0; j < numSources; j++) {
+        pmSource *source = sources->data[j]; // Source of interest
+        if (source->mode & PHOT_SOURCE_MASK || !isfinite(source->psfMag)) {
+            source->psfMag = NAN;
+            continue;
+        }
+        float x = source->peak->xf, y = source->peak->yf; // Coordinates of source
+        int xCentral = x + 0.5, yCentral = y + 0.5; // Central pixel
+        // Range of integration
+        int xMin = PS_MAX(0, xCentral - zpRadius), xMax = PS_MIN(numCols - 1, xCentral + zpRadius);
+        int yMin = PS_MAX(0, yCentral - zpRadius), yMax = PS_MIN(numRows - 1, yCentral + zpRadius);
+
+        // Integrate
+        double sumImage = 0.0, sumKernel = 0.0; // Sums from integration
+        int numBadPix = 0;         // Number of bad pixels
+        for (int v = yMin; v <= yMax; v++) {
+            float dy2 = PS_SQR(y - v); // Distance from centroid
+            for (int u = xMin; u <= xMax; u++) {
+                if (mask->data.PS_TYPE_MASK_DATA[v][u] & maskVal) {
+                    numBadPix++;
+                    continue;
+                }
+                float dx2 = PS_SQR(x - u); // Distance from centroid
+                double kernel = exp(-0.5 * (dx2 + dy2) / PS_SQR(zpSigma)); // Kernel value
+                sumImage += (image->data.F32[v][u] - bg) * kernel;
+                sumKernel += kernel;
+            }
+        }
+
+        if (numBadPix > zpFrac * M_PI * PS_SQR(zpRadius) || !isfinite(sumImage)) {
+            source->psfMag = NAN;
+        } else {
+            source->psfMag = - 2.5 * log10(sumImage / sumKernel * M_PI * PS_SQR(zpRadius));
+            numGood++;
+            maxMag = PS_MAX(maxMag, source->psfMag);
+        }
+    }
+    psLogMsg("ppStack", PS_LOG_INFO, "Photometered %d good sources in image; max mag %f", numGood, maxMag);
+
+    return true;
+}
+
+
 
 bool ppStackPhotometry(pmConfig *config, const pmReadout *readout, const pmFPAview *view)
