Index: branches/pap/ppSub/configure.ac
===================================================================
--- branches/pap/ppSub/configure.ac	(revision 23690)
+++ branches/pap/ppSub/configure.ac	(revision 23704)
@@ -23,4 +23,9 @@
 PKG_CHECK_MODULES([PSPHOT], [psphot >= 0.9.0]) 
 
+AC_PATH_PROG([ERRORCODES], [psParseErrorCodes], [missing])
+if test "$ERRORCODES" = "missing" ; then
+  AC_MSG_ERROR([psParseErrorCodes is required])
+fi
+
 dnl Set CFLAGS for build
 IPP_STDOPTS
Index: branches/pap/ppSub/src/Makefile.am
===================================================================
--- branches/pap/ppSub/src/Makefile.am	(revision 23690)
+++ branches/pap/ppSub/src/Makefile.am	(revision 23704)
@@ -42,4 +42,16 @@
 	ppSub.h
 
+
+### Error codes.
+BUILT_SOURCES = ppSubErrorCodes.h ppSubErrorCodes.c
+CLEANFILES = ppSubErrorCodes.h ppSubErrorCodes.c
+
+ppSubErrorCodes.h : ppSubErrorCodes.dat ppSubErrorCodes.h.in
+	$(ERRORCODES) --data=ppSubErrorCodes.dat --outdir=. ppSubErrorCodes.h
+
+ppSubErrorCodes.c : ppSubErrorCodes.dat ppSubErrorCodes.c.in ppSubErrorCodes.h
+	$(ERRORCODES) --data=ppSubErrorCodes.dat --outdir=. ppSubErrorCodes.c
+
+
 clean-local:
 	-rm -f TAGS
@@ -48,3 +60,2 @@
 tags:
 	etags `find . -name \*.[ch] -print`
-
Index: branches/pap/ppSub/src/ppSub.c
===================================================================
--- branches/pap/ppSub/src/ppSub.c	(revision 23690)
+++ branches/pap/ppSub/src/ppSub.c	(revision 23704)
@@ -49,5 +49,7 @@
     }
 
