Index: /trunk/ppStack/src/Makefile.am
===================================================================
--- /trunk/ppStack/src/Makefile.am	(revision 23575)
+++ /trunk/ppStack/src/Makefile.am	(revision 23576)
@@ -29,4 +29,5 @@
 	ppStackPrepare.c	\
 	ppStackConvolve.c	\
+	ppStackCombinePrepare.c	\
 	ppStackCombineInitial.c	\
 	ppStackReject.c		\
Index: /trunk/ppStack/src/ppStackCamera.c
===================================================================
--- /trunk/ppStack/src/ppStackCamera.c	(revision 23575)
+++ /trunk/ppStack/src/ppStackCamera.c	(revision 23576)
@@ -51,4 +51,11 @@
     bool status = false;                // Status of file definition
 
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // Recipe for ppSim
+    if (!recipe) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSTACK_RECIPE);
+        return false;
+    }
+    bool convolve = psMetadataLookupBool(NULL, recipe, "CONVOLVE"); // Convolve images before stack?
+
     psArray *runImages = pmFPAfileDefineMultipleFromRun(&status, NULL, config,
                                                         "PPSTACK.INPUT"); // Input images from previous run
@@ -98,5 +105,5 @@
         }
         if (!runSrc) {
-            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to define input sources from RUN metadta.");
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to define input sources from RUN metadata.");
             psFree(runImages);
             return false;
@@ -104,17 +111,20 @@
         psFree(runSrc);
 
-        psArray *runKernel = pmFPAfileDefineMultipleFromRun(&status, runImages, config,
-                                                            "PPSTACK.CONV.KERNEL"); // Convolution kernels
-        if (!status) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to define convolution kernels from RUN metadata.");
-            psFree(runImages);
-            return false;
-        }
-        if (!runSrc) {
-            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to define convolution kernels from RUN metadta.");
-            psFree(runImages);
-            return false;
-        }
-        psFree(runKernel);
+        if (convolve) {
+            psArray *runKernel = pmFPAfileDefineMultipleFromRun(&status, runImages, config,
+                                                                "PPSTACK.CONV.KERNEL"); // Convolution kernels
+            if (!status) {
+                psError(PS_ERR_UNKNOWN, false, "Unable to define convolution kernels from RUN metadata.");
+                psFree(runImages);
+                return false;
+            }
+            if (!runKernel) {
+                psError(PS_ERR_UNEXPECTED_NULL, true,
+                        "Unable to define convolution kernels from RUN metadata.");
+                psFree(runImages);
+                return false;
+            }
+            psFree(runKernel);
+        }
 
         psFree(runImages);
@@ -200,10 +210,12 @@
             }
 
-            pmFPAfile *kernel = pmFPAfileDefineOutput(config, imageFile->fpa, "PPSTACK.CONV.KERNEL");
-            if (!kernel) {
-                psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.CONV.KERNEL"));
-                return false;
-            }
-            kernel->save = true;
+            if (convolve) {
+                pmFPAfile *kernel = pmFPAfileDefineOutput(config, imageFile->fpa, "PPSTACK.CONV.KERNEL");
+                if (!kernel) {
+                    psError(PS_ERR_IO, false, _("Unable to generate output file from PPSTACK.CONV.KERNEL"));
+                    return false;
+                }
+                kernel->save = true;
+            }
 
             i++;
@@ -300,11 +312,4 @@
     }
     jpeg2->save = true;
-
-
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // Recipe for ppSim
-    if (!recipe) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find recipe %s", PPSTACK_RECIPE);
-        return false;
-    }
 
     // For photometry, we operate on the chip-mosaicked image
Index: /trunk/ppStack/src/ppStackCombineInitial.c
===================================================================
--- /trunk/ppStack/src/ppStackCombineInitial.c	(revision 23575)
+++ /trunk/ppStack/src/ppStackCombineInitial.c	(revision 23576)
@@ -23,40 +23,8 @@
     psTimerStart("PPSTACK_INITIAL");
 
