Index: trunk/ppBackground/configure.ac
===================================================================
--- trunk/ppBackground/configure.ac	(revision 28276)
+++ trunk/ppBackground/configure.ac	(revision 28280)
@@ -20,5 +20,10 @@
 PKG_CHECK_MODULES([PSLIB], [pslib >= 1.0.0])
 PKG_CHECK_MODULES([PSMODULE], [psmodules >= 1.0.0])
-PKG_CHECK_MODULES([PSPHOT], [psphot >= 1.0.0])
+PKG_CHECK_MODULES([PSPHOT], [psphot])
+
+AC_PATH_PROG([ERRORCODES], [psParseErrorCodes], [missing])
+if test "$ERRORCODES" = "missing" ; then
+  AC_MSG_ERROR([psParseErrorCodes is required])
+fi
 
 dnl Set CFLAGS for build
Index: trunk/ppBackground/src/Makefile.am
===================================================================
--- trunk/ppBackground/src/Makefile.am	(revision 28276)
+++ trunk/ppBackground/src/Makefile.am	(revision 28280)
@@ -2,15 +2,15 @@
 
 if HAVE_SVNVERSION
-PPVIZPATTERN_VERSION=`$(SVNVERSION) ..`
+PPBACKGROUND_VERSION=`$(SVNVERSION) ..`
 else
-PPVIZPATTERN_VERSION="UNKNOWN"
+PPBACKGROUND_VERSION="UNKNOWN"
 endif
 
 if HAVE_SVN
-PPVIZPATTERN_BRANCH=`$(SVN) info .. | $(SED) -n -e '/URL:/ h' -e '/Repository Root:/ { x; H; x; s|Repository Root: \(.*\)\nURL: \1\(.*\)|\2| ; s|^/|| ; s|/[a-zA-Z]*/src.*|| ; p }'`
-PPVIZPATTERN_SOURCE=`$(SVN) info | $(SED) -n -e 's/Repository UUID: // p'`
+PPBACKGROUND_BRANCH=`$(SVN) info .. | $(SED) -n -e '/URL:/ h' -e '/Repository Root:/ { x; H; x; s|Repository Root: \(.*\)\nURL: \1\(.*\)|\2| ; s|^/|| ; s|/[a-zA-Z]*/src.*|| ; p }'`
+PPBACKGROUND_SOURCE=`$(SVN) info | $(SED) -n -e 's/Repository UUID: // p'`
 else
-PPVIZPATTERN_BRANCH="UNKNOWN"
-PPVIZPATTERN_SOURCE="UNKNOWN"
+PPBACKGROUND_BRANCH="UNKNOWN"
+PPBACKGROUND_SOURCE="UNKNOWN"
 endif
 
@@ -19,5 +19,5 @@
 ppBackgroundVersionDefinitions.h: ppBackgroundVersionDefinitions.h.in FORCE
 	-$(RM) ppBackgroundVersionDefinitions.h
-	$(SED) -e "s|@PPVIZPATTERN_VERSION@|\"$(PPVIZPATTERN_VERSION)\"|" -e "s|@PPVIZPATTERN_BRANCH@|\"$(PPVIZPATTERN_BRANCH)\"|" -e "s|@PPVIZPATTERN_SOURCE@|\"$(PPVIZPATTERN_SOURCE)\"|" ppBackgroundVersionDefinitions.h.in > ppBackgroundVersionDefinitions.h
+	$(SED) -e "s|@PPBACKGROUND_VERSION@|\"$(PPBACKGROUND_VERSION)\"|" -e "s|@PPBACKGROUND_BRANCH@|\"$(PPBACKGROUND_BRANCH)\"|" -e "s|@PPBACKGROUND_SOURCE@|\"$(PPBACKGROUND_SOURCE)\"|" ppBackgroundVersionDefinitions.h.in > ppBackgroundVersionDefinitions.h
 FORCE: ;
 