-    if (!ppSubArgumentsSetup(argc, argv, config)) {
+    ppSubData *data = ppSubDataAlloc(); // Processing data
+
+    if (!ppSubArgumentsSetup(argc, argv, config, data)) {
         psErrorStackPrint(stderr, "Error reading arguments.\n");
         exitValue = PS_EXIT_CONFIG_ERROR;
@@ -55,5 +57,5 @@
     }
 
-    if (!ppSubCamera(config)) {
+    if (!ppSubCamera(config, data)) {
         psErrorStackPrint(stderr, "Error setting up camera.\n");
         exitValue = PS_EXIT_CONFIG_ERROR;
@@ -61,11 +63,5 @@
     }
 
-    if (!ppSubArgumentsParse(config)) {
-        psErrorStackPrint(stderr, "Error reading arguments.\n");
-        exitValue = PS_EXIT_CONFIG_ERROR;
-        goto die;
-    }
-
-    if (!ppSubLoop(config)) {
+    if (!ppSubLoop(config, data)) {
         psErrorStackPrint(stderr, "Error performing subtraction.\n");
         exitValue = PS_EXIT_SYS_ERROR;
Index: branches/pap/ppSub/src/ppSub.h
===================================================================
--- branches/pap/ppSub/src/ppSub.h	(revision 23690)
+++ branches/pap/ppSub/src/ppSub.h	(revision 23704)
@@ -24,13 +24,20 @@
 // Output files, for activation/deactivation
 typedef enum {
-    PPSUB_FILES_IMAGE = 0x01,           // Image files
-    PPSUB_FILES_PHOT  = 0x02,           // Photometry files
-    PPSUB_FILES_ALL   = 0xFF,           // All files
+    PPSUB_FILES_INPUT    = 0x01,         // Input files
+    PPSUB_FILES_CONV     = 0x02,         // Convolved files (output)
+    PPSUB_FILES_SUB      = 0x04,         // Subtracted files (output)
+    PPSUB_FILES_INV      = 0x08,         // Inverse subtracted files (output)
+    PPSUB_FILES_PHOT_SUB = 0x10,         // Photometry files (output)
+    PPSUB_FILES_PHOT_INV = 0x20,        // Photometry files (
+    PPSUB_FILES_ALL      = 0xFF,         // All files
 } ppSubFiles;
 
 /// Data for processing
 typedef struct {
-    psErrorCode quality;                /// Quality code; 0 for no problem
-    psMetadata *stats;                  /// Statistics
+    psErrorCode quality;                // Quality code; 0 for no problem
+    bool photometry;                    // Perform photometry?
+    bool inverse;                       // Output inverse subtraction as well?
+    const char *statsFile;              // Statistics file
+    psMetadata *stats;                  // Statistics
 } ppSubData;
 
Index: branches/pap/ppSub/src/ppSubArguments.c
===================================================================
--- branches/pap/ppSub/src/ppSubArguments.c	(revision 23690)
+++ branches/pap/ppSub/src/ppSubArguments.c	(revision 23704)
@@ -189,15 +189,7 @@
 }
 
-bool ppSubArgumentsSetup(int argc, char *argv[], pmConfig *config)
-{
-    //    int argnum;                         // Argument Number
+bool ppSubArguments(int argc, char *argv[], pmConfig *config, ppSubData *data)
+{
     assert(config);
-
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
-    if (!recipe) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSUB_RECIPE);
-        return false;
-    }
-
 
     psMetadata *arguments = config->arguments; // Command-line arguments
@@ -212,45 +204,6 @@
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-kernel", 0, "Precalculated kernel to apply", NULL);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-stats", 0, "Statistics file", NULL);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-region", 0, "Size of iso-kernel region", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-size", 0, "Kernel half-size (pixels)", 0);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-order", 0, "Spatial polynomial order", -1);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-type", 0,
-                     "Kernel type (ISIS|POIS|SPAM|FRIES|GUNK|RINGS)", NULL);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-penalty", 0, "Penalty for wideness", NAN);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-isis-widths", 0,
-                     "ISIS Gaussian FWHMs (comma-separated)", NULL);
-    psMetadataAddStr(arguments, PS_LIST_TAIL, "-isis-orders", 0,
-                     "ISIS polynomial orders (comma-separated)", NULL);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-rings-order", 0, "RINGS polynomial order", -1);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-inner", 0, "SPAM and FRIES inner radius", -1);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-spam-binning", 0, "SPAM kernel binning", 0);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-spacing", 0, "Typical stamp spacing (pixels)", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-footprint", 0, "Stamp footprint half-size (pixels)", -1);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-source-radius", 0, "Source matching radius (pixels)", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-stride", 0, "Size of convolution patches (pixels)", -1);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-threshold", 0, "Minimum threshold for stamps (ADU)", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-iter", 0, "Number of rejection iterations", -1);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-rej", 0, "Rejection thresold (sigma)", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-sys", 0, "Relative systematic error in kernel", NAN);
-    psMetadataAddImageMask(arguments,  PS_LIST_TAIL, "-mask-bad", 0, "Mask value for bad pixels", 0);
-    psMetadataAddImageMask(arguments,  PS_LIST_TAIL, "-mask-poor", 0, "Mask value for poor pixels", 0);
-    psMetadataAddF32(arguments,  PS_LIST_TAIL, "-poor-frac", 0, "Fraction of variance for poor pixels", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-badfrac", 0, "Maximum fraction of bad pixels to accept", 1.0);
-    psMetadataAddBool(arguments,  PS_LIST_TAIL, "-reverse", 0, "Reverse sense of subtraction?", false);
-    psMetadataAddBool(arguments,  PS_LIST_TAIL, "-generate-mask", 0, "Generate mask if not supplied?", false);
-    psMetadataAddStr(arguments,  PS_LIST_TAIL, "-stamps", 0,
-                     "Stamps filename; file has x,y on each line", NULL);
-    psMetadataAddBool(arguments, PS_LIST_TAIL, "-opt", 0,
-                      "Derive optimum parameters for ISIS kernels?", false);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-opt-min", 0, "Minimum value for optimum kernel search", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-opt-max", 0, "Minimum value for optimum kernel search", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-opt-step", 0, "Step value for optimum kernel search", NAN);
-    psMetadataAddF32(arguments, PS_LIST_TAIL, "-opt-tol", 0, "Tolerance for optimum kernel search", NAN);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-opt-order", 0, "Maximum order for optimum kernel search", -1);
-    psMetadataAddBool(arguments, PS_LIST_TAIL, "-dual", 0, "Dual convolution", false);
-    psMetadataAddBool(arguments, PS_LIST_TAIL, "-photometry", 0, "Perform photometry?", false);
+    psMetadataAddStr(arguments,  PS_LIST_TAIL, "-stamps", 0, "Stamps filename; x,y on each line", NULL);
     psMetadataAddS32(arguments, PS_LIST_TAIL, "-threads", 0, "Number of threads", 0);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-bin1", 0, "Binning factor for first level", 0);
-    psMetadataAddS32(arguments, PS_LIST_TAIL, "-bin2", 0, "Binning factor for second level", 0);
     psMetadataAddStr(arguments, PS_LIST_TAIL, "-dumpconfig", 0, "file to dump configuration to", NULL);
     psMetadataAddBool(arguments, PS_LIST_TAIL, "-visual", 0, "Show diagnostic plots", NULL);
@@ -302,80 +255,16 @@
     }
 
