Index: branches/tap_branches/pswarp/src/pswarpLoop.c
===================================================================
--- branches/tap_branches/pswarp/src/pswarpLoop.c	(revision 25900)
+++ branches/tap_branches/pswarp/src/pswarpLoop.c	(revision 27838)
@@ -19,75 +19,25 @@
 
 
-// XXX these are generic functions which should be moved to psModules
-// Activate a list of files
-static void fileActivation(pmConfig *config, // Configuration
-                           char **files, // Files to turn on/off
-                           bool state   // Activation state
-    )
-{
-    for (int i = 0; files[i] != NULL; i++) {
-        pmFPAfileActivate(config->files, state, files[i]);
-    }
-    return;
-}
-
-/**
- * Run down the FPA hierarchy, checking files
- */
-static bool ioChecksBefore(pmConfig *config ///< Configuration
-                           )
-{
-    pmFPAview *view = pmFPAviewAlloc(0); ///< View for checking
-    bool status = true;                 ///< Status of checks
-    status &= pmFPAfileIOChecks(config, view, PM_FPA_BEFORE);
-    view->chip = 0;
-    status &= pmFPAfileIOChecks(config, view, PM_FPA_BEFORE);
-    view->cell = 0;
-    status &= pmFPAfileIOChecks(config, view, PM_FPA_BEFORE);
-    psFree(view);
-    return status;
-}
-
-/**
- * Run up the FPA hierarchy, checking files
- */
-static bool ioChecksAfter(pmConfig *config ///< Configuration
-                          )
-{
-    pmFPAview *view = pmFPAviewAlloc(0); ///< View for checking
-    view->chip = view->cell = 0;
-    bool status = true;                 ///< Status of checks
-    status &= pmFPAfileIOChecks(config, view, PM_FPA_AFTER);
-    view->cell = -1;
-    status &= pmFPAfileIOChecks(config, view, PM_FPA_AFTER);
-    view->chip = -1;
-    status &= pmFPAfileIOChecks(config, view, PM_FPA_AFTER);
-    psFree(view);
-    return status;
-}
-
-
-/**
- * Loop over the inputs, warp them to the output skycell and then write out the output.
- */
-bool pswarpLoop(pmConfig *config)
+
+// Loop over the inputs, warp them to the output skycell and then write out the output.
+bool pswarpLoop(pmConfig *config, psMetadata *stats)
 {
     bool status;
+    bool mdok;                          // Status of MD lookup
 
     const char *skyCamera = psMetadataLookupStr(NULL, config->arguments,
-                                                "SKYCELL.CAMERA");  ///< Name of camera for skycell
+                                                "SKYCELL.CAMERA");  // Name of camera for skycell
     pmConfigCamerasCull(config, skyCamera);
     pmConfigRecipesCull(config, "PSWARP,PPSTATS,PSPHOT,PSASTRO,MASKS,JPEG");
-
 
     // load the recipe
     psMetadata *recipe = psMetadataLookupPtr (&status, config->recipes, PSWARP_RECIPE);
     if (!recipe) {
-        psError(PSPHOT_ERR_CONFIG, false, "missing recipe %s", PSWARP_RECIPE);
+        psError(PSWARP_ERR_CONFIG, false, "missing recipe %s", PSWARP_RECIPE);
         return false;
     }
 
     if (!pswarpSetMaskBits(config)) {
-        psError(PS_ERR_IO, false, "failed to set mask bits");
+        psError(psErrorCodeLast(), false, "failed to set mask bits");
         return NULL;
     }
@@ -111,5 +61,5 @@
 
     if (astrom->camera != input->camera) {
-        psError(PS_ERR_UNKNOWN, true, "Input camera and astrometry camera do not match.");
+        psError(PSWARP_ERR_DATA, true, "Input camera and astrometry camera do not match.");
         return false;
     }
@@ -127,30 +77,17 @@
     psFree (view);
 