@@ -35,6 +35,7 @@
 	ppBackgroundLoop.c	\
 	ppBackgroundVersion.c   \
-	ppBackgroundModel.c	\
-	ppBackgroundErrorCodes.c
+	ppBackgroundRestore.c	\
+	ppBackgroundErrorCodes.c	\
+	ppBackgroundExit.c
 
 noinst_HEADERS = \
Index: trunk/ppBackground/src/ppBackground.c
===================================================================
--- trunk/ppBackground/src/ppBackground.c	(revision 28276)
+++ trunk/ppBackground/src/ppBackground.c	(revision 28280)
@@ -6,4 +6,5 @@
 #include <pslib.h>
 #include <psmodules.h>
+#include <psphot.h>
 
 #include "ppBackground.h"
@@ -12,4 +13,8 @@
 {
     ppBackgroundVersionPrint();
+
+    pmErrorRegister();
+    psphotErrorRegister();
+    ppBackgroundErrorRegister();
 
     ppBackgroundData *data = ppBackgroundDataInit(&argc, argv);
@@ -46,5 +51,4 @@
         }
         data->statsFile = NULL;
-        pmConfigRunFilenameAddWrite(data->config, "STATS", data->statsName);
         exitValue = ppBackgroundExitCode(exitValue);
     }
Index: trunk/ppBackground/src/ppBackground.h
===================================================================
--- trunk/ppBackground/src/ppBackground.h	(revision 28276)
+++ trunk/ppBackground/src/ppBackground.h	(revision 28280)
@@ -5,5 +5,5 @@
 #include <psmodules.h>
 
-#include <ppBackgroundErrorCodes.h>
+#include "ppBackgroundErrorCodes.h"
 
 #define PPBACKGROUND_RECIPE "PPBACKGROUND"      // Recipe name
@@ -37,4 +37,13 @@
     );
 