-    if (psMetadataLookupBool(NULL, arguments, "-photometry")) {
-        psMetadataAddBool(recipe, PS_LIST_TAIL, "PHOTOMETRY", PS_META_REPLACE, "Perform photometry?", true);
-    }
-
-    return true;
-}
-
-bool ppSubArgumentsParse(pmConfig *config)
-{
-    assert(config);
-
-    psMetadata *arguments = config->arguments; // Command-line arguments
-
-    valueArgStr(arguments, "-stats",  "STATS",  arguments);
-    valueArgStr(arguments, "-stamps", "STAMPS", arguments);
-
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
-    if (!recipe) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSUB_RECIPE);
-        goto ERROR;
-    }
-
-    VALUE_ARG_RECIPE_FLOAT("-region",        "REGION.SIZE",     F32);
-    VALUE_ARG_RECIPE_INT("-size",            "KERNEL.SIZE",     S32, 0);
-    VALUE_ARG_RECIPE_INT("-order",           "SPATIAL.ORDER",   S32, -1);
-    VALUE_ARG_RECIPE_FLOAT("-spacing",       "STAMP.SPACING",   F32);
-    VALUE_ARG_RECIPE_INT("-rings-order",     "RINGS.ORDER",     S32, -1);
-    VALUE_ARG_RECIPE_INT("-inner",           "INNER",           S32, -1);
-    VALUE_ARG_RECIPE_INT("-spam-binning",    "SPAM.BINNING",    S32, 0);
-    VALUE_ARG_RECIPE_INT("-footprint",       "STAMP.FOOTPRINT", S32, -1);
-    VALUE_ARG_RECIPE_FLOAT("-source-radius", "SOURCE.RADIUS",   F32);
-    VALUE_ARG_RECIPE_INT("-stride",          "STRIDE",          S32, -1);
-    VALUE_ARG_RECIPE_FLOAT("-threshold",     "STAMP.THRESHOLD", F32);
-    VALUE_ARG_RECIPE_INT("-iter",            "ITER",            S32, -1);
-    VALUE_ARG_RECIPE_FLOAT("-rej",           "REJ",             F32);
-    VALUE_ARG_RECIPE_FLOAT("-sys",           "SYS",             F32);
-    VALUE_ARG_RECIPE_FLOAT("-badfrac",       "BADFRAC",         F32);
-    VALUE_ARG_RECIPE_FLOAT("-penalty",       "PENALTY",         F32);
-    VALUE_ARG_RECIPE_FLOAT("-poor-frac",     "POOR.FRACTION",   F32);
-    VALUE_ARG_RECIPE_INT("-bin1",            "BIN1",            S32, 0);
-    VALUE_ARG_RECIPE_INT("-bin2",            "BIN2",            S32, 0);
-
-    valueArgRecipeStr(arguments, recipe, "-mask-in",   "MASK.IN",  recipe);
-    valueArgRecipeStr(arguments, recipe, "-mask-bad",  "MASK.BAD",  recipe);
-    valueArgRecipeStr(arguments, recipe, "-mask-poor", "MASK.POOR", recipe);
-
-    vectorArgRecipe(arguments, "-isis-widths", recipe, "ISIS.WIDTHS", recipe, PS_TYPE_F32);
-    vectorArgRecipe(arguments, "-isis-orders", recipe, "ISIS.ORDERS", recipe, PS_TYPE_S32);
-
-    psVector *widths = psMetadataLookupPtr(NULL, recipe, "ISIS.WIDTHS"); // ISIS Gaussian widths
-    psVector *orders = psMetadataLookupPtr(NULL, recipe, "ISIS.ORDERS"); // ISIS Polynomial orders
-    if (widths->n != orders->n) {
-        psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Size of vectors for ISIS widths and orders do not match.");
-        goto ERROR;
-    }
-
-    if (psMetadataLookupBool(NULL, arguments, "-opt") || psMetadataLookupBool(NULL, recipe, "OPTIMUM")) {
-        psMetadataAddBool(recipe, PS_LIST_TAIL, "OPTIMUM", PS_META_REPLACE,
-                          "Derive optimum parameters for ISIS kernels?", true);
-        VALUE_ARG_RECIPE_FLOAT("-opt-min", "OPTIMUM.MIN",   F32);
-        VALUE_ARG_RECIPE_FLOAT("-opt-max", "OPTIMUM.MAX",   F32);
-        VALUE_ARG_RECIPE_FLOAT("-opt-step","OPTIMUM.STEP",  F32);
-        VALUE_ARG_RECIPE_FLOAT("-opt-tol", "OPTIMUM.TOL",   F32);
-        VALUE_ARG_RECIPE_INT("-opt-order", "OPTIMUM.ORDER", S32, -1);
-    }
-
-    psMetadataAddBool(arguments, PS_LIST_TAIL, "REVERSE", 0, "Reverse sense of subtraction",
-                      psMetadataLookupBool(NULL, arguments, "-reverse"));
-    psMetadataAddBool(recipe, PS_LIST_TAIL, "MASK.GENERATE", PS_META_REPLACE, "Generate mask if not supplied",
-                      psMetadataLookupBool(NULL, arguments, "-generate-mask"));
-    psMetadataAddBool(recipe, PS_LIST_TAIL, "DUAL", PS_META_REPLACE, "Dual convolution?",
-                      psMetadataLookupBool(NULL, arguments, "-dual"));
-
-    // Need to update this because it could have been overwritten by the camera's own recipe
-    if (psMetadataLookupBool(NULL, arguments, "-photometry")) {
-        psMetadataAddBool(recipe, PS_LIST_TAIL, "PHOTOMETRY", PS_META_REPLACE, "Perform photometry?", true);
+    data->stamps = psMetadataLookupStr(NULL, arguments, "-stamps");
+
+    const char *statsName = psMetadataLookupStr(NULL, arguments, "-stats"); // Filename for statistics
+    if (statsName && strlen(statsName) > 0) {
+        psString resolved = pmConfigConvertFilename(statsName, config, true, true); // Resolved filename
+        data->statsFile = fopen(resolved, "w");
+        if (!data->statsFile) {
+            psError(PS_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
+            psFree(resolved);
+            return false;
+        }
+        psFree(resolved);
     }
 
@@ -384,19 +273,5 @@
     }
 
-    // Translate the kernel type
-    psString type = psMetadataLookupStr(NULL, arguments, "-type"); // Name of kernel type
-    if (!type || strlen(type) == 0) {
-        type = psMetadataLookupStr(NULL, recipe, "KERNEL.TYPE");
-        if (!type || strlen(type) == 0) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, false, "Unable to find KERNEL.TYPE specified.");
-            goto ERROR;
-        }
-    }
-    psMetadataAddStr(recipe, PS_LIST_TAIL, "KERNEL.TYPE", PS_META_REPLACE, "Type of kernel", type);
-
-    psTrace("ppSub", 1, "Done reading command-line arguments\n");
-
-    // XXX move this to ppSubArguments
-    int threads = psMetadataLookupS32(NULL, config->arguments, "-threads"); // Number of threads
+    int threads = psMetadataLookupS32(NULL, arguments, "-threads"); // Number of threads
     if (threads > 0) {
         if (!psThreadPoolInit(threads)) {
@@ -407,6 +282,10 @@
 
     return true;
-
-ERROR:
-    return false;
-}
+}
+
+
+
+    psTrace("ppSub", 1, "Done reading command-line arguments\n");
+
+    return true;
+}
Index: branches/pap/ppSub/src/ppSubCamera.c
===================================================================
--- branches/pap/ppSub/src/ppSubCamera.c	(revision 23690)
+++ branches/pap/ppSub/src/ppSubCamera.c	(revision 23704)
@@ -161,4 +161,14 @@
 
 
+    // Now that the camera has been determined, we can read the recipe
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSUB_RECIPE); // Recipe for ppSim
+    if (!recipe) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSUB_RECIPE);
+        return false;
+    }
+    data->invert = psMetadataLookupBool(NULL, recipe, "INVERSE");
+    data->photometry = psMetadataLookupBool(NULL, recipe, "PHOTOMETRY");
+
+
     // Output image
     pmFPAfile *output = defineOutputFile(config, input, true, "PPSUB.OUTPUT", PM_FPA_FILE_IMAGE);
