Index: trunk/ppSub/src/ppSubLoop.c
===================================================================
--- trunk/ppSub/src/ppSubLoop.c	(revision 23688)
+++ trunk/ppSub/src/ppSubLoop.c	(revision 23740)
@@ -17,9 +17,8 @@
 #include <pslib.h>
 #include <psmodules.h>
-#include <ppStats.h>
 
 #include "ppSub.h"
 
-bool ppSubLoop(pmConfig *config)
+bool ppSubLoop(pmConfig *config, ppSubData *data)
 {
     psAssert(config, "Require configuration.");
@@ -28,151 +27,146 @@
     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);
-            goto ERROR;
-        }
-        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;
     }
 
-    pmFPAfile *input = psMetadataLookupPtr(NULL, config->files, "PPSUB.INPUT");
-    if (!input) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Can't find input data!\n");
-        goto ERROR;
+    psTimerStart("PPSUB_MATCH");
+
+    if (!ppSubSetMasks(config)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to set masks.");
+        return false;
     }
 
-    pmFPAfile *reference = psMetadataLookupPtr(NULL, config->files, "PPSUB.REF");
-    if (!reference) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Can't find reference data!\n");
-        goto ERROR;
+    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;
     }
 
-    pmFPAfile *output = psMetadataLookupPtr(NULL, config->files, "PPSUB.OUTPUT");
-    if (!output) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Can't find output data!\n");
-        goto ERROR;
+    psMetadataAddF32(data->stats, PS_LIST_TAIL, "TIME_MATCH", 0, "Time to match PSFs",
+                     psTimerClear("PPSUB_MATCH"));
+
+    // Close input files
+    if (!ppSubFilesIterateUp(config, PPSUB_FILES_INPUT)) {
+        psError(PPSUB_ERR_IO, false, "Unable to close input files.");
+        return false;
     }
 
-    pmFPAview *view = pmFPAviewAlloc(0); // Pointer into FPA hierarchy
-
-    // Iterate over the FPA hierarchy
-    if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
-        goto ERROR;
+    // Set up subtraction files
+    if (!ppSubFilesIterateDown(config, PPSUB_FILES_SUB)) {
+        psError(PPSUB_ERR_IO, false, "Unable to set up subtraction files.");
+        return false;
     }
 
-    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 (!ppSubDefineOutput("PPSUB.OUTPUT", config)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to define output.");
+        return false;
+    }
+
+    if (!data->quality && !ppSubMakePSF(config, data)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to generate PSF.");
+        return false;
+    }
+
+    if (!ppSubReadoutSubtract(config)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to subtract images.");
+        return false;
+    }
+
+    // Close convolved files
+    if (!ppSubFilesIterateUp(config, PPSUB_FILES_PSF | PPSUB_FILES_CONV)) {
+        psError(PPSUB_ERR_IO, false, "Unable to close input files.");
+        return false;
+    }
+
+    // Higher order background subtraction using psphot
+    if (!ppSubBackground(config)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to subtract background.");
+        return false;
+    }
+
+    if (!ppSubFilesIterateDown(config, PPSUB_FILES_PHOT_SUB)) {
+        psError(PPSUB_ERR_IO, false, "Unable to set up photometry files.");
+        return false;
+    }
+
+    if (!data->quality && !ppSubReadoutPhotometry("PPSUB.OUTPUT", config, data)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry.");
+        return false;
+    }
+
+    if (!ppSubFilesIterateUp(config, PPSUB_FILES_PHOT_SUB)) {
+        psError(PPSUB_ERR_IO, false, "Unable to set up photometry files.");
+        return false;
+    }
+
+    // Perform statistics on the cell
+    if (!ppSubReadoutStats(config, data)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to collect statistics");
+        return false;
+    }
+
+    if (!ppSubReadoutJpeg(config)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to update.");
+        return false;
+    }
+
+    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 (data->inverse && !ppSubDefineOutput("PPSUB.INVERSE", config)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to define inverse.");
+            return false;
         }
 
-        if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) {
-            goto ERROR;
+        if (!ppSubReadoutInverse(config)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to invert images.");
+            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;
-            }
+        // 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;
         }
 
-        if (!pmFPAfileIOChecks(config, view, PM_FPA_AFTER)) {
-            goto ERROR;
+        if (!ppSubFilesIterateDown(config, PPSUB_FILES_PHOT_INV)) {
+            psError(PPSUB_ERR_IO, false, "Unable to set up inverse files.");
+            return false;
+        }
+
+        if (!data->quality && !ppSubReadoutPhotometry("PPSUB.INVERSE", config, data)) {
+            psError(PS_ERR_UNKNOWN, false, "Unable to perform photometry.");
+            return false;
+        }
+
+        // Close inverse subtraction files
+        if (!ppSubFilesIterateUp(config, PPSUB_FILES_INV | PPSUB_FILES_PHOT_INV)) {
+            psError(PPSUB_ERR_IO, false, "Unable to close subtraction files.");
+            return false;
+        }
+    } 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;
-    }
-
-    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");
+    psString dump_file = psMetadataLookupStr(NULL, config->arguments, "-dumpconfig");
     if (dump_file) {
         pmFPAfile *input = psMetadataLookupPtr(NULL, config->files, "PPSUB.INPUT"); // Input file
@@ -180,9 +174,4 @@
     }
 
-    psFree(data);
     return true;
-
-ERROR:
-    psFree(data);
-    return false;
 }