+/// Restore the background to an image
+bool ppBackgroundRestore(
+    pmChip *chip,                       // Input chip
+    const pmChip *background,           // Chip with background model
+    const pmChip *pattern,              // Chip with pattern
+    const pmFPAview *view,              // View to data
+    pmConfig *config                    // Configuration
+    );
+
 /// Determine exit code
 psExit ppBackgroundExitCode(
Index: trunk/ppBackground/src/ppBackgroundArguments.c
===================================================================
--- trunk/ppBackground/src/ppBackgroundArguments.c	(revision 28276)
+++ trunk/ppBackground/src/ppBackgroundArguments.c	(revision 28280)
@@ -48,6 +48,7 @@
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-pattern", 0, "Filename of pattern correction", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-background", 0, "Filename of background model", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-image", 0, "Filename of image", NULL);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-image", 0, "Filename of image (required)", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-mask", 0, "Filename of mask", NULL);
+    psMetadataAddStr(arguments, PS_LIST_TAIL, "-stats", 0, "Output statistics file", NULL);
     if (argc == 1 || !psArgumentParse(arguments, &argc, argv) || argc != 2) {
         usage(argv[0], arguments, data);
@@ -68,6 +69,21 @@
         return false;
     }
+    if (!data->imageName) {
+        psError(PPBACKGROUND_ERR_CONFIG, true, "Must specify -image");
+        return false;
+    }
 
     PS_ASSERT_STRING_NON_EMPTY(data->outRoot, false);
+
+    const char *statsName = psMetadataLookupStr(NULL, arguments, "-stats");
+    if (statsName) {
+        data->statsFile = fopen(statsName, "w");
+        if (!data->statsFile) {
+            psError(PPBACKGROUND_ERR_IO, true, "Unable to open statistics file %s", statsName);
+            return false;
+        }
+        data->stats = psMetadataAlloc();
+        pmConfigRunFilenameAddWrite(data->config, "STATS", statsName);
+    }
 
     return true;
Index: trunk/ppBackground/src/ppBackgroundCamera.c
===================================================================
--- trunk/ppBackground/src/ppBackgroundCamera.c	(revision 28276)
+++ trunk/ppBackground/src/ppBackgroundCamera.c	(revision 28280)
@@ -33,6 +33,5 @@
 
     fileArguments("PATTERN", data->patternName, "Input pattern", data->config);
-    pmFPAfile *pattern = pmFPAfileDefineFromArgs(&status, data->config, "PPBACKGROUND.PATTERN",
-                                                 "PATTERN"); // File
+    pmFPAfileDefineFromArgs(&status, data->config, "PPBACKGROUND.PATTERN", "PATTERN"); // File
     if (!status) {
         psError(psErrorCodeLast(), false, "Failed to build file from PPBACKGROUND.PATTERN");
@@ -41,6 +40,5 @@
 
     fileArguments("BACKGROUND", data->backgroundName, "Input background model", data->config);
-    pmFPAfile *background = pmFPAfileBindFromArgs(&status, data->config, "PPBACKGROUND.BACKGROUND",
-                                                  "BACKGROUND"); // File
+    pmFPAfileDefineFromArgs(&status, data->config, "PPBACKGROUND.BACKGROUND", "BACKGROUND"); // File
     if (!status) {
         psError(psErrorCodeLast(), false, "Failed to build file from PPBACKGROUND.BACKGROUND");
@@ -49,7 +47,7 @@
 
     fileArguments("IMAGE", data->backgroundName, "Input uncorrected image", data->config);
-    pmFPAfile *image = pmFPAfileBindFromArgs(&status, background, data->config, "PPBACKGROUND.IMAGE",
-                                             "IMAGE"); // File
-    if (!status) {
+    pmFPAfile *image = pmFPAfileDefineFromArgs(&status, data->config, "PPBACKGROUND.IMAGE",
+                                               "IMAGE"); // File
+    if (!status || !image) {
         psError(psErrorCodeLast(), false, "Failed to build file from PPBACKGROUND.IMAGE");
         return false;
@@ -57,6 +55,5 @@
 
     fileArguments("MASK", data->backgroundName, "Input uncorrected mask", data->config);
-    pmFPAfile *mask = pmFPAfileBindFromArgs(&status, image, data->config, "PPBACKGROUND.MASK",
-                                              "MASK"); // File
+    pmFPAfileBindFromArgs(&status, image, data->config, "PPBACKGROUND.MASK", "MASK"); // File
     if (!status) {
         psError(psErrorCodeLast(), false, "Failed to build file from PPBACKGROUND.MASK");
@@ -64,5 +61,5 @@
     }
 
-    pmFPAfile *output = pmFPAfileDefineOutput(data->config, file->fpa, "PPBACKGROUND.OUTPUT");
+    pmFPAfile *output = pmFPAfileDefineOutput(data->config, image->fpa, "PPBACKGROUND.OUTPUT");
     if (!output) {
         psError(psErrorCodeLast(), false, "Unable to define output.");
Index: trunk/ppBackground/src/ppBackgroundLoop.c
===================================================================
--- trunk/ppBackground/src/ppBackgroundLoop.c	(revision 28276)
+++ trunk/ppBackground/src/ppBackgroundLoop.c	(revision 28280)
@@ -13,6 +13,7 @@
 {
     pmConfig *config = data->config;                                        // Configuration data
-    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPBACKGROUND.BACKGROUND", 0);
+    pmFPAfile *file = pmFPAfileSelectSingle(config->files, "PPBACKGROUND.IMAGE", 0);
     pmFPAfile *patternFile = pmFPAfileSelectSingle(config->files, "PPBACKGROUND.PATTERN", 0); // File with data
+    pmFPAfile *bgFile = pmFPAfileSelectSingle(config->files, "PPBACKGROUND.BACKGROUND", 0);   // File with bg
     pmFPA *patternMosaic = pmFPAConstruct(file->camera, file->cameraName); // Mosaicked FPA for pattern
 
@@ -34,5 +35,5 @@
         }
 
-        if (chip->cell->n > 1) {
+        if (chip->cells->n > 1) {
             psError(PPBACKGROUND_ERR_CONFIG, true,
                     "Input image and background model should be chip-mosaicked");
@@ -44,7 +45,7 @@
             pmFPAfileActivate(config->files, true, "PPBACKGROUND.PATTERN");
 
-            pmCell *cell;               // Cell with pattern data
+            pmCell *patternCell;               // Cell with pattern data
             while ((patternCell = pmFPAviewNextCell(view, patternFile->fpa, 1))) {
-                if (!cell->process || !cell->file_exists) {
+                if (!patternCell->process || !patternCell->file_exists) {
                     continue;
                 }
@@ -68,10 +69,10 @@
                     // Get size of image from concepts
                     if (numCols == 0 || numRows == 0) {
-                        numCols = psMetadataLookupS32(NULL, cell->concepts, "CELL.XSIZE");
-                        numRows = psMetadataLookupS32(NULL, cell->concepts, "CELL.YSIZE");
+                        numCols = psMetadataLookupS32(NULL, patternCell->concepts, "CELL.XSIZE");
+                        numRows = psMetadataLookupS32(NULL, patternCell->concepts, "CELL.YSIZE");
                     }
                     // Get size of image from TRIMSEC
                     if (numCols == 0 || numRows == 0) {
-                        psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC");
+                        psRegion *trimsec = psMetadataLookupPtr(NULL, patternCell->concepts, "CELL.TRIMSEC");
                         numCols = trimsec->x1 - trimsec->x0;
                         numRows = trimsec->y1 - trimsec->y0;
@@ -91,5 +92,5 @@
 
                     // Remove bias sections to avoid warnings
-                    psMetadataItem *biassec = psMetadataLookup(patternRO->parent->concepts, "CELL.BIASSEC");
+                    psMetadataItem *biassec = psMetadataLookup(patternCell->concepts, "CELL.BIASSEC");
                     if (psListLength(biassec->data.V)) {
                         psFree(biassec->data.V);
@@ -123,26 +124,21 @@
         }
 
+        pmChip *patternChip = patternFile ? pmFPAviewThisChip(view, patternMosaic) : NULL; // Chip with pattern
+        pmChip *bgChip = bgFile ? pmFPAviewThisChip(view, bgFile->fpa) : NULL; // Chip with background model
+        if (!ppBackgroundRestore(chip, bgChip, patternChip, view, config)) {
+            psError(psErrorCodeLast(), false, "Unable to replace background");
+            return false;
+        }
+        pmChipFreeData(patternChip);
 
-
-
-
-
-
-                pmHDU *hdu = pmHDUGetLowest(file->fpa, chip, cell); // HDU for readout
-                if (!hdu) {
-                    psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find HDU for data.");
-                    return false;
-                }
-                if (!hdu->header) {
-                    hdu->header = psMetadataAlloc();
-                }
-                ppBackgroundVersionHeader(hdu->header);
-
-
-
-
-
-
-
+        pmHDU *hdu = pmHDUGetLowest(file->fpa, chip, NULL); // HDU for chip
+        if (!hdu) {
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find HDU for data.");
+            return false;
+        }
+        if (!hdu->header) {
+            hdu->header = psMetadataAlloc();
+        }
+        ppBackgroundVersionHeader(hdu->header);
 
         // Chip
@@ -158,4 +154,7 @@
     }
 
+    psFree(view);
+    psFree(patternMosaic);
+
     return true;
 }
Index: trunk/ppBackground/src/ppBackgroundModel.c
===================================================================
--- trunk/ppBackground/src/ppBackgroundModel.c	(revision 28276)
+++ 	(revision )
@@ -1,92 +1,0 @@
-#include <stdio.h>
-#include <pslib.h>
-#include <psmodules.h>
-#include <psphot.h>
-
-
-bool ppBackgroundModel(
-        pmReadout *ro = cell->readouts->data[0]; // Readout of interest
-        if (!ro || !ro->data_exists) {
-            psError(PS_ERR_UNKNOWN, true, "readout has no data");
-            return false;
-        }
-        psImage *image = ro->image;
-//        psImage *mask = NULL;
-//        psImageMaskType maskVal = 0;
-
-        pmFPAview roView = *view;
-        roView.cell = 0;
-        roView.readout = 0;
-        pmReadout *modelRO = pmFPAviewThisReadout(&roView, backmdl->fpa);
-        if (!modelRO || !modelRO->data_exists) {
-            psError(PS_ERR_UNKNOWN, true, "model readout has no data");
-            return false;
-        }
-        output->save = true;
-        background->save = save_background;
-
-        psImageBinning *binning = psphotBackgroundBinning(image, config);
-        if (!binning) {
-            psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find background binning");
-            return false;
-        }
-        pmReadout *backgroundRO;
-#define USE_CELL
-#ifdef USE_CELL
-        pmCell *backgroundCell = pmFPAviewThisCell(&roView, background->fpa);
-        backgroundRO = pmReadoutAlloc(backgroundCell);
-#else
-        backgroundRO = pmFPAviewThisReadout(&roView, background->fpa);
-//        backgroundRO = pmFPAfileDefineInternal (config->files, "PSPHOT.BACKGND", image->numCols, image->numRows, PS_TYPE_F32);
-#endif
-        backgroundRO->image = psImageAlloc(image->numCols, image->numRows, PS_TYPE_F32);
-        backgroundRO->data_exists = true;
-        backgroundRO->parent->data_exists = true;
-        backgroundRO->parent->parent->data_exists = true;
-
-        // linear interpolation to full-scale
-        if (!psImageUnbin (backgroundRO->image, modelRO->image, binning)) {
-            psError (PSPHOT_ERR_PROG, true, "inconsistent sizes for unbinning");
-            psFree(binning);
-            return false;
-        }
-        psFree(binning);
-        psF32 **backData = backgroundRO->image->data.F32;
-
-        // Undo the background subtraction
-        int numCols = image->numCols, numRows = image->numRows; // Size of image
-        long nancount = 0;
-        long naninputs = 0;
-        long finitecount = 0;
-        for (int y = 0; y < numRows; y++) {
-            for (int x = 0; x < numCols; x++) {
-                float imageval =  image->data.F32[y][x] ;
-                float bgvalue = backData[y][x];
-                if (!isfinite(bgvalue)) {
-                    // if background is NAN leave the image unchanged
-                    // According to ppImageSubtractBackground pixels where the background is not finite should be NAN
-                    // experimentally
-                    // for breakpoint
-                    nancount++;
-                    if (isfinite(imageval)) {
-                         finitecount++;
-                         //   psWarning("unexpected finite image value %f found at %d %d background is infinite", imageval, x, y);
-                    }
-                    //      Doing this is causes a lot of new NAN pixels to appear.
-                    //      NANS are appearing in the model for some reason.
-                    //      image->data.F32[y][x] = NAN;
-                } else if (isfinite(imageval)) {
-                    // XXX: TODO:following ppImage we should not modify pixels that are masked.
-                    image->data.F32[y][x] = imageval + bgvalue;
-                } else {
-                    naninputs++;
-                }
-            }
-        }
-        if (naninputs) {
-            printf("%ld infinite pixels found in input image\n", naninputs);
-        }
-        if (nancount) {
-            psWarning("%ld infinite pixels found in background %ld pixels were finite\n", nancount, finitecount);
-        }
-//        pmFPAfileDropInternal(config->files, "PSPHOT.BACKGND");
Index: trunk/ppBackground/src/ppBackgroundRestore.c
===================================================================
--- trunk/ppBackground/src/ppBackgroundRestore.c	(revision 28280)
+++ trunk/ppBackground/src/ppBackgroundRestore.c	(revision 28280)
@@ -0,0 +1,71 @@
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <psphot.h>
+
+#include "ppBackground.h"
+
+bool ppBackgroundRestore(pmChip *chip, const pmChip *background, const pmChip *pattern,
+                         const pmFPAview *oldView, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(chip, false);
+    PS_ASSERT_PTR_NON_NULL(oldView, false);
+
+    pmFPAview *view = pmFPAviewAlloc(0); // View to readout
+    *view = *oldView;
+    view->cell = 0;
+    view->readout = 0;
+
+    pmReadout *ro = pmFPAviewThisReadout(view, chip->parent);
+    if (!ro || !ro->data_exists) {
+        psError(PPBACKGROUND_ERR_CONFIG, true, "Readout has no data");
+        return false;
+    }
+    psImage *image = ro->image;                             // Image to correct
+    int numCols = image->numCols, numRows = image->numRows; // Size of image
+
+    if (background) {
+        pmReadout *bgRO = pmFPAviewThisReadout(view, background->parent); // Readout with background
+        psImageBinning *binning = psphotBackgroundBinning(bgRO->image, config);
+        if (!binning) {
+            psError(psErrorCodeLast(), false, "Unable to find background binning");
+            return false;
+        }
+        if (binning->nXfine != numCols || binning->nYfine != numRows) {
+            psError(PPBACKGROUND_ERR_CONFIG, true,
+                    "Unbinned background model and input don't match (%dx%d vs %dx%d)",
+                    binning->nXfine, binning->nYfine, numCols, numRows);
+            return false;
+        }
+
+        psImage *bgImage = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Background
+        if (!psImageUnbin(bgImage, bgRO->image, binning)) {
+            psError(psErrorCodeLast(), false, "Unable to unbin background model");
+            psFree(binning);
+            return false;
+        }
+        psFree(binning);
+
+        for (int y = 0; y < numRows; y++) {
+            for (int x = 0; x < numCols; x++) {
+                image->data.F32[y][x] += bgImage->data.F32[y][x];
+            }
+        }
+        psFree(bgImage);
+    }
+
+    if (pattern) {
+        pmReadout *patternRO = pmFPAviewThisReadout(view, pattern->parent); // Readout with pattern
+        psImage *patternImage = patternRO->image; // Image with pattern
+        for (int y = 0; y < numRows; y++) {
+            for (int x = 0; x < numCols; x++) {
+                image->data.F32[y][x] += patternImage->data.F32[y][x];
+            }
+        }
+    }
+
+    return true;
+}
+
+
+
Index: trunk/ppBackground/src/ppBackgroundVersionDefinitions.h.in
===================================================================
--- trunk/ppBackground/src/ppBackgroundVersionDefinitions.h.in	(revision 28276)
+++ trunk/ppBackground/src/ppBackgroundVersionDefinitions.h.in	(revision 28280)
@@ -1,8 +1,8 @@
-#ifndef PPVIZPATTERN_VERSION_DEFINITIONS_H
-#define PPVIZPATTERN_VERSION_DEFINITIONS_H
+#ifndef PPBACKGROUND_VERSION_DEFINITIONS_H
+#define PPBACKGROUND_VERSION_DEFINITIONS_H
 
-#define PPVIZPATTERN_VERSION @PPVIZPATTERN_VERSION@ // SVN version
-#define PPVIZPATTERN_BRANCH  @PPVIZPATTERN_BRANCH@  // SVN branch
-#define PPVIZPATTERN_SOURCE  @PPVIZPATTERN_SOURCE@  // SVN source
+#define PPBACKGROUND_VERSION @PPBACKGROUND_VERSION@ // SVN version
+#define PPBACKGROUND_BRANCH  @PPBACKGROUND_BRANCH@  // SVN branch
+#define PPBACKGROUND_SOURCE  @PPBACKGROUND_SOURCE@  // SVN source
 
 #endif