@@ -170,7 +180,7 @@
     output->save = true;
     outMask->save = true;
-    pmFPAfile *outVar = NULL;
     if (inVar && refVar) {
-        outVar = defineOutputFile(config, output, false, "PPSUB.OUTPUT.VARIANCE", PM_FPA_FILE_VARIANCE);
+        pmFPAfile *outVar = defineOutputFile(config, output, false, "PPSUB.OUTPUT.VARIANCE",
+                                             PM_FPA_FILE_VARIANCE);
         if (!outVar) {
             psError(PS_ERR_UNKNOWN, false, "Unable to define output files");
@@ -180,4 +190,25 @@
     }
 
+    if (data->inverse) {
+        // Inverse output image
+        pmFPAfile *outinv = defineOutputFile(config, input, true, "PPSUB.OUTINV", PM_FPA_FILE_IMAGE);
+        pmFPAfile *outinvMask = defineOutputFile(config, outinv, false, "PPSUB.OUTINV.MASK",
+                                                 PM_FPA_FILE_MASK);
+        if (!outinv || !outinvMask) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to define output files");
+            return false;
+        }
+        outinv->save = true;
+        outinvMask->save = true;
+        if (inVar && refVar) {
+            pmFPAfile *outinvVar = defineOutputFile(config, outinv, false, "PPSUB.OUTINV.VARIANCE",
+                                                    PM_FPA_FILE_VARIANCE);
+            if (!outinvVar) {
+                psError(PS_ERR_UNKNOWN, false, "Unable to define output files");
+                return false;
+            }
+            outinvVar->save = true;
+        }
+    }
 
     // Convolved input image
@@ -252,5 +283,5 @@
 
     // psPhot input