-    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
-    psAssert(recipe, "We've thrown an error on this before.");
-
     psMetadata *ppsub = psMetadataLookupMetadata(NULL, config->recipes, "PPSUB"); // PPSUB recipe
     int overlap = 2 * psMetadataLookupS32(NULL, ppsub,
                                           "KERNEL.SIZE"); // Overlap by kernel size between consecutive scans
 
-    pmFPAview *view = NULL;             // View to readout
-
-    int row0, col0;                 // Offset for readout
-    int numCols, numRows;           // Size of readout
-    ppStackThread *thread = stack->threads->data[0]; // Representative thread
-    if (!pmReadoutStackSetOutputSize(&col0, &row0, &numCols, &numRows, thread->readouts)) {
-        psError(PS_ERR_UNKNOWN, false, "problem setting output readout size.");
-        return false;
-    }
-
-    pmFPAfileActivate(config->files, false, NULL);
-    ppStackFileActivation(config, PPSTACK_FILES_COMBINE, true);
-    view = ppStackFilesIterateDown(config);
-    if (!view) {
-        return false;
-    }
-
-    pmCell *outCell = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT"); // Output cell
-    options->outRO = pmReadoutAlloc(outCell); // Output readout
-    psFree(view);
-
-    psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad
-    psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
-    if (!pmReadoutStackDefineOutput(options->outRO, col0, row0, numCols, numRows, true, true, maskBad)) {
-        psError(PS_ERR_UNKNOWN, false, "Unable to prepare output.");
-        return false;
-    }
-
-    psFree(options->cells); options->cells = NULL;
 
     bool status;                    // Status of read