-    bool mdok;                          ///< Status of MD lookup
-    const char *statsName = psMetadataLookupStr(&mdok, config->arguments, "STATS"); ///< Filename for statistics
-    psMetadata *stats = NULL;           ///< Container for statistics
-    FILE *statsFile = NULL;             ///< File stream for statistics
-    if (mdok && statsName && strlen(statsName) > 0) {
-        psString resolved = pmConfigConvertFilename(statsName, config, true, true);
-        statsFile = fopen(resolved, "w");
-        if (!statsFile) {
-            psError(PS_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
-            psFree(resolved);
-            return false;
-        }
-        psFree(resolved);
-        stats = psMetadataAlloc();
-        psMetadataAddS32(stats, PS_LIST_TAIL, "QUALITY", 0, "No problems", 0);
-    }
 
     // Turn all skycell files on to generate them, and then turn them off for the loop over the input images
     // the input, which is in a different format.
     {
-        fileActivation(config, detectorFiles, false);
-        fileActivation(config, photFiles, false);
-        fileActivation(config, independentFiles, false);
-        fileActivation(config, skycellFiles, true);
-        ioChecksBefore(config);
-        fileActivation(config, skycellFiles, false);
+        pswarpFileActivation(config, detectorFiles, false);
+        pswarpFileActivation(config, photFiles, false);
+        pswarpFileActivation(config, independentFiles, false);
+        pswarpFileActivation(config, skycellFiles, true);
+        if (!pswarpIOChecksBefore(config)) {
+            psError(psErrorCodeLast(), false, "Unable to read files.");
+            goto DONE;
+        }
+        pswarpFileActivation(config, skycellFiles, false);
     }
 
@@ -162,22 +99,37 @@
         pmChip *chip;
         pmFPAview *view = pmFPAviewAlloc(0);
-        pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
+        if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+            psError(psErrorCodeLast(), false, "Unable to read files.");
+            goto DONE;
+        }
         while ((chip = pmFPAviewNextChip (view, input->fpa, 1)) != NULL) {
             psTrace ("pswarp", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
             if (!chip->process || !chip->file_exists) { continue; }
-            pmFPAfileIOChecks(config, view, PM_FPA_BEFORE);
+            if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                psError(psErrorCodeLast(), false, "Unable to read files.");
+                goto DONE;
+            }
             pmCell *cell;
             while ((cell = pmFPAviewNextCell (view, input->fpa, 1)) != NULL) {
                 psTrace ("pswarp", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
                 if (!cell->process || !cell->file_exists) { continue; }
-                pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
-                pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-            }
-            pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-        }
-        pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-        psFree(view);
-
-        fileActivation(config, detectorFiles, true);
+                if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE) ||
+                    !pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
+                    psError(psErrorCodeLast(), false, "Unable to read files.");
+                    goto DONE;
+                }
+            }
+            if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
+                psError(psErrorCodeLast(), false, "Unable to write files.");
+                goto DONE;
+            }
+        }
+        if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) {
+            psError(psErrorCodeLast(), false, "Unable to write files.");
+            goto DONE;
+        }
+        psFree(view);
+
+        pswarpFileActivation(config, detectorFiles, true);
         pmFPAfileActivate(config->files, false, "PSWARP.ASTROM");
     }
@@ -201,8 +153,8 @@
     if (bilevelAstrometry) {
         if (!pmAstromReadBilevelMosaic(input->fpa, phu->header)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to read bilevel mosaic astrometry for input FPA.");
+            psError(psErrorCodeLast(), false, "Unable to read bilevel mosaic astrometry for input FPA.");
             psFree(view);
             psFree(stats);
-            return false;
+            goto DONE;
         }
     }
@@ -211,5 +163,8 @@
 
     // files associated with the science image
-    pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
+    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) {
+        psError(psErrorCodeLast(), false, "Unable to read files.");
+        goto DONE;
+    }
 
     pmChip *chip;
@@ -217,5 +172,8 @@
         psTrace ("pswarp", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
         if (!chip->process || !chip->file_exists) { continue; }
-        pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
+        if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) {
+            psError(psErrorCodeLast(), false, "Unable to read files.");
+            goto DONE;
+        }
 
         // read WCS data from the corresponding header
