Index: /trunk/pswarp/src/Makefile.am
===================================================================
--- /trunk/pswarp/src/Makefile.am	(revision 13660)
+++ /trunk/pswarp/src/Makefile.am	(revision 13661)
@@ -7,6 +7,5 @@
 	pswarpArguments.c		\
 	pswarpCleanup.c			\
-	pswarpDataLoad.c		\
-	pswarpDataSave.c		\
+	pswarpLoop.c			\
 	pswarpDefine.c			\
 	pswarpDefineSkycell.c		\
Index: /trunk/pswarp/src/pswarp.c
===================================================================
--- /trunk/pswarp/src/pswarp.c	(revision 13660)
+++ /trunk/pswarp/src/pswarp.c	(revision 13661)
@@ -37,12 +37,6 @@
 
     // load and warp
-    if (!pswarpDataLoad (config)) {
-        psErrorStackPrint(stderr, "error reading input data\n");
-        exit (1);
-    }
-
-    // write out result image
-    if (!pswarpDataSave (config)) {
-        psErrorStackPrint(stderr, "error writing output data\n");
+    if (!pswarpLoop(config)) {
+        psErrorStackPrint(stderr, "error warping data\n");
         exit (1);
     }
Index: /trunk/pswarp/src/pswarp.h
===================================================================
--- /trunk/pswarp/src/pswarp.h	(revision 13660)
+++ /trunk/pswarp/src/pswarp.h	(revision 13661)
@@ -14,5 +14,5 @@
 # define PSASTRO_RECIPE "PSASTRO" // Name of the recipe to use
 
-// a single pswarpMap converts coordinates from one image to a second image 
+// a single pswarpMap converts coordinates from one image to a second image
 // the linear model is only valid over a limited range of pixels
 typedef struct {
@@ -27,7 +27,7 @@
 typedef struct {
     pswarpMap ***maps;
-    int nXpts, nYpts;			// number of x,y samples in the grid
-    int nXpix, nYpix;			// x,y spacing in src image pixels of grid samples
-    int xMin,  yMin;			// coordinate of first grid sample
+    int nXpts, nYpts;                   // number of x,y samples in the grid
+    int nXpix, nYpix;                   // x,y spacing in src image pixels of grid samples
+    int xMin,  yMin;                    // coordinate of first grid sample
 } pswarpMapGrid;
 
@@ -35,6 +35,5 @@
 bool pswarpParseCamera (pmConfig *config);
 bool pswarpDefine (pmConfig *config);
-bool pswarpDataLoad (pmConfig *config);
-bool pswarpDataSave (pmConfig *config);
+bool pswarpLoop (pmConfig *config);
 void pswarpCleanup (pmConfig *config);
 bool pswarpTransformReadout (pmReadout *output, pmReadout *input, pmConfig *config);
Index: unk/pswarp/src/pswarpDataLoad.c
===================================================================
--- /trunk/pswarp/src/pswarpDataLoad.c	(revision 13660)
+++ 	(revision )
@@ -1,117 +1,0 @@
-# include "pswarp.h"
-
-// this loop loads the data from the input files and selects the
-// brighter stars for astrometry
-// at the end of this function, the complete stellar data is loaded
-// into the correct fpa structure locations (readout.analysis:PSPHOT.SOURCES)
-
-// all of the different astrometry analysis modes use the same data load loop
-bool pswarpDataLoad (pmConfig *config) {
-
-    pmChip *chip;
-    pmCell *cell;
-    pmReadout *readout;
-    pmFPAview *view;
-
-    // select the input data sources
-    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSWARP.INPUT");
-    if (!input) {
-        psError(PSWARP_ERR_CONFIG, true, "Can't find input data!\n");
-        return false;
-    }
-
-    // use the external astrometry source if supplied
-    pmFPAfile *astrom = psMetadataLookupPtr (NULL, config->files, "PSWARP.ASTROM");
-    if (!astrom) {
-        astrom = input;
-    }
-
-    // select the output readout
-    view = pmFPAviewAlloc (0);
-    view->chip = 0;
-    view->cell = 0;
-    view->readout = 0;
-    pmReadout  *output = pmFPAfileThisReadout (config->files, view, "PSWARP.OUTPUT");
-    if (!output) {
-        psError(PSWARP_ERR_CONFIG, true, "Can't find output data!\n");
-        return false;
-    }
-    psFree (view);
-
-    // de-activate PSWARP.SKYCELL and PSWARP.OUTPUT
-    pmFPAfileActivate (config->files, false, "PSWARP.SKYCELL");
-    pmFPAfileActivate (config->files, false, "PSWARP.OUTPUT");
-    pmFPAfileActivate (config->files, false, "PSWARP.OUTPUT.MASK");
-    pmFPAfileActivate (config->files, false, "PSWARP.OUTPUT.WEIGHT");
-
-    view = pmFPAviewAlloc (0);
-
-    // XXX need to read only the headers for the skycell
-    // XXX these pmAstromReadBilevel functions seem to be broken
-
-    // find the FPA phu
-    bool bilevelAstrometry = false;
-    pmHDU *phu = pmFPAviewThisPHU (view, astrom->fpa);
-    if (phu) {
-        char *ctype = psMetadataLookupStr (NULL, phu->header, "CTYPE1");
-        if (ctype) {
-            bilevelAstrometry = !strcmp (&ctype[4], "-DIS");
-        }
-    }
-    if (bilevelAstrometry) {
-        if (!pmAstromReadBilevelMosaic(input->fpa, phu->header)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to read bilevel mosaic astrometry for input FPA.");
-            psFree(view);
-            return false;
-        }
-    }
-
-    // files associated with the science image
-    pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
-
-    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);
-
-        // read WCS data from the corresponding header
-        pmHDU *hdu = pmFPAviewThisHDU (view, astrom->fpa);
-        if (bilevelAstrometry) {
-            if (!pmAstromReadBilevelChip (chip, hdu->header)) {
-                psError(PS_ERR_UNKNOWN, false, "Unable to read bilevel chip astrometry for input FPA.");
-                psFree(view);
-                return false;
-            }
-        } 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.");
-                psFree(view);
-                return false;
-            }
-        }
-
-        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);
-
-            // process each of the readouts
-            while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
-                pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
-                if (! readout->data_exists) { continue; }
-
-                // XXX _Opt version uses locally-linear map
-                // pswarpTransformReadout (output, readout, config);
-                pswarpTransformReadout_Opt (output, readout, config);
-
-                pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-            }
-            pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-        }
-        pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-    }
-    pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-    psFree (view);
-    return true;
-}
Index: unk/pswarp/src/pswarpDataSave.c
===================================================================
--- /trunk/pswarp/src/pswarpDataSave.c	(revision 13660)
+++ 	(revision )
@@ -1,125 +1,0 @@
-#include <ppStats.h>
-#include "pswarp.h"
-
-// this loop loads the data from the input files and selects the
-// brighter stars for astrometry
-// at the end of this function, the complete stellar data is loaded
-// into the correct fpa structure locations (readout.analysis:PSPHOT.SOURCES)
-
-// all of the different astrometry analysis modes use the same data load loop
-bool pswarpDataSave(pmConfig *config) {
-
-    pmChip *chip;
-    pmCell *cell;
-    pmReadout *readout;
-
-    // select the input data sources
-    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSWARP.INPUT");
-    if (!input) {
-        psError(PSWARP_ERR_CONFIG, true, "Can't find input data!\n");
-        return false;
-    }
-
-    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);
-        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();
-    }
-
-    // de-activate all files except PSWARP.OUTPUT
-    pmFPAfileActivate (config->files, false, NULL);
-    pmFPAfileActivate (config->files, true, "PSWARP.OUTPUT");
-    pmFPAfileActivate (config->files, true, "PSWARP.OUTPUT.MASK");
-    pmFPAfileActivate (config->files, true, "PSWARP.OUTPUT.WEIGHT");
-    pmFPAview *view = pmFPAviewAlloc (0);
-
-    // files associated with the science image
-    pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
-
-    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);
-
-        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);
-
-            // Perform statistics on the cell
-            if (stats) {
-                bool mdok;              // Status of MD lookup
-                pmFPAfile *output = psMetadataLookupPtr(&mdok, config->files, "PSWARP.OUTPUT");
-                if (!mdok || !output) {
-                    psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find file PSWARP.OUTPUT.\n");
-                    psFree(view);
-                    psFree(stats);
-                    return false;
-                }
-                ppStats(stats, output->fpa, view, config);
-            }
-
-            pmHDU *hdu = pmHDUFromCell(cell); // HDU that owns the cell
-
-            // Process readouts
-            while ((readout = pmFPAviewNextReadout(view, input->fpa, 1)) != NULL) {
-                pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
-                if (!readout->data_exists) {
-                    continue;
-                }
-
-                // pswarpConvertReadout (readout, config);
-
-                // Add MD5 information for readout
-                const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME");
-                const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME");
-                psString headerName = NULL; // Header name for MD5
-                psStringAppend(&headerName, "MD5_%s_%s_%d", chipName, cellName, view->readout);
-                psVector *md5 = psImageMD5(readout->image); // md5 hash
-                psString md5string = psMD5toString(md5); // String
-                psFree(md5);
-                psMetadataAddStr(hdu->header, PS_LIST_TAIL, headerName, PS_META_REPLACE,
-                                 "Image MD5", md5string);
-                psFree(md5string);
-                psFree(headerName);
-
-                pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-            }
-            pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-        }
-        pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-    }
-    pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
-    psFree (view);
-
-    // re-activate all pmFPAfiles
-    pmFPAfileActivate (config->files, true, NULL);
-
-    // Write out summary statistics
-    if (stats) {
-        const char *statsMDC = psMetadataConfigFormat(stats);
-        if (!statsMDC || strlen(statsMDC) == 0) {
-            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);
-
-        psFree(stats);
-    }
-
-    return true;
-}
Index: /trunk/pswarp/src/pswarpLoop.c
===================================================================
--- /trunk/pswarp/src/pswarpLoop.c	(revision 13661)
+++ /trunk/pswarp/src/pswarpLoop.c	(revision 13661)
@@ -0,0 +1,164 @@
+# include "pswarp.h"
+#include <ppStats.h>
+
+// Loop over the inputs, warp them to the output skycell and then write out the output.
+bool pswarpLoop(pmConfig *config)
+{
+
+    psMaskType maskPoor = psMetadataLookupU8(NULL, config->arguments, "MASK.POOR"); // Mask for "poor" data
+    psMaskType maskBad = psMetadataLookupU8(NULL, config->arguments, "MASK.BAD"); // Mask for bad data
+
+    // select the input data sources
+    pmFPAfile *input = psMetadataLookupPtr(NULL, config->files, "PSWARP.INPUT");
+    if (!input) {
+        psError(PSWARP_ERR_CONFIG, true, "Can't find input data!\n");
+        return false;
+    }
+
+    // use the external astrometry source if supplied
+    pmFPAfile *astrom = psMetadataLookupPtr(NULL, config->files, "PSWARP.ASTROM");
+    if (!astrom) {
+        astrom = input;
+    }
+
+    // select the output readout
+    pmFPAview *view = pmFPAviewAlloc(0);
+    view->chip = 0;
+    view->cell = 0;
+    view->readout = 0;
+    pmReadout *output = pmFPAfileThisReadout(config->files, view, "PSWARP.OUTPUT");
+    if (!output) {
+        psError(PSWARP_ERR_CONFIG, true, "Can't find output data!\n");
+        return false;
+    }
+    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);
+        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();
+    }
+
+    // de-activate PSWARP.SKYCELL and PSWARP.OUTPUT
+    pmFPAfileActivate(config->files, false, "PSWARP.SKYCELL");
+
+    view = pmFPAviewAlloc(0);
+
+    // find the FPA phu
+    bool bilevelAstrometry = false;
+    pmHDU *phu = pmFPAviewThisPHU (view, astrom->fpa);
+    if (phu) {
+        char *ctype = psMetadataLookupStr (NULL, phu->header, "CTYPE1");
+        if (ctype) {
+            bilevelAstrometry = !strcmp (&ctype[4], "-DIS");
+        }
+    }
+    if (bilevelAstrometry) {
+        if (!pmAstromReadBilevelMosaic(input->fpa, phu->header)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to read bilevel mosaic astrometry for input FPA.");
+            psFree(view);
+            return false;
+        }
+    }
+
+    // files associated with the science image
+    pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
+
+    pmChip *chip;
+    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);
+
+        // read WCS data from the corresponding header
+        pmHDU *hdu = pmFPAviewThisHDU (view, astrom->fpa);
+        if (bilevelAstrometry) {
+            if (!pmAstromReadBilevelChip (chip, hdu->header)) {
+                psError(PS_ERR_UNKNOWN, false, "Unable to read bilevel chip astrometry for input FPA.");
+                psFree(view);
+                return false;
+            }
+        } 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.");
+                psFree(view);
+                return false;
+            }
+        }
+
+        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);
+
+            // process each of the readouts
+            pmReadout *readout;
+            while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
+                pmFPAfileIOChecks (config, view, PM_FPA_BEFORE);
+                if (! readout->data_exists) { continue; }
+
+                // XXX _Opt version uses locally-linear map
+                // pswarpTransformReadout (output, readout, config);
+                pswarpTransformReadout_Opt (output, readout, config);
+
+                pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
+            }
+
+            pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
+        }
+        pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
+    }
+
+    // Perform statistics on the output image
+    if (stats) {
+        ppStats(stats, output->parent->parent->parent, view, maskBad | maskPoor, config);
+    }
+
+    pmHDU *hdu = output->parent->parent->parent->hdu; // HDU for the output warped image
+
+    // Add MD5 information for readout
+    const char *chipName = psMetadataLookupStr(NULL, output->parent->parent->concepts, "CHIP.NAME");
+    const char *cellName = psMetadataLookupStr(NULL, output->parent->concepts, "CELL.NAME");
+    psString headerName = NULL; // Header name for MD5
+    psStringAppend(&headerName, "MD5_%s_%s_%d", chipName, cellName, view->readout);
+    psVector *md5 = psImageMD5(output->image); // md5 hash
+    psString md5string = psMD5toString(md5); // String
+    psFree(md5);
+    psMetadataAddStr(hdu->header, PS_LIST_TAIL, headerName, PS_META_REPLACE,
+                     "Image MD5", md5string);
+    psFree(md5string);
+    psFree(headerName);
+
+    pmFPAfileIOChecks (config, view, PM_FPA_AFTER);
+    psFree (view);
+
+    // Write out summary statistics
+    if (stats) {
+        const char *statsMDC = psMetadataConfigFormat(stats);
+        if (!statsMDC || strlen(statsMDC) == 0) {
+            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);
+
+        psFree(stats);
+    }
+
+    return true;
+}
