Index: trunk/ppImage/src/ppImageLoop.c
===================================================================
--- trunk/ppImage/src/ppImageLoop.c	(revision 19399)
+++ trunk/ppImage/src/ppImageLoop.c	(revision 19928)
@@ -5,20 +5,17 @@
 #include "ppImage.h"
 
-# define ESCAPE(MESSAGE) { \
+#define ESCAPE(MESSAGE) { \
   psError(PS_ERR_UNKNOWN, false, MESSAGE); \
-  psFree (view); \
+  psFree(view); \
   return false; \
 }
 
-bool ppImageLoop (pmConfig *config, ppImageOptions *options)
+bool ppImageLoop(pmConfig *config, ppImageOptions *options)
 {
-    bool status;
-    pmChip *chip;
-    pmCell *cell;
-    pmReadout *readout;
-
-    // measure the total elapsed time in ppImageLoop.
-    psTimerStart ("ppImageLoop");
-
+    psMetadata *stats = options->doStats ? psMetadataAlloc() : NULL; // Statistics to output
+    float timeDetrend = 0;              // Amount of time spent in detrend
+    float timePhot = 0;                 // Amount of time spent in photometry
+
+    bool status;                        // Status of MD lookup
     pmFPAfile *input = psMetadataLookupPtr(&status, config->files, "PPIMAGE.INPUT");
     if (!status) {
@@ -40,6 +37,9 @@
 
     // files associated with the science image
-    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) ESCAPE ("load failure for FPA");
-
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        ESCAPE("load failure for FPA");
+    }
+
+    pmChip *chip;                       // Chip from FPA
     while ((chip = pmFPAviewNextChip(view, input->fpa, 1)) != NULL) {
         psLogMsg ("ppImageLoop", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
@@ -47,6 +47,10 @@
             continue;
         }
-        if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) ESCAPE ("load failure for Chip");
-
+        if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+            ESCAPE("load failure for Chip");
+        }
+
+        psTimerStart(TIMER_DETREND);
+        pmCell *cell;                   // Cell from chip
         while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) {
             psLogMsg ("ppImageLoop", 5, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
@@ -54,5 +58,7 @@
                 continue;
             }
-            if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) ESCAPE ("load failure for Cell");
+            if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                ESCAPE("load failure for Cell");
+            }
 
             // Put version information into the header
@@ -70,6 +76,9 @@
 
             // process each of the readouts
+            pmReadout *readout;         // Readout from cell
             while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
-                if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) ESCAPE ("load failure for Readout");
+                if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                    ESCAPE("load failure for Readout");
+                }
                 if (!readout->data_exists) {
                     continue;
@@ -78,10 +87,12 @@
                 // XXX set the options->*Mask values here (after the mask images have been loaded
                 // and before any of the value are used)
-                if (!ppImageSetMaskBits (config, options))
-                    ESCAPE ("Unable to set bit masks");
+                if (!ppImageSetMaskBits(config, options)) {
+                    ESCAPE("Unable to set bit masks");
+                }
 
                 // perform the detrend analysis
-                if (!ppImageDetrendReadout(config, options, view))
-                    ESCAPE ("Unable to detrend readout");
+                if (!ppImageDetrendReadout(config, options, view)) {
+                    ESCAPE("Unable to detrend readout");
+                }
             }
         }
@@ -89,32 +100,42 @@
         // Apply the fringe correction
         if (options->doFringe) {
-            if (!ppImageDetrendFringeApply (config, chip, view, options))
-                ESCAPE ("Unable to defringe");
+            if (!ppImageDetrendFringeApply(config, chip, view, options)) {
+                ESCAPE("Unable to defringe");
+            }
         }
 
         // measure various statistics for this image
-        if (!ppImagePixelStats (config, options, view))
-            ESCAPE ("Unable to measures stats for image");
-
-        if (!ppImageMosaicChip(config, options, view, "PPIMAGE.CHIP", "PPIMAGE.OUTPUT"))
-            ESCAPE ("Unable to mosaic chip");
+        if (!ppImagePixelStats(config, stats, options, view)) {
+            ESCAPE("Unable to measures stats for image");
+        }
+        if (!ppImageMosaicChip(config, options, view, "PPIMAGE.CHIP", "PPIMAGE.OUTPUT")) {
+            ESCAPE("Unable to mosaic chip");
+        }
+        timeDetrend += psTimerClear(TIMER_DETREND);
+
 
         // we perform photometry on the readouts of this chip in the output