@@ -223,16 +181,16 @@
         if (bilevelAstrometry) {
             if (!pmAstromReadBilevelChip (chip, hdu->header)) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to read bilevel chip astrometry for input FPA.");
+                psError(psErrorCodeLast(), false, "Unable to read bilevel chip astrometry for input FPA.");
                 psFree(view);
                 psFree(stats);
-                return false;
+                goto DONE;
             }
         } else {
             // we use a default FPA pixel scale of 1.0
             if (!pmAstromReadWCS (input->fpa, chip, hdu->header, 1.0)) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to read WCS astrometry for input FPA.");
+                psError(psErrorCodeLast(), false, "Unable to read WCS astrometry for input FPA.");
                 psFree(view);
                 psFree(stats);
-                return false;
+                goto DONE;
             }
         }
@@ -242,5 +200,8 @@
             psTrace ("pswarp", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
             if (!cell->process || !cell->file_exists) { continue; }
-            pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
+            if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) {
+                psError(psErrorCodeLast(), false, "Unable to read files.");
+                goto DONE;
+            }
 
             psListAdd(cells, PS_LIST_TAIL, cell);
@@ -249,26 +210,36 @@
             pmReadout *readout;
             while ((readout = pmFPAviewNextReadout(view, input->fpa, 1)) != NULL) {
-                pmFPAfileIOChecks(config, view, PM_FPA_BEFORE);
+                if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+                    psError(psErrorCodeLast(), false, "Unable to read files.");
+                    goto DONE;
+                }
                 if (!readout->data_exists) {
                     continue;
                 }
 
-                // Copy the sources from the astrometry carrier to the input, so they can be accessed by
+                // Copy the detections from the astrometry carrier to the input, so they can be accessed by
                 // pswarpTransformReadout
                 pmReadout *astromRO = pmFPAviewThisReadout(view, astrom->fpa); // Readout for astrometry
-                psArray *sources = psMetadataLookupPtr(&mdok, astromRO->analysis,
-                                                       "PSPHOT.SOURCES"); // Sources from astrometry
-                if (sources) {
-                    psMetadataAddPtr(readout->analysis, PS_LIST_TAIL, "PSPHOT.SOURCES", PS_DATA_ARRAY,
-                                     "Sources from input astrometry", sources);
+                pmDetections *detections = psMetadataLookupPtr(&mdok, astromRO->analysis, "PSPHOT.DETECTIONS"); // Sources from astrometry
+                if (detections) {
+                    psMetadataAddPtr(readout->analysis, PS_LIST_TAIL, "PSPHOT.DETECTIONS", PS_DATA_ARRAY, "Sources from input astrometry", detections);
                 }
 
                 pswarpTransformReadout(output, readout, config);
 
-                pmFPAfileIOChecks(config, view, PM_FPA_AFTER);
-            }
-            pmFPAfileIOChecks(config, view, PM_FPA_AFTER);
-        }
-        pmFPAfileIOChecks(config, view, PM_FPA_AFTER);
+                if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+                    psError(psErrorCodeLast(), false, "Unable to write files.");
+                    goto DONE;
+                }
+            }
+            if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+                psError(psErrorCodeLast(), false, "Unable to write files.");
+                goto DONE;
+            }
+        }
+        if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+            psError(psErrorCodeLast(), false, "Unable to write files.");
+            goto DONE;
+        }
     }
 
@@ -290,8 +261,8 @@
 
     if (!pswarpPixelsLit(output, stats, config)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to calculate pixel regions.");
+        psError(psErrorCodeLast(), false, "Unable to calculate pixel regions.");
         psFree(cells);
         psFree(view);
-        return false;
+        goto DONE;
     }
 
@@ -327,9 +298,9 @@
 
     if (!pmConceptsAverageCells(outCell, cells, NULL, NULL, false)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to average cell concepts.");
+        psError(psErrorCodeLast(), false, "Unable to average cell concepts.");
         psFree(stats);
         psFree(cells);
         psFree(view);
-        return false;
+        goto DONE;
     }
     psFree(cells);
@@ -339,8 +310,14 @@
 
     if (!psMetadataCopy(outFPA->concepts, input->fpa->concepts)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to copy FPA concepts from input to output.");
+        psError(psErrorCodeLast(), false, "Unable to copy FPA concepts from input to output.");
         psFree(stats);
         psFree(view);
-        return false;
+        goto DONE;
+    }
+
+    // Update ZP from the astrometry
+    {
+        psMetadataItem *item = psMetadataLookup(outFPA->concepts, "FPA.ZP");
+        item->data.F32 = psMetadataLookupF32(NULL, astrom->fpa->concepts, "FPA.ZP");
     }
 
