Index: /branches/eam_branches/psphot.stack.20100120/doc/stack.txt
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/doc/stack.txt	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/doc/stack.txt	(revision 26643)
@@ -1,2 +1,27 @@
+
+20100120 : more stack processing mods:
+
+  there are a number of data collections generated during psphotReadout:
+
+  * detections (currently a structure containing multiple arrays)
+  * sources (a psArray)
+  * psf (the psf model structure)
+  
+  * new sources vs old sources:
+    there is a sequence on the second pass in which we need to distinguish the sources
+    from the first pass from those on the second pass:
+
+    - add noise (old sources only)
+    - find detections
+    - subtract noise (old sources only)
+    - generate sources (new detections only)
+    - source classifications (new sources only)
+    - guess models (new sources only)
+    - replace sources (old sources only)
+    - merge sources (new + old -> sources)
+
+    currently we are distiguishing the old vs new based on different arrays.
+    can we use the processing flags to distinguish the these cases and carry around 
+    only a single source list?
 
 20100107 : updates for stack processing
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotBasicDeblend.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotBasicDeblend.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotBasicDeblend.c	(revision 26643)
@@ -1,5 +1,5 @@
 # include "psphotInternal.h"
 
-bool psphotBasicDeblend (psArray *sources, psMetadata *recipe) {
+bool psphotBasicDeblend (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
 
     int N;
@@ -8,7 +8,21 @@
     pmSource *source, *testSource;
 
+    psTimerStart ("psphot.deblend.basic");
+
     int Nblend = 0;
 
-    psTimerStart ("psphot.deblend.basic");
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
+    psAssert (readout, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    psArray *sources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES");
+    psAssert (sources, "missing sources?");
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
 
     float FRACTION = psMetadataLookupF32 (&status, recipe, "DEBLEND_PEAK_FRACTION");
@@ -128,2 +142,20 @@
     return true;
 }
+
+// for now, let's store the detections on the readout->analysis for each readout
+bool psphotBasicDeblend (pmConfig *config, const pmFPAview *view)
+{
+    bool status = true;
+
+    int num = psMetadataAddS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
+    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+
+    // loop over the available readouts
+    for (int i = 0; i < num; i++) {
+	if (!psphotBasicDeblendReadout (config, view, "PSPHOT.INPUT", i)) {
+            psError (PSPHOT_ERR_CONFIG, false, "failed on saturated star deblend analysis for PSPHOT.INPUT entry %d", i);
+	    return false;
+	}
+    }
+    return true;
+}
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotChoosePSF.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotChoosePSF.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotChoosePSF.c	(revision 26643)
@@ -2,17 +2,31 @@
 
 // try PSF models and select best option
-pmPSF *psphotChoosePSF (pmReadout *readout, psArray *sources, psMetadata *recipe) {
+bool psphotChoosePSFReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
 
     bool status;
 
     psTimerStart ("psphot.choose.psf");
+
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
+    psAssert (readout, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    psArray *sources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES");
+    psAssert (sources, "missing sources?");
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
 
     // bit-masks to test for good/bad pixels
     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT");
-    assert (maskVal);
+    psAssert (maskVal, "missing mask value?");
 
     // bit-mask to mark pixels not used in analysis
     psImageMaskType markVal = psMetadataLookupImageMask(&status, recipe, "MARK.PSPHOT");
-    assert (markVal);
+    psAssert (markVal, "missing mark value?");
 
     // maskVal is used to test for rejected pixels, and must include markVal
@@ -302,5 +316,12 @@
 
     psFree (options);
-    return (psf);
+
+    // save PSF on readout->analysis
+    if (!psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.PSF", PS_DATA_PTR, "psphot psf model", psf)) {
+	psError (PSPHOT_ERR_UNKNOWN, false, "problem saving sources on readout");
+        return false;
+    }
+
+    return true;
 }
 
@@ -445,2 +466,20 @@
     return true;
 }
+
+// for now, let's store the detections on the readout->analysis for each readout
+bool psphotChoosePSF (pmConfig *config, const pmFPAview *view)
+{
+    bool status = true;
+
+    int num = psMetadataAddS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
+    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+
+    // loop over the available readouts
+    for (int i = 0; i < num; i++) {
+	if (!psphotChoosePSFReadout (config, view, "PSPHOT.INPUT", i, havePSF)) {
+            psError (PSPHOT_ERR_CONFIG, false, "failed on saturated star deblend analysis for PSPHOT.INPUT entry %d", i);
+	    return false;
+	}
+    }
+    return true;
+}
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotDeblendSatstars.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotDeblendSatstars.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotDeblendSatstars.c	(revision 26643)
@@ -1,5 +1,5 @@
 # include "psphotInternal.h"
 
-bool psphotDeblendSatstars (pmReadout *readout, psArray *sources, psMetadata *recipe) {
+bool psphotDeblendSatstarsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
 
     int N;
@@ -10,4 +10,18 @@
     int Nblend = 0;
     float SAT_MIN_RADIUS = 5.0;
+
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
+    psAssert (readout, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    psArray *sources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES");
+    psAssert (sources, "missing sources?");
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
 
     bool status;
@@ -169,2 +183,20 @@
     return true;
 }
+
+// for now, let's store the detections on the readout->analysis for each readout
+bool psphotDeblendSatstars (pmConfig *config, const pmFPAview *view)
+{
+    bool status = true;
+
+    int num = psMetadataAddS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
+    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+
+    // loop over the available readouts
+    for (int i = 0; i < num; i++) {
+	if (!psphotDeblendSatstarsReadout (config, view, "PSPHOT.INPUT", i)) {
+            psError (PSPHOT_ERR_CONFIG, false, "failed on saturated star deblend analysis for PSPHOT.INPUT entry %d", i);
+	    return false;
+	}
+    }
+    return true;
+}
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotFindDetections.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotFindDetections.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotFindDetections.c	(revision 26643)
@@ -2,5 +2,5 @@
 
 // smooth the image, search for peaks, optionally define footprints based on the peaks
-pmDetections *psphotFindDetections (pmDetections *detections, pmReadout *readout, psMetadata *recipe) {
+bool psphotFindDetections (pmConfig *config, const pmFPAview *view, const char *filename, int index) {
 
     bool status;
@@ -9,7 +9,18 @@
     int NMAX = 0;
 
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
+    psAssert (readout, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
+
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
     psImageMaskType maskVal = psMetadataLookupImageMask(&status, recipe, "MASK.PSPHOT"); // Mask value for bad pixels
-    assert (maskVal);
+    psAssert (maskVal, "missing mask value?");
 
     // Use the new pmFootprints approach?
@@ -71,5 +82,11 @@
     psphotVisualShowFootprints (detections);
 
-    return detections;
+    // save detections on the readout->analysis
+    if (!psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_DATA_PTR, "psphot detectinos", detections)) {
+	psError (PSPHOT_ERR_CONFIG, false, "problem saving detections on readout");
+        return NULL;
+    }
+
+    return true;
 }
 
@@ -77,6 +94,5 @@
 // otherwise it only contains the new peaks.
 
-# if 0
-// XXX where do we place the N sets of detections?
+// for now, let's store the detections on the readout->analysis for each readout
 bool psphotFindDetections (pmConfig *config, const pmFPAview *view)
 {
@@ -84,10 +100,10 @@
 
     int num = psMetadataAddS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
-    psAbort (!status, "programming error: must define PSPHOT.INPUT.NUM");
+    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
 
     // loop over the available readouts
     for (int i = 0; i < num; i++) {
 	if (!psphotFindDetectionsReadout (config, view, "PSPHOT.INPUT", i)) {
-            psError (PSPHOT_ERR_CONFIG, false, "failed to subtract background for PSPHOT.INPUT entry %d", i);
+            psError (PSPHOT_ERR_CONFIG, false, "failed to find initial detections for PSPHOT.INPUT entry %d", i);
 	    return false;
 	}
@@ -95,3 +111,2 @@
     return true;
 }
-# endif
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotReadout.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotReadout.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotReadout.c	(revision 26643)
@@ -48,4 +48,5 @@
 
     // display the image, weight, mask (ch 1,2,3)
+    // XXX move this into the loop above
     psphotVisualShowImage (readout);
 
@@ -62,4 +63,5 @@
 
     // display the backsub and backgnd images
+    // move this inthe the subtract background loop
     psphotVisualShowBackground (config, view, readout);
 
@@ -74,6 +76,5 @@
 
     // find the detections (by peak and/or footprint) in the image.
-    pmDetections *detections = psphotFindDetections (NULL, readout, recipe);
-    if (!detections) {
+    if (!psphotFindDetections (config, view)) {
 	// this only happens if we had an error in psphotFindDetections
         psError (PSPHOT_ERR_UNKNOWN, false, "failure in peak analysis");
@@ -86,6 +87,8 @@
 
     // construct sources and measure basic stats
-    psArray *sources = psphotSourceStats (config, readout, detections, true);
-    if (!sources) return false;
+    if (!psphotSourceStats (config, view, true)) {
+	// XXX do I need to raise an error here?
+	return false; 
+    }
     if (!strcasecmp (breakPt, "PEAKS")) {
         return psphotReadoutCleanup(config, readout, recipe, detections, psf, sources);
@@ -94,8 +97,11 @@
     // find blended neighbors of very saturated stars
     // XXX merge this with Basic Deblend?
-    psphotDeblendSatstars (readout, sources, recipe);
+    if (!psphotDeblendSatstars (config, view)) {
+        psLogMsg ("psphot", 3, "failed on satstar deblend analysis");
+        return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
+    }
 
     // mark blended peaks PS_SOURCE_BLEND
-    if (!psphotBasicDeblend (sources, recipe)) {
+    if (!psphotBasicDeblend (config, view)) {
         psLogMsg ("psphot", 3, "failed on deblend analysis");
         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
@@ -103,5 +109,5 @@
 
     // classify sources based on moments, brightness
-    if (!psphotRoughClass (readout, sources, recipe, havePSF)) {
+    if (!psphotRoughClass (config, view, havePSF)) {
         psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
@@ -121,6 +127,5 @@
         // XXX if we do not have enough stars to generate the PSF, build one
         // from the SEEING guess and model class
-        psf = psphotChoosePSF (readout, sources, recipe);
-        if (psf == NULL) {
+        if (!psphotChoosePSF (config, view)) {
             psLogMsg ("psphot", 3, "failure to construct a psf model");
             return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
@@ -131,4 +136,5 @@
         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
     }
+    // move into psphotChoosePSF 
     psphotVisualShowPSFModel (readout, psf);
 
@@ -147,5 +153,5 @@
 
     // identify CRs and extended sources
-    psphotSourceSize (config, readout, sources, recipe, psf, 0);
+    psphotSourceSize (config, view);
     if (!strcasecmp (breakPt, "ENSEMBLE")) {
         goto finish;
@@ -182,5 +188,5 @@
 
     // set source type
-    if (!psphotRoughClass (readout, newSources, recipe, havePSF)) {
+    if (!psphotRoughClass (config, view, havePSF)) {
         psLogMsg ("psphot", 3, "failed to find a valid PSF clump for image");
         return psphotReadoutCleanup (config, readout, recipe, detections, psf, sources);
@@ -203,5 +209,5 @@
 
     // measure source size for the remaining sources
-    psphotSourceSize (config, readout, sources, recipe, psf, 0);
+    psphotSourceSize (config, view);
 
     psphotExtendedSourceAnalysis (readout, sources, recipe);
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotReadoutCleanup.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotReadoutCleanup.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotReadoutCleanup.c	(revision 26643)
@@ -61,7 +61,5 @@
     // save the results of the analysis
     psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.HEADER",  PS_DATA_METADATA, "header stats", header);
-    if (sources) {
-        psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY, "psphot sources", sources);
-    }
+
     if (psf) {
         // save the psf for possible output.  if there was already an entry, it was loaded from external sources
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotRoughClass.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotRoughClass.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotRoughClass.c	(revision 26643)
@@ -10,9 +10,23 @@
 
 // 2006.02.02 : no leaks
-bool psphotRoughClass (pmReadout *readout, psArray *sources, psMetadata *recipe, const bool havePSF) {
+bool psphotRoughClassReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, const bool havePSF) {
 
     bool status;
 
     psTimerStart ("psphot.rough");
+
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
+    psAssert (readout, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    psArray *sources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES");
+    psAssert (sources, "missing sources?");
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
 
     // we make this measurement on a NxM grid of regions across the readout
@@ -111,2 +125,20 @@
     return true;
 }
+
+// for now, let's store the detections on the readout->analysis for each readout
+bool psphotRoughClass (pmConfig *config, const pmFPAview *view, const bool havePSF)
+{
+    bool status = true;
+
+    int num = psMetadataAddS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
+    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+
+    // loop over the available readouts
+    for (int i = 0; i < num; i++) {
+	if (!psphotRoughClassReadout (config, view, "PSPHOT.INPUT", i, havePSF)) {
+            psError (PSPHOT_ERR_CONFIG, false, "failed on saturated star deblend analysis for PSPHOT.INPUT entry %d", i);
+	    return false;
+	}
+    }
+    return true;
+}
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotSourceSize.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotSourceSize.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotSourceSize.c	(revision 26643)
@@ -28,6 +28,25 @@
 // deviation from the psf model at the r = FWHM/2 position
 
+// for now, let's store the detections on the readout->analysis for each readout
+bool psphotSourceSize (pmConfig *config, const pmFPAview *view)
+{
+    bool status = true;
+
+    int num = psMetadataAddS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
+    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+
+    // loop over the available readouts
+    for (int i = 0; i < num; i++) {
+	if (!psphotSourceSizeReadout (config, view, "PSPHOT.INPUT", i)) {
+            psError (PSPHOT_ERR_CONFIG, false, "failed on saturated star deblend analysis for PSPHOT.INPUT entry %d", i);
+	    return false;
+	}
+    }
+    return true;
+}
+
 // XXX use an internal flag to mark sources which have already been measured
-bool psphotSourceSize(pmConfig *config, pmReadout *readout, psArray *sources, psMetadata *recipe, pmPSF *psf, long first)
+// how to track the sources already measured?
+bool psphotSourceSize(pmConfig *config, const pmFPAview *view, const char *filename, int index)
 {
     bool status;
@@ -35,4 +54,21 @@
 
     psTimerStart ("psphot.size");
+
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
+    psAssert (readout, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    psArray *sources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES");
+    psAssert (sources, "missing sources?");
+
+    pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
+    psAssert (psf, "missing psf?");
+
+    // select the appropriate recipe information
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
+    psAssert (recipe, "missing recipe?");
 
     // user-defined masks to test for good/bad pixels (build from recipe list if not yet set)
Index: /branches/eam_branches/psphot.stack.20100120/src/psphotSourceStats.c
===================================================================
--- /branches/eam_branches/psphot.stack.20100120/src/psphotSourceStats.c	(revision 26642)
+++ /branches/eam_branches/psphot.stack.20100120/src/psphotSourceStats.c	(revision 26643)
@@ -3,5 +3,5 @@
 bool psphotSetMomentsWindow (psMetadata *recipe, psMetadata *analysis, psArray *sources);
 
-psArray *psphotSourceStats (pmConfig *config, pmReadout *readout, pmDetections *detections, bool setWindow) {
+bool psphotSourceStatsReadout (pmConfig *config, const pmFPAview *view, const char *filename, int index, bool setWindow) {
 
     bool status = false;
@@ -10,7 +10,17 @@
     psTimerStart ("psphot.stats");
 
+    // find the currently selected readout
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, filename, index); // File of interest
+    psAssert (readout, "missing file?");
+
+    pmReadout *readout = pmFPAviewThisReadout(view, file->fpa);
+    psAssert (readout, "missing readout?");
+
+    pmDetections *detections = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.DETECTIONS");
+    psAssert (detections, "missing detections?");
+
     // select the appropriate recipe information
     psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSPHOT_RECIPE);
-    assert (recipe);
+    psAssert (recipe, "missing recipe?");
 
     // determine the number of allowed threads
@@ -21,16 +31,17 @@
 
     // determine properties (sky, moments) of initial sources
-    float OUTER    = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
-    if (!status) return NULL;
-
+    float OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
+    psAssert (status, "missing SKY_OUTER_RADIUS in recipe?");
+
+    // XXX this seems like an arbitrary number...
     OUTER = PS_MAX(OUTER, 20.0); // XXX Guarantee that we can encompass the max moments radius
 
     char *breakPt  = psMetadataLookupStr (&status, recipe, "BREAK_POINT");
-    if (!status) return NULL;
+    if (!status) return false;
 
     psArray *peaks = detections->peaks;
     if (!peaks) {
         psError(PS_ERR_UNEXPECTED_NULL, false, "No peaks found!");
-        return NULL;
+        return false;
     }
 
@@ -64,5 +75,12 @@
         psLogMsg ("psphot", PS_LOG_INFO, "break point PEAKS, skipping MOMENTS\n");
         psphotVisualShowMoments (sources);
-        return sources;
+	// save sources on the readout->analysis
+	if (!psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY, "psphot sources", sources)) {
+	    psError (PSPHOT_ERR_UNKNOWN, false, "problem saving sources on readout");
+	    psFree(sources);
+	    return false;
+	}
+	psFree(sources);
+        return true;
     }
 
@@ -70,5 +88,6 @@
         if (!psphotSetMomentsWindow(recipe, readout->analysis, sources)) {
             psError(PS_ERR_UNEXPECTED_NULL, false, "Failed to determine Moments Window!");
-            return NULL;
+	    psFree(sources);
+            return false;
         }
     }
@@ -103,5 +122,6 @@
                 psError(PS_ERR_UNKNOWN, false, "Unable to launch thread job PSPHOT_SOURCE_STATS");
                 psFree (job);
-                return NULL;
+		psFree(sources);
+                return false;
             }
             psFree(job);
@@ -111,5 +131,6 @@
         if (!psThreadPoolWait (false)) {
             psError(PS_ERR_UNKNOWN, false, "Failure in thread job PSPHOT_SOURCE_STATS");
-            return NULL;
+	    psFree(sources);
+            return false;
         }
 
@@ -138,7 +159,15 @@
     psphotVisualShowMoments (sources);
 
-    return (sources);
+    // save sources on the readout->analysis
+    if (!psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY, "psphot sources", sources)) {
+	psError (PSPHOT_ERR_UNKNOWN, false, "problem saving sources on readout");
+	psFree(sources);
+        return false;
+    }
+    psFree(sources);
+    return true;
 }
 
+// XXX fix the return status of this function...
 bool psphotSourceStatsUpdate (psArray *sources, pmConfig *config, pmReadout *readout) {
 
@@ -451,2 +480,24 @@
     return true;
 }
+
+
+// if we use the footprints, the output peaks list contains both old and new peaks,
+// otherwise it only contains the new peaks.
+
+// for now, let's store the detections on the readout->analysis for each readout
+bool psphotSourceStats (pmConfig *config, const pmFPAview *view, bool setWindow)
+{
+    bool status = true;
+
+    int num = psMetadataAddS32 (&status, config->arguments, "PSPHOT.INPUT.NUM");
+    psAssert (status, "programming error: must define PSPHOT.INPUT.NUM");
+
+    // loop over the available readouts
+    for (int i = 0; i < num; i++) {
+	if (!psphotFindDetectionsReadout (config, view, "PSPHOT.INPUT", i, setWindow)) {
+            psError (PSPHOT_ERR_CONFIG, false, "failed to find initial detections for PSPHOT.INPUT entry %d", i);
+	    return false;
+	}
+    }
+    return true;
+}