+        psTimerStart(TIMER_PHOT);
         if (options->doPhotom) {
-            if (!ppImagePhotom(config, view)) ESCAPE ("error running photometry.");
-        }
+            if (!ppImagePhotom(config, view)) {
+                ESCAPE("error running photometry.");
+            }
+        }
+        timePhot += psTimerClear(TIMER_PHOT);
 
         // replace the masked pixels with the background level
         if (options->replaceMasked) {
-            if (!ppImageReplaceBackground (config, view, options))
-                ESCAPE ("Unable to replace masked pixels with background level");
+            if (!ppImageReplaceBackground(config, view, options)) {
+                ESCAPE("Unable to replace masked pixels with background level");
+            }
         }
 
         // binning (used for display) must take place after the background is replaced, if desired
-        if (!ppImageRebinChip(config, view, options, "PPIMAGE.BIN1"))
-            ESCAPE ("Unable to bin chip (level 1).");
-
-        if (!ppImageRebinChip(config, view, options, "PPIMAGE.BIN2"))
-            ESCAPE ("Unable to bin chip (level 2).");
+        if (!ppImageRebinChip(config, view, options, "PPIMAGE.BIN1")) {
+            ESCAPE("Unable to bin chip (level 1).");
+        }
+        if (!ppImageRebinChip(config, view, options, "PPIMAGE.BIN2")) {
+            ESCAPE("Unable to bin chip (level 2).");
+        }
 
         // Close cells (XXX shouldn't pmFPAfileClose iterate down as needed?)
@@ -124,35 +145,57 @@
                 continue;
             }
-            if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) ESCAPE ("save failure for Cell");
+            if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+                ESCAPE("save failure for Cell");
+            }
         }
 
         // Close chip
-        if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) ESCAPE ("save failure for Chip");
+        if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+            ESCAPE("save failure for Chip");
+        }
     }
 
     // generate the full-scale FPA mosaic
-    if (!ppImageMosaicFPA(config, options, "PPIMAGE.OUTPUT.FPA1", "PPIMAGE.BIN1")) ESCAPE ("failure in FPA Mosaic (level 1)");
-    if (!ppImageMosaicFPA(config, options, "PPIMAGE.OUTPUT.FPA2", "PPIMAGE.BIN2")) ESCAPE ("failure in FPA Mosaic (level 2)");
+    if (!ppImageMosaicFPA(config, options, "PPIMAGE.OUTPUT.FPA1", "PPIMAGE.BIN1")) {
+        ESCAPE("failure in FPA Mosaic (level 1)");
+    }
+    if (!ppImageMosaicFPA(config, options, "PPIMAGE.OUTPUT.FPA2", "PPIMAGE.BIN2")) {
+        ESCAPE("failure in FPA Mosaic (level 2)");
+    }
 
     // we perform astrometry on all chips after sources have been detected
     // this also performs the psastro file IO
     if (options->doAstromChip || options->doAstromMosaic) {
-        if (!ppImageAstrom(config)) ESCAPE ("error running astrometry.");
+        if (!ppImageAstrom(config)) {
+            ESCAPE("error running astrometry.");
+        }
     }
 
     if (psTraceGetLevel("ppImage") >= 3) {
-        ppImageFileCheck (config);
+        ppImageFileCheck(config);
     }
 
     // Write out summary statistics
-    if (!ppImageMetadataStats (config, options)) ESCAPE ("Unable to write statistics file.");
+    if (!ppImageMetadataStats(config, stats, options)) {
+        ESCAPE("Unable to write statistics file.");
+    }
+
+    // Output and Close FPA
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        ESCAPE("save failure for FPA");
+    }
+
+    psFree(view);
 
     // Write out summary statistics
-    if (!ppImageStatsOutput (config, options)) ESCAPE ("Unable to write statistics file.");
-
-    // Output and Close FPA
-    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) ESCAPE ("save failure for FPA");
-
-    psFree(view);
+    if (options->doStats) {
+        psMetadataAddF32(stats, PS_LIST_TAIL, "DT_DET", 0, "Time spent detrending (sec)", timeDetrend);
+        psMetadataAddF32(stats, PS_LIST_TAIL, "DT_PHOT", 0, "Time spent photometering (sec)", timePhot);
+        psMetadataAddF32(stats, PS_LIST_TAIL, "DT_TOTAL", 0, "Total time (sec)", psTimerMark(TIMER_TOTAL));
+        if (!ppImageStatsOutput(config, stats, options)) {
+            ESCAPE("Unable to write statistics file.");
+        }
+    }
+
     return true;
 }