@@ -355,7 +332,7 @@
         pmHDU *skyHDU = pmHDUFromCell(cell); ///< HDU
         if (!skyHDU) {
-            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find skycell HDU.");
+            psError(PSWARP_ERR_DATA, false, "Unable to find skycell HDU.");
             psFree(view);
-            return false;
+            goto DONE;
         }
         hdu->header = psMetadataCopy(hdu->header, skyHDU->header);
@@ -365,14 +342,17 @@
 
     if (!pmAstromWriteWCS(hdu->header, outFPA, outChip, WCS_NONLIN_TOL)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to generate WCS header.");
+        psError(psErrorCodeLast(), false, "Unable to generate WCS header.");
         psFree(stats);
-        return false;
-    }
-
-    pmFPAfileIOChecks(config, view, PM_FPA_AFTER);
+        goto DONE;
+    }
+
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        psError(psErrorCodeLast(), false, "Unable to write files.");
+        goto DONE;
+    }
 
     // Done with the detector side of things
-    fileActivation(config, detectorFiles, false);
-    fileActivation(config, independentFiles, false);
+    pswarpFileActivation(config, detectorFiles, false);
+    pswarpFileActivation(config, independentFiles, false);
 
     // We need a new PSF model for the warped frame.  It would be good to generate this analytically, but
@@ -380,6 +360,9 @@
 
     if (psMetadataLookupBool(&mdok, recipe, "PSF")) {
-        fileActivation(config, photFiles, true);
-        ioChecksBefore(config);
+        pswarpFileActivation(config, photFiles, true);
+        if (!pswarpIOChecksBefore(config)) {
+            psError(psErrorCodeLast(), false, "Unable to read files.");
+            goto DONE;
+        }
 
         // supply the readout and fpa of interest to psphot
@@ -393,6 +376,6 @@
         psArray *sources = psphotLoadPSFSources (config, view);
         if (!sources) {
-            psError(PS_ERR_UNKNOWN, false, "No sources supplied to measure PSF");
-            return false;
+            psError(psErrorCodeLast(), false, "No sources supplied to measure PSF");
+            goto DONE;
         }
 
@@ -412,4 +395,9 @@
             psphotFilesActivate(config, false);
         }
+
+        // Ensure seeing is carried over
+        pmChip *photChip = pmFPAviewThisChip(view, photFile->fpa);                 // Chip with seeing
+        psMetadataItem *item = psMetadataLookup(outChip->concepts, "CHIP.SEEING"); // Concept with seeing
+        item->data.F32 = psMetadataLookupF32(NULL, photChip->concepts, "CHIP.SEEING");
 
 // XXX EAM : put this in a visualization function
@@ -435,6 +423,4 @@
     }
 
-    fileActivation(config, skycellFiles, true);
-
     // Perform statistics on the output image
     if (stats) {
@@ -458,39 +444,5 @@
     psFree(view);
 
-    // Ensure everything is written out, at every level
-    ioChecksAfter(config);
-
-    // Now done with the skycell side of things
-
  DONE:
-
-    // Write out summary statistics
-    if (stats) {
-        psMetadataAddF32(stats, PS_LIST_TAIL, "DT_WARP", 0, "Time for warp completion",
-                         psTimerMark("pswarp"));
-
-        const char *statsMDC = psMetadataConfigFormat(stats);
-        if (!statsMDC) {
-            psError(PS_ERR_IO, false, "Unable to get statistics MDC file.\n");
-            psFree(stats);
-            fclose(statsFile);
-            return false;
-        }
-        fprintf(statsFile, "%s", statsMDC);
-        psFree((void*)statsMDC);
-        fclose(statsFile);
-        pmConfigRunFilenameAddWrite(config, "STATS", statsName);
-
-        psFree(stats);
-    }
-
-    // Dump configuration
-    psString dump_file = psMetadataLookupStr(&status, config->arguments, "DUMP_CONFIG");
-    if (dump_file) {
-        if (!pmConfigDump(config, dump_file)) {
-            psError(PS_ERR_IO, false, "Unable to dump configuration");
-            return false;
-        }
-    }
 
     return true;