-    if (psMetadataLookupBool(NULL, recipe, "PHOTOMETRY")) {
+    if (data->photometry) {
         psphotModelClassInit();        // load implementation-specific models
 
Index: branches/pap/ppSub/src/ppSubData.c
===================================================================
--- branches/pap/ppSub/src/ppSubData.c	(revision 23690)
+++ branches/pap/ppSub/src/ppSubData.c	(revision 23704)
@@ -20,7 +20,17 @@
 
 
-static void subOptionsFree(ppSubData *options)
+static void subDataFree(ppSubData *data)
 {
-    psFree(options->stats);
+    if (data->statsFile) {
+        psString stats = psMetadataConfigFormat(data->stats); // Statistics to output
+        if (!stats || strlen(stats) == 0) {
+            psWarning("Unable to generate statistics file.");
+        } else {
+            fprintf(data->statsFile, "%s", stats);
+        }
+        psFree(stats);
+        fclose(data->statsFile);
+    }
+    psFree(data->stats);
     return;
 }
@@ -28,10 +38,13 @@
 ppSubData *ppSubDataAlloc(void)
 {
-    ppSubData *options = psAlloc(sizeof(ppSubData)); // Processing data, to return
-    psMemSetDeallocator(options, (psFreeFunc)subOptionsFree);
+    ppSubData *data = psAlloc(sizeof(ppSubData)); // Processing data, to return
+    psMemSetDeallocator(data, (psFreeFunc)subDataFree);
 
-    options->quality = 0;
-    options->stats = psMetadataAlloc();
-    psMetadataAddS32(options->stats, PS_LIST_TAIL, "QUALITY", 0, "Data quality", 0);
+    data->quality = 0;
+    data->photometry = false;
+    data->inverse = false;
+    data->statsFile = NULL;
+    data->stats = psMetadataAlloc();
+    psMetadataAddS32(data->stats, PS_LIST_TAIL, "QUALITY", 0, "Data quality", 0);
 
     return options;
Index: branches/pap/ppSub/src/ppSubDefineOutput.c
===================================================================
--- branches/pap/ppSub/src/ppSubDefineOutput.c	(revision 23690)
+++ branches/pap/ppSub/src/ppSubDefineOutput.c	(revision 23704)
@@ -21,10 +21,11 @@
 #include "ppSub.h"
 
-bool ppSubDefineOutput(pmConfig *config, const pmFPAview *view)
+bool ppSubDefineOutput(const char *name, pmConfig *config, const ppSubData *data, const pmFPAview *view)
 {
+    psAssert(name, "Require name");
     psAssert(config, "Require configuration");
     psAssert(view, "Require view");
 
-    pmCell *outCell = pmFPAfileThisCell(config->files, view, "PPSUB.OUTPUT"); // Output cell
+    pmCell *outCell = pmFPAfileThisCell(config->files, view, name); // Output cell
     pmFPA *outFPA = outCell->parent->parent; // Output FPA
     pmHDU *outHDU = outFPA->hdu; // Output HDU
@@ -33,8 +34,9 @@
     }
 
-    // generate an output readout (first check if it's already there by virtue of kernels)
-    pmReadout *outRO = pmFPAfileThisReadout(config->files, view, "PPSUB.OUTPUT.KERNELS"); // RO with kernel
-    if (!outRO) {
-        outRO = pmReadoutAlloc(outCell); // Output readout: subtraction
+    pmReadout *outRO = NULL;            // Output readout
+    if (outCell->readouts && outCell->readouts->n > 0 && outCell->readouts->data[0]) {
+        outRO = psMemIncrRefCounter(outCell->readouts->data[0]);
+    } else {
+        outRO = pmReadoutAlloc(outCell);
     }
 
@@ -55,6 +57,4 @@
     if (!kernels) {
         psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find SUBTRACTION.KERNEL");
-        psFree(inConv);
-        psFree(refConv);
         psFree(outRO);
         return false;
@@ -65,13 +65,5 @@
     outRO->analysis = psMetadataCopy(outRO->analysis, analysis);
 
-#ifdef TESTING
-    {
-        psImage *kernelImage = psMetadataLookupPtr(&mdok, analysis,
-                                                   "SUBTRACTION.KERNEL.IMAGE"); // Image of kernel
-        psFits *fits = psFitsOpen("kernel.fits", "w");
-        psFitsWriteImage(fits, NULL, kernelImage, 0, NULL);
-        psFitsClose(fits);
-    }
-#endif
+    psFree(outRO);
 
     return true;
Index: branches/pap/ppSub/src/ppSubErrorCodes.c.in
===================================================================
--- branches/pap/ppSub/src/ppSubErrorCodes.c.in	(revision 23704)
+++ branches/pap/ppSub/src/ppSubErrorCodes.c.in	(revision 23704)
@@ -0,0 +1,37 @@
+/** @file pswarpErrorCodes.c.in
+ *
+ *  @brief
+ *
+ *  @ingroup pswarp
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-05 20:44:04 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#include "pslib.h"
+#include "pswarpErrorCodes.h"
+
+/*
+ * The line
+    { PSWARP_ERR_$X{ErrorCode}, "$X{ErrorDescription}"},
+ * (without the Xs)
+ * will be replaced by values from errorCodes.dat
+ */
+void pswarpErrorRegister(void)
+{
+    static psErrorDescription errors[] = {
+       { PSWARP_ERR_BASE, "First value we use; lower values belong to psLib" },
+       { PSWARP_ERR_${ErrorCode}, "${ErrorDescription}"},
+    };
+    static int nerror = PSWARP_ERR_NERROR - PSWARP_ERR_BASE; ///< number of values in enum
+
+    for (int i = 0; i < nerror; i++) {
+       psErrorDescription *tmp = psAlloc(sizeof(psErrorDescription));
+       *tmp = errors[i];
+       psErrorRegister(tmp, 1);
+       psFree(tmp);			/* it's on the internal list */
+    }
+    nerror = 0;			                // don't register more than once
+}
Index: branches/pap/ppSub/src/ppSubErrorCodes.dat
===================================================================
--- branches/pap/ppSub/src/ppSubErrorCodes.dat	(revision 23704)
+++ branches/pap/ppSub/src/ppSubErrorCodes.dat	(revision 23704)
@@ -0,0 +1,11 @@
+#
+# This file is used to generate pswarpErrorClasses.h
+#
+BASE = 14000		First value we use; lower values belong to psLib
+UNKNOWN			Unknown ppSub error code
+NOT_IMPLEMENTED		Desired feature is not yet implemented
+ARGUMENTS		Incorrect arguments
+CONFIG			Problem in configure files
+IO			Problem in FITS I/O
+DATA                    Problem in data values
+NO_OVERLAP		No overlap between input and skycell
Index: branches/pap/ppSub/src/ppSubErrorCodes.h.in
===================================================================
--- branches/pap/ppSub/src/ppSubErrorCodes.h.in	(revision 23704)
+++ branches/pap/ppSub/src/ppSubErrorCodes.h.in	(revision 23704)
@@ -0,0 +1,30 @@
+/** @file pswarpErrorCodes.h.in
+ *
+ *  @brief
+ *
+ *  @ingroup pswarp
+ *
+ *  @author IfA
+ *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-05 20:44:04 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+#if !defined(PSWARP_ERROR_CODES_H)
+#define PSWARP_ERROR_CODES_H
+/*
+ * The line
+ *  PSWARP_ERR_$X{ErrorCode},
+ * (without the X)
+ *
+ * will be replaced by values from errorCodes.dat
+ */
+typedef enum {
+    PSWARP_ERR_BASE = 14000,
+    PSWARP_ERR_${ErrorCode},
+    PSWARP_ERR_NERROR
+} pswarpErrorCode;
+
+void pswarpErrorRegister(void);
+
+#endif
Index: branches/pap/ppSub/src/ppSubFiles.c
===================================================================
--- branches/pap/ppSub/src/ppSubFiles.c	(revision 23704)
+++ branches/pap/ppSub/src/ppSubFiles.c	(revision 23704)
@@ -0,0 +1,160 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+#include <psphot.h>
+
+#include "ppSub.h"
+
+
+// Input files
+static const char *inputFiles[] = { "PPSUB.OUTPUT", "PPSUB.OUTPUT.MASK", "PPSUB.OUTPUT.VARIANCE",
+                                    "PPSUB.OUTPUT.KERNELS", "PPSUB.OUTPUT.JPEG1", "PPSUB.OUTPUT.JPEG2",
+                                    NULL };
+
+// Convolved files
+static const char *convFiles[] = { "PPSUB.INPUT.CONV", "PPSUB.INPUT.CONV.MASK", "PPSUB.INPUT.CONV.VARIANCE",
+                                   "PPSUB.REF.CONV", "PPSUB.REF.CONV.MASK", "PPSUB.REF.CONV.VARIANCE",
+                                   NULL };
+
+// Subtraction files
+static const char *subFiles[] = { "PPSUB.OUTPUT", "PPSUB.OUTPUT.MASK", "PPSUB.OUTPUT.VARIANCE",
+                                  "PPSUB.OUTPUT.KERNELS", "PPSUB.OUTPUT.JPEG1", "PPSUB.OUTPUT.JPEG2",
+                                  NULL };
+
+// Inverse subtraction files
+static const char *invFiles[] = { "PPSUB.OUTINV", "PPSUB.OUTINV.MASK", "PPSUB.OUTINV.VARIANCE",
+                                  "PPSUB.OUTINV.KERNELS", "PPSUB.OUTINV.JPEG1", "PPSUB.OUTINV.JPEG2",
+                                  NULL };
+
+// Calculation (may be either input or output) files
+static const char *calcFiles[] = { "PPSUB.OUTPUT.KERNELS", NULL };
+
+
+// Activate/deactivate a list of files
+static void filesActivate(const char **files, // List of files
+                          bool state    // Activation status to set
+    )
+{
+    for (int i = 0; imageFiles[i]; i++) {
+        pmFPAfileActivate(config->files, files[i], state);
+    }
+    return;
+}
+
+// Activate/deactivate a list of files depending on their 'save' boolean.
+//  This is so we can activate/deactivate the 'calculation' files, which may be either input or output, which
+// is indicated by their 'save' boolean.
+static void filesActivateSave(const char **files, // List of files
+                              bool save, // Activate when this save state is set
+                              bool state // Activation status to set
+    )
+{
+    for (int i = 0; imageFiles[i]; i++) {
+        pmFPAfile *file = pmFPAfileSelectSingle(config->files, files[i], 0);
+        if (file && file->save == save) {
+            pmFPAfileActivate(config->files, files[i], state);
+        }
+    }
+    return;
+}
+
+void ppSubFilesActivate(pmConfig *config, ppSubFiles files, bool state)
+{
+    psAssert(config, "Require configuration");
+
+    if (files & PPSUB_FILES_INPUT) {
+        filesActivate(inputFiles, state);
+        filesActivateSave(calcFiles, false, state);
+    }
+    if (files & PPSUB_FILES_CONV) {
+        filesActivate(convFiles, state);
+    }
+    if (files & PPSUB_FILES_SUB) {
+        filesActivate(subFiles, state);
+        filesActivateSave(calcFiles, true, state);
+    }
+    if (files & PPSUB_FILES_INV) {
+        filesActivate(invFiles, state);
+    }
+    if (files & PPSUB_FILES_PHOT) {
+        psphotFilesActivate(config, state);
+    }
+
+    return;
+}
+
+
+pmFPAview *ppSubViewReadout(void)
+{
+    pmFPAview *view = pmFPAviewAlloc(0);
+    view->chip = view->cell = view->readout = 0;
+    return view;
+}
+
+bool ppSubFilesIterateDown(pmConfig *config)
+{
+    psAssert(config, "Require configuration");
+
+    pmFPAview *view = pmFPAviewAlloc(0);// View to FPA top
+
+    // FPA
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        return false;
+    }
+
+    // Chip
+    view->chip = 0;
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        return false;
+    }
+
+    // Cell
+    view->cell = 0;
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        return false;
+    }
+
+    // Readout
+    view->readout = 0;
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
+        return false;
+    }
+
+    return true;
+}
+
+bool ppSubFilesIterateUp(pmConfig *config)
+{
+    psAssert(config, "Require configuration");
+
+    pmFPAview *view = ppSubViewReadout(); // View to readout
+
+    // Readout
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        return false;
+    }
+
+    // Cell
+    view->readout = -1;
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        return false;
+    }
+
+    // Chip
+    view->cell = -1;
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        return false;
+    }
+
+    // FPA
+    view->chip = -1;
+    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
+        return false;
+    }
+
+    return true;
+}
Index: branches/pap/ppSub/src/ppSubLoop.c
===================================================================
--- branches/pap/ppSub/src/ppSubLoop.c	(revision 23690)
+++ branches/pap/ppSub/src/ppSubLoop.c	(revision 23704)
@@ -21,5 +21,5 @@
 #include "ppSub.h"
 