Index: /trunk/ppStack/src/ppStackCombinePrepare.c
===================================================================
--- /trunk/ppStack/src/ppStackCombinePrepare.c	(revision 23576)
+++ /trunk/ppStack/src/ppStackCombinePrepare.c	(revision 23576)
@@ -0,0 +1,47 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
+
+#include "ppStack.h"
+#include "ppStackLoop.h"
+
+bool ppStackCombinePrepare(ppStackThreadData *stack, ppStackOptions *options, pmConfig *config)
+{
+    psAssert(stack, "Require stack");
+    psAssert(options, "Require options");
+    psAssert(config, "Require configuration");
+
+    int row0, col0;                 // Offset for readout
+    int numCols, numRows;           // Size of readout
+    ppStackThread *thread = stack->threads->data[0]; // Representative thread
+    if (!pmReadoutStackSetOutputSize(&col0, &row0, &numCols, &numRows, thread->readouts)) {
+        psError(PS_ERR_UNKNOWN, false, "problem setting output readout size.");
+        return false;
+    }
+
+    pmFPAfileActivate(config->files, false, NULL);
+    ppStackFileActivation(config, PPSTACK_FILES_COMBINE, true);
+    pmFPAview *view = ppStackFilesIterateDown(config); // View to readout
+    if (!view) {
+        return false;
+    }
+
+    pmCell *outCell = pmFPAfileThisCell(config->files, view, "PPSTACK.OUTPUT"); // Output cell
+    options->outRO = pmReadoutAlloc(outCell); // Output readout
+    psFree(view);
+
+    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, PPSTACK_RECIPE); // ppStack recipe
+    psAssert(recipe, "We've thrown an error on this before.");
+    psString maskBadStr = psMetadataLookupStr(NULL, recipe, "MASK.BAD"); // Name of bits to mask for bad
+    psImageMaskType maskBad = pmConfigMaskGet(maskBadStr, config); // Bits to mask for bad pixels
+    if (!pmReadoutStackDefineOutput(options->outRO, col0, row0, numCols, numRows, true, true, maskBad)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to prepare output.");
+        return false;
+    }
+
+    return true;
+}
Index: /trunk/ppStack/src/ppStackLoop.c
===================================================================
--- /trunk/ppStack/src/ppStackLoop.c	(revision 23575)
+++ /trunk/ppStack/src/ppStackLoop.c	(revision 23576)
@@ -59,4 +59,13 @@
     if (!stack) {
         psError(PS_ERR_IO, false, "Unable to initialise stack threads.");
+        psFree(options);
+        return false;
+    }
+    psFree(options->cells); options->cells = NULL;
+
+    // Prepare for combination
+    if (!ppStackCombinePrepare(stack, options, config)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to prepare for combination.");
+        psFree(stack);
         psFree(options);
         return false;
Index: /trunk/ppStack/src/ppStackLoop.h
===================================================================
--- /trunk/ppStack/src/ppStackLoop.h	(revision 23575)
+++ /trunk/ppStack/src/ppStackLoop.h	(revision 23576)
@@ -30,4 +30,11 @@
 // Convolve inputs to match target PSF
 bool ppStackConvolve(
+    ppStackOptions *options,            // Options
+    pmConfig *config                    // Configuration
+    );
+
+// Prepare for combination
+bool ppStackCombinePrepare(
+    ppStackThreadData *stack,           // Stack
     ppStackOptions *options,            // Options
     pmConfig *config                    // Configuration
Index: /trunk/ppStack/src/ppStackReadout.c
===================================================================
--- /trunk/ppStack/src/ppStackReadout.c	(revision 23575)
+++ /trunk/ppStack/src/ppStackReadout.c	(revision 23576)
@@ -185,6 +185,5 @@
     assert(outRO);
     assert(readouts);
-    assert(rejected);
-    assert(readouts->n == rejected->n);
+    assert(!rejected || readouts->n == rejected->n);
     assert(mask && mask->n == readouts->n && mask->type.type == PS_TYPE_VECTOR_MASK);
     assert(weightings && weightings->n == readouts->n && weightings->type.type == PS_TYPE_F32);
@@ -207,10 +206,13 @@
     psArray *stack = psArrayAlloc(num); // Array for stacking
 
-    int numGood = num;                  // Number of good inputs: images that haven't been completely rejected
+    bool entire = (rejected ? false : true); // Combine entire image?
     for (int i = 0; i < num; i++) {
         pmReadout *ro = readouts->data[i];
-        if (!ro || !rejected->data[i] || mask->data.PS_TYPE_VECTOR_MASK_DATA[i]) {
-            // Image completely rejected
-            numGood--;
+        if (mask->data.U8[i] & (PPSTACK_MASK_REJECT | PPSTACK_MASK_BAD)) {
+            // Image completely rejected since previous combination
+            entire = true;
+            continue;
+        } else if (mask->data.U8[i]) {
+            // Image completely rejected before original combination
             continue;
         }
@@ -234,10 +236,10 @@
         pmStackData *data = pmStackDataAlloc(ro, weightings->data.F32[i],
                                              addVariance ? addVariance->data.F32[i] : NAN);
-        data->reject = psMemIncrRefCounter(rejected->data[i]);
+        data->reject = rejected ? psMemIncrRefCounter(rejected->data[i]) : NULL;
         stack->data[i] = data;
     }
 
     if (!pmStackCombine(outRO, stack, maskVal | maskBad, maskBad, 0, 0, NAN, NAN, NAN,
-                        numGood != num, useVariance, false)) {
+                        entire, useVariance, false)) {
         psError(PS_ERR_UNKNOWN, false, "Unable to combine input readouts.");
         psFree(stack);
Index: /trunk/ppStack/src/ppStackSetup.c
===================================================================
--- /trunk/ppStack/src/ppStackSetup.c	(revision 23575)
+++ /trunk/ppStack/src/ppStackSetup.c	(revision 23576)
@@ -14,5 +14,6 @@
 
 // Generate an array of input filenames
-static psArray *stackNameArray(pmConfig *config, // Configuration
+static psArray *stackNameArray(const ppStackOptions *options, // Stack options
+                               pmConfig *config, // Configuration
                                const char *name // Name of file
     )
@@ -21,19 +22,16 @@
     psAssert(config, "Require file name");
 
-    psString regex = NULL;             // Regular expression for selecting file
-    psStringAppend(&regex, "^%s$", name);
-    psMetadataIterator *iter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD, regex); // Iterator
-    psFree(regex);
-    psMetadataItem *item;               // Item from iteration
-    psArray *array = psArrayAlloc(BUFFER); // Array of file names
-    while ((item = psMetadataGetAndIncrement(iter))) {
-        psAssert(item->type == PS_DATA_UNKNOWN, "Should be this type");
-        pmFPAfile *file = item->data.V; // An input file
+    psArray *array = psArrayAllocEmpty(options->num); // Array with filenames
+    pmFPAview *view = pmFPAviewAlloc(0);// View to readout
+    view->chip = view->cell = view->readout = -1;
 
-        psString filename = psStringCopy(file->filename); // Filename of interest
+    for (int i = 0; i < options->num; i++) {
+        pmFPAfile *file = pmFPAfileSelectSingle(config->files, name, i); // File of interest
+
+        psString filename = pmFPAfileName(file, view, config); // Filename of interest
+        psAssert(filename, "Can't determine filename");
         psArrayAdd(array, array->n, filename);
         psFree(filename);               // Drop reference
     }
-    psFree(iter);
 
     return array;
@@ -114,7 +112,7 @@
         psFree(outputName);
     } else {
-        options->imageNames = stackNameArray(config, "PPSTACK.INPUT");
-        options->maskNames = stackNameArray(config, "PPSTACK.INPUT.MASK");
-        options->varianceNames = stackNameArray(config, "PPSTACK.INPUT.VARIANCE");
+        options->imageNames = stackNameArray(options, config, "PPSTACK.INPUT");
+        options->maskNames = stackNameArray(options, config, "PPSTACK.INPUT.MASK");
+        options->varianceNames = stackNameArray(options, config, "PPSTACK.INPUT.VARIANCE");
     }
 
Index: /trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileIO.c	(revision 23575)
+++ /trunk/psModules/src/camera/pmFPAfileIO.c	(revision 23576)
@@ -635,4 +635,74 @@
 }
 
+psString pmFPAfileName(const pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, NULL);
+    PS_ASSERT_PTR_NON_NULL(view, NULL);
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+
+    psString filename = pmFPAfileNameFromRule(file->filerule, file, view); // Filename, based on rule
+    if (!filename) {
+        psError(PS_ERR_IO, true, "Cannot determine file name from rule");
+        return false;
+    }
+
+    // indirect filenames: these come from a list on the command line or elsewhere
+    if (!strcasecmp(filename, "@FILES")) {
+        psString filesrc = pmFPAfileNameFromRule(file->filesrc, file, view); // Source of file name
+        if (!filesrc) {
+            psError(PS_ERR_IO, false, "error converting filesrc to name %s", file->filesrc);
+            return false;
+        }
+        psFree(filename);
+        filename = psMemIncrRefCounter(psMetadataLookupStr(NULL, file->names, filesrc));
+        if (!filename) {
+            psError(PS_ERR_IO, false, "filename lookup error (@FILES) for %s : %s", file->filesrc, filesrc);
+            psFree(filesrc);
+            return false;
+        }
+        psFree(filesrc);
+    }
+
+    // get name from detrend database
+    // file->detrend->detID contains the desired -det_id detID -iteration iter string
+    if (!strcasecmp(filename, "@DETDB")) {
+        if (!file->detrend) {
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find information about selected detrend.");
+            return false;
+        }
+        psMetadata *menu = psMetadataLookupMetadata(NULL, file->camera, "CLASSID"); // Menu of class IDs
+        if (!menu) {
+            psError(PS_ERR_IO, false, "Unable to find CLASSID metadata in camera configuration");
+            return false;
+        }
+        const char *rule = psMetadataLookupStr(NULL, menu, file->detrend->level); // Rule for class_id
+        if (!rule || strlen(rule) == 0) {
+            psError(PS_ERR_IO, false, "Unable to find %s in CLASSID in camera configuration",
+                    file->detrend->level);
+            return false;
+        }
+        psString classId = pmFPAfileNameFromRule(rule, file, view); // The class identifier, for pmDetrendFile
+        if (!classId) {
+            psError(PS_ERR_IO, false, "error converting CLASSID rule to name: %s\n", rule);
+            return false;
+        }
+
+        psTrace("psModules.camera", 6, "looking for detrend (%s, %s)\n", file->detrend->detID, classId);
+        psFree(filename);
+        filename = pmDetrendFile(file->detrend->detID, classId, config);
+        if (!filename) {
+            psError(PS_ERR_IO, false, "failed to find a valid detrend image for detID %s : classID %s",
+                    file->detrend->detID, classId);
+            psFree(classId);
+            return false;
+        }
+
+        psTrace("psModules.camera", 6, "got detrend file %s", filename);
+        psFree(classId);
+    }
+
+    return filename;
+}
+
 // open file (if not already opened).
 // this function is only called only within pmFPAfileRead or pmFPAfileWrite.
@@ -672,68 +742,9 @@
 
     // determine the file name, free a name allocated earlier
-    psFree (file->filename);
-    file->filename = pmFPAfileNameFromRule (file->filerule, file, view);
-    if (file->filename == NULL) {
-        psError(PS_ERR_IO, true, "Filename is NULL");
-        return false;
-    }
-
-    // indirect filenames: these come from a list on the command line or elsewhere
-    if (!strcasecmp (file->filename, "@FILES")) {
-        char *filesrc = pmFPAfileNameFromRule (file->filesrc, file, view);
-        if (filesrc == NULL) {
-            psError(PS_ERR_IO, false, "error converting filesrc to name %s\n", file->filesrc);
-            return false;
-        }
-
-        psFree (file->filename);
-        file->filename = psMetadataLookupStr (&status, file->names, filesrc);
-
-        if (file->filename == NULL) {
-            psError(PS_ERR_IO, true, "filename lookup error (@FILES) for %s : %s\n", file->filesrc, filesrc);
-            psFree (filesrc);
-            return false;
-        }
-        // psMetadataLookupStr just returns a view, file->filename must be protected
-        psMemIncrRefCounter (file->filename);
-        psFree (filesrc);
-    }
-
-    // get name from detrend database
-    // file->detrend->detID contains the desired -det_id detID -iteration iter string
-    if (!strcasecmp (file->filename, "@DETDB")) {
-        if (!file->detrend) {
-            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find information about selected detrend.");
-            return false;
-        }
-
-        psString classId = NULL;        // The class identifier, to pass to pmDetrendFile
-        psMetadata *menu = psMetadataLookupMetadata(&status, file->camera, "CLASSID"); // Menu of class IDs
-        if (!status || !menu) {
-            psError(PS_ERR_IO, false, "Unable to find CLASSID metadata in camera configuration");
-            return false;
-        }
-        const char *rule = psMetadataLookupStr(&status, menu, file->detrend->level); // Rule for class_id
-        if (!status || !rule || strlen(rule) == 0) {
-            psError(PS_ERR_IO, false, "Unable to find %s in CLASSID in camera configuration", file->detrend->level);
-            return false;
-        }
-        classId = pmFPAfileNameFromRule(rule, file, view);
-        if (!classId) {
-            psError(PS_ERR_IO, false, "error converting CLASSID rule to name: %s\n", rule);
-            return false;
-        }
-        psTrace ("psModules.camera", 6, "looking for detrend (%s, %s)\n", file->detrend->detID, classId);
-        psFree (file->filename);
-
-        file->filename = pmDetrendFile(file->detrend->detID, classId, config);
-        if (file->filename == NULL) {
-            psError(PS_ERR_IO, false, "failed to find a valid detrend image for detID %s : classID %s\n", file->detrend->detID, classId);
-            psFree (classId);
-            return false;
-        }
-
-        psTrace ("psModules.camera", 6, "got detrend file %s\n", file->filename);
-        psFree (classId);
+    psFree(file->filename);
+    file->filename = pmFPAfileName(file, view, config);
+    if (!file->filename) {
+        psError(PS_ERR_IO, true, "Unable to determine filename");
+        return false;
     }
 
Index: /trunk/psModules/src/camera/pmFPAfileIO.h
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileIO.h	(revision 23575)
+++ /trunk/psModules/src/camera/pmFPAfileIO.h	(revision 23576)
@@ -15,4 +15,7 @@
 /// @addtogroup Camera Camera Layout
 /// @{
+
+// Determine appropriate file name
+psString pmFPAfileName(const pmFPAfile *file, const pmFPAview *view, pmConfig *config);
 
 // open the real file corresponding to the given pmFPAfile appropriate to the current view