-bool ppSubLoop(pmConfig *config)
+bool ppSubLoop(pmConfig *config, ppSubData *data)
 {
     psAssert(config, "Require configuration.");
@@ -28,149 +28,134 @@
     pmConfigRecipesCull(config, "PPSUB,PPSTATS,PSPHOT,MASKS,JPEG");
 
-    ppSubData *data = ppSubDataAlloc(); // Processing data
 
-    bool mdok;                          // Status of MD lookup
-    const char *statsName = psMetadataLookupStr(&mdok, config->arguments, "STATS"); // Filename for statistics
-    FILE *statsFile = NULL;             // File stream for statistics
-    if (statsName && strlen(statsName) > 0) {
-        psString resolved = pmConfigConvertFilename(statsName, config, true, true); // Resolved filename
-        statsFile = fopen(resolved, "w");
-        if (!statsFile) {
-            psError(PS_ERR_IO, true, "Unable to open statistics file %s for writing.\n", resolved);
-            psFree(resolved);
+    pmFPAfile *input = psMetadataLookupPtr(NULL, config->files, "PPSUB.INPUT");
+    pmFPAfile *reference = psMetadataLookupPtr(NULL, config->files, "PPSUB.REF");
+    pmFPAfile *output = psMetadataLookupPtr(NULL, config->files, "PPSUB.OUTPUT");
+    psAssert(input && reference && output, "Require files");
+
+    if (!ppSubFilesIterateDown(config, PPSUB_FILES_INPUT | PPSUB_FILES_CONV)) {
+        psError(PPSUB_ERR_IO, false, "Unable to load files.");
+        return false;
+    }
+
+    psTimerStart("PPSUB_MATCH");
+
+    if (!ppSubSetMasks(config)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to set masks.");
+        return false;
+    }
+
+    if (!ppSubMatchPSFs(config, data)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to match PSFs.");
+        return false;
+    }
+    if (data->quality) {
+        // Can't do anything at all
+        return true;
+    }
+
+    // Close input files
+    if (!ppSubFilesIterateUp(config, PPSUB_FILES_INPUT)) {
+        psError(PPSUB_ERR_IO, false, "Unable to close input files.");
+        return false;
+    }
+
+    // Set up subtraction files
+    if (!ppSubFilesIterateDown(config, PPSUB_FILES_SUB)) {
+        psError(PPSUB_ERR_IO, false, "Unable to set up subtraction files.");
+        return false;
+    }
+
+    if (!ppSubDefineOutput("PPSUB.OUTPUT", config, data, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to define output.");
+        return false;
+    }
+
+    if (data->inverse && !ppSubDefineOutput("PPSUB.OUTINV", config, data, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to define inverse.");
+        return false;
+    }
+
+    if (!data->quality && !ppSubMakePSF("PPSUB.OUTPUT", "PPSUB.OUTINV", config, data, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to generate PSF.");
+        return false;
+    }
+
+    // Close convolved files
+    if (!ppSubFilesIterateUp(config, PPSUB_FILES_CONV)) {
+        psError(PPSUB_ERR_IO, false, "Unable to close input files.");
+        return false;
+    }
+
+    if (!ppSubReadoutSubtract("PPSUB.OUTPUT", config, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to subtract images.");
+        return false;
+    }
+
+    // Higher order background subtraction using psphot
+    if (!ppSubBackground("PPSUB.OUTPUT", config, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to subtract background.");
+        return false;
+    }
+
+    if (!data->quality && data->!ppSubReadoutPhotometry("PPSUB.OUTPUT", config, data, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry.");
+        return false;
+    }
+
+    if (!ppSubReadoutUpdate("PPSUB.OUTPUT", config, data, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to update.");
+        return false;
+    }
+
+    // Perform statistics on the cell
+    if (statsFile) {
+        pmFPAfile *output = psMetadataLookupPtr(NULL, config->files, "PPSUB.OUTPUT"); // Output file
+        if (!output) {
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find file PPSUB.OUTPUT.\n");
             goto ERROR;
         }
-        psFree(resolved);
+        psImageMaskType maskValue = pmConfigMaskGet("MASK.VALUE", config);
+        ppStatsFPA(data->stats, output->fpa, view, maskValue, config);
     }
 
-    pmFPAfile *input = psMetadataLookupPtr(NULL, config->files, "PPSUB.INPUT");
-    if (!input) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Can't find input data!\n");
-        goto ERROR;
-    }
-
-    pmFPAfile *reference = psMetadataLookupPtr(NULL, config->files, "PPSUB.REF");
-    if (!reference) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Can't find reference data!\n");
-        goto ERROR;
-    }
-
-    pmFPAfile *output = psMetadataLookupPtr(NULL, config->files, "PPSUB.OUTPUT");
-    if (!output) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Can't find output data!\n");
-        goto ERROR;
-    }
-
-    pmFPAview *view = pmFPAviewAlloc(0); // Pointer into FPA hierarchy
-
-    // Iterate over the FPA hierarchy
-    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
-        goto ERROR;
-    }
-
-    pmChip *inChip;                    // Input chip of interest
-    while ((inChip = pmFPAviewNextChip(view, input->fpa, 1)) != NULL) {
-        pmChip *refChip = pmFPAviewThisChip(view, reference->fpa); // Reference chip of interest
-        if ((!inChip->file_exists && refChip->file_exists) ||
-            (inChip->file_exists && !refChip->file_exists)) {
-            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "FPA format discrepency between input and reference");
-            psFree(view);
-            goto ERROR;
+    if (data->inverse) {
+        // Set up inverse subtraction files
+        if (!ppSubFilesIterateDown(config, PPSUB_FILES_INV)) {
+            psError(PPSUB_ERR_IO, false, "Unable to set up inverse files.");
+            return false;
         }
 
-        if (!inChip->file_exists) {
-            continue;
+        if (!ppSubReadoutInverse("PPSUB.OUTINV", "PPSUB.OUTPUT", config, view)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to invert images.");
+            return false;
         }
 
-        if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
-            goto ERROR;
+        // Close subtraction files and open inverse photometry files
+        if (!ppSubFilesIterateUp(config, PPSUB_FILES_SUB)) {
+            psError(PPSUB_ERR_IO, false, "Unable to close subtraction files.");
+            return false;
         }
 
-        pmCell *inCell;                // Cell of interest
-        while ((inCell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) {
-            pmCell *refCell = pmFPAviewThisCell(view, reference->fpa); // Reference cell of interest
-            if ((!inCell->file_exists && refCell->file_exists) ||
-                (inCell->file_exists && !refCell->file_exists)) {
-                psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                        "FPA format discrepency between input and reference");
-                psFree(view);
-                goto ERROR;
-            }
-            if (!inCell->file_exists) {
-                continue;
-            }
-            if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
-                goto ERROR;
-            }
-
-            pmReadout *inRO;           // Readin of interest
-            while ((inRO = pmFPAviewNextReadout(view, input->fpa, 1))) {
-                if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
-                    goto ERROR;
-                }
-                pmReadout *refRO = pmFPAviewThisReadout(view, reference->fpa);// Reference readout of interest
-                if (!refRO || (!inRO->data_exists && refRO->data_exists) ||
-                    (inRO->data_exists && !refRO->data_exists)) {
-                    psError(PS_ERR_BAD_PARAMETER_VALUE, true,
-                            "FPA format discrepency between input and reference");
-                    psFree(view);
-                    goto ERROR;
-                }
-                if (!inRO->data_exists) {
-                    continue;
-                }
-
-                // Perform the analysis
-                if (!ppSubReadout(config, data, view)) {
-                    psError(PS_ERR_UNKNOWN, false, "Unable to subtract images.\n");
-                    goto ERROR;
-                }
-
-                if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
-                    goto ERROR;
-                }
-            }
-
-            // Perform statistics on the cell
-            if (statsFile) {
-                pmFPAfile *output = psMetadataLookupPtr(NULL, config->files, "PPSUB.OUTPUT"); // Output file
-                if (!output) {
-                    psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find file PPSUB.OUTPUT.\n");
-                    goto ERROR;
-                }
-                psImageMaskType maskValue = pmConfigMaskGet("MASK.VALUE", config);
-                ppStatsFPA(data->stats, output->fpa, view, maskValue, config);
-            }
-
-            if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
-                goto ERROR;
-            }
+        if (!data->quality && data->!ppSubReadoutPhotometry("PPSUB.OUTINV", config, data, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry.");
+        return false;
         }
-
-        if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
-            goto ERROR;
+    } else {
+        // Close subtraction files
+        if (!ppSubFilesIterateUp(config, PPSUB_FILES_SUB)) {
+            psError(PPSUB_ERR_IO, false, "Unable to close subtraction files.");
+            return false;
         }
     }
 
-    if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
-        goto ERROR;
+
+    if (!ppSubReadoutUpdate("PPSUB.OUTPUT", config, data, view)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to update.");
+        return false;
     }
 
+
     psFree(view);
-
-    // Write out summary statistics
-    if (statsFile) {
-        psMetadataAddF32(data->stats, PS_LIST_TAIL, "TIME_SUB", 0, "Time for subtraction completion",
-                         psTimerMark("ppSub"));
-
-        const char *statsMDC = psMetadataConfigFormat(data->stats);
-        if (!statsMDC || strlen(statsMDC) == 0) {
-            psWarning("Unable to generate statistics MDC file.\n");
-        } else {
-            fprintf(statsFile, "%s", statsMDC);
-        }
-        psFree((void *)statsMDC);
-        fclose(statsFile);
-    }
 
     psString dump_file = psMetadataLookupStr(&mdok, config->arguments, "-dumpconfig");
@@ -180,9 +165,7 @@
     }
 
-    psFree(data);
     return true;
 
 ERROR:
-    psFree(data);
     return false;
 }
Index: branches/pap/ppSub/src/ppSubReadout.c
===================================================================
--- branches/pap/ppSub/src/ppSubReadout.c	(revision 23690)
+++ branches/pap/ppSub/src/ppSubReadout.c	(revision 23704)
@@ -21,32 +21,22 @@
 #include "ppSub.h"
 
-bool ppSubReadout(pmConfig *config, ppSubData *data, const pmFPAview *view)
+bool ppSubReadout(const char *name, bool reverse, pmConfig *config, ppSubData *data, const pmFPAview *view)
 {
-    psTimerStart("PPSUB_MATCH");
+    psAssert(name, "Require name");
+    psAssert(config, "Require configuration");
+    psAssert(data, "Require data");
+    psAssert(view, "Require view");
 
-    if (!ppSubSetMasks(config, view)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to set masks.");
-        return false;
-    }
-
-    if (!ppSubMatchPSFs(config, data, view)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to match PSFs.");
-        return false;
-    } else if (data->quality) {
-        // Can't do anything at all
-        return true;
-    }
-
-    if (!ppSubDefineOutput(config, view)) {
+    if (!ppSubDefineOutput(name, config, data, view)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to define output.");
         return false;
     }
 
-    if (!data->quality && !ppSubMakePSF(config, data, view)) {
+    if (!data->quality && !ppSubMakePSF(name, config, data, view)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to generate PSF.");
         return false;
     }
 
-    if (!ppSubReadoutSubtract(config, view)) {
+    if (!ppSubReadoutSubtract(name, reverse, config, view)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to subtract images.");
         return false;
@@ -54,19 +44,22 @@
 
     // Higher order background subtraction using psphot
-    if (!ppSubBackground(config, view)) {
+    if (!ppSubBackground(name, config, view)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to subtract background.");
         return false;
     }
 
-    if (!data->quality && !ppSubReadoutPhotometry(config, data, view)) {
+    if (!data->quality && data->!ppSubReadoutPhotometry(name, config, data, view)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry.");
         return false;
     }
 
-    if (!ppSubReadoutUpdate(config, data, view)) {
+    if (!ppSubReadoutUpdate(name, config, data, view)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to update.");
         return false;
     }
 
+
+
+
     return true;
 }
