Index: /trunk/ppImage/src/ppImageArguments.c
===================================================================
--- /trunk/ppImage/src/ppImageArguments.c	(revision 23267)
+++ /trunk/ppImage/src/ppImageArguments.c	(revision 23268)
@@ -108,8 +108,5 @@
 
     // the input file is a required argument; if not found, we will exit
-    bool status = pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
-    if (!status) {
-        usage ();
-    }
+    pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list");
 
     // if these command-line options are supplied, load the file name lists into config->arguments
@@ -142,10 +139,10 @@
         psArgumentRemove(argnum, &argc, argv);
 
-	unsigned int nFail = 0;
-	psMetadata *normlist = psMetadataConfigRead (NULL, &nFail, argv[argnum], false);
-	// XXX allow this file to be in nebulous?
+        unsigned int nFail = 0;
+        psMetadata *normlist = psMetadataConfigRead (NULL, &nFail, argv[argnum], false);
+        // XXX allow this file to be in nebulous?
 
         psMetadataAddMetadata(config->arguments, PS_LIST_TAIL, "NORMALIZATION.TABLE", 0, "Normalization to apply", normlist);
-	psFree (normlist);
+        psFree (normlist);
         psArgumentRemove(argnum, &argc, argv);
     }
Index: /trunk/ppImage/src/ppImageDefineFile.c
===================================================================
--- /trunk/ppImage/src/ppImageDefineFile.c	(revision 23267)
+++ /trunk/ppImage/src/ppImageDefineFile.c	(revision 23268)
@@ -5,51 +5,52 @@
 # include "ppImage.h"
 
-bool ppImageDefineFile (pmConfig *config, pmFPA *input, char *filerule, char *argname, pmFPAfileType fileType, pmDetrendType detrendType) {
+bool ppImageDefineFile(pmConfig *config, pmFPA *input, char *filerule, char *argname,
+                       pmFPAfileType fileType, pmDetrendType detrendType)
+{
+    bool status;
+    pmFPAfile *file = NULL;             // File to be defined
 
-    bool status;
-    pmFPAfile *file;
-
-    // look for the file on the argument list
-    file = pmFPAfileDefineFromArgs  (&status, config, filerule, argname);
-    if (!status) {
-	psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
-	return false;
+    if (!file) {
+        // look for the file on the RUN metadata
+        file = pmFPAfileDefineFromRun(&status, config, filerule);
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to load file definition");
+            return false;
+        }
     }
-    if (file) {
-	if (file->type != fileType) {
-	    psError(PS_ERR_IO, true, "%s is not of type %s", filerule, pmFPAfileStringFromType (fileType));
-	    return false;
-	}
-	return true;
+    if (!file) {
+        // look for the file on the argument list
+        file = pmFPAfileDefineFromArgs(&status, config, filerule, argname);
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to load file definition");
+            return false;
+        }
+    }
+    if (!file) {
+        // look for the file in the camera config table
+        file = pmFPAfileDefineFromConf(&status, config, filerule);
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to load file definition");
+            return false;
+        }
+    }
+    if (!file) {
+        // look for the file to be loaded from the detrend database
+        file = pmFPAfileDefineFromDetDB(&status, config, filerule, input, detrendType);
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to load file definition");
+            return false;
+        }
     }
 
-    // look for the file in the camera config table
-    file = pmFPAfileDefineFromConf  (&status, config, filerule);
-    if (!status) {
-	psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
-	return false;
-    }
-    if (file) {
-	if (file->type != fileType) {
-	    psError(PS_ERR_IO, true, "%s is not of type %s", filerule, pmFPAfileStringFromType (fileType));
-	    return false;
-	}
-	return true;
+    if (!file) {
+        return false;
     }
 
-    // look for the file to be loaded from the detrend database
-    file = pmFPAfileDefineFromDetDB (&status, config, filerule, input, detrendType);
-    if (!status) {
-	psError (PS_ERR_UNKNOWN, false, "failed to load file definition");
-	return false;
+    if (file->type != fileType) {
+        psError(PS_ERR_IO, true, "%s is not of type %s", filerule, pmFPAfileStringFromType(fileType));
+        return false;
     }
-    if (file) {
-	if (file->type != fileType) {
-	    psError(PS_ERR_IO, true, "%s is not of type %s", filerule, pmFPAfileStringFromType (fileType));
-	    return false;
-	}
-	return true;
-    }
-    return false;
+    return true;
 }
 
Index: /trunk/ppImage/src/ppImageParseCamera.c
===================================================================
--- /trunk/ppImage/src/ppImageParseCamera.c	(revision 23267)
+++ /trunk/ppImage/src/ppImageParseCamera.c	(revision 23268)
@@ -9,44 +9,16 @@
     bool status = false;
 
-    // the input image defines the camera, and all recipes and options the follow
-    pmFPAfile *input = pmFPAfileDefineFromArgs (&status, config, "PPIMAGE.INPUT", "INPUT");
-    if (!status || !input) {
-        psError(PS_ERR_IO, false, "Failed to build FPA from PPIMAGE.INPUT");
-        return NULL;
-    }
-    if (input->type != PM_FPA_FILE_IMAGE) {
-        psError(PS_ERR_IO, true, "PPIMAGE.INPUT is not of type IMAGE");
-        return NULL;
-    }
-
-    // if MASK or VARIANCE was supplied on command line, bind files to 'input'.
-    // the mask and variance will be mosaicked with the image
-    pmFPAfile *inputMask = pmFPAfileBindFromArgs(&status, input, config, "PPIMAGE.INPUT.MASK", "PPIMAGE.INPUT.MASK");
-    if (!status) {
-        psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
-        return NULL;
-    }
-    if (inputMask) {
-      if (inputMask->type != PM_FPA_FILE_MASK) {
-        psError(PS_ERR_IO, true, "PPIMAGE.INPUT.MASK is not of type MASK");
-        return NULL;
-      }
-    }
-
-    pmFPAfile *inputVariance = pmFPAfileBindFromArgs(&status, input, config, "PPIMAGE.INPUT.VARIANCE", "PPIMAGE.INPUT.VARIANCE");
-    if (!status) {
-        psError (PS_ERR_UNKNOWN, false, "failed to load find definition");
-        return NULL;
-    }
-    if (inputVariance && inputVariance->type != PM_FPA_FILE_VARIANCE) {
-        psError(PS_ERR_IO, true, "PPIMAGE.INPUT.VARIANCE is not of type VARIANCE");
-        return NULL;
-    }
+    if (!ppImageDefineFile(config, NULL, "PPIMAGE.INPUT", "INPUT", PM_FPA_FILE_IMAGE, PM_DETREND_TYPE_NONE)) {
+        psError(PS_ERR_IO, false, "Can't find an input image source");
+        return NULL;
+    }
+    pmFPAfile *input = psMetadataLookupPtr(NULL, config->files, "PPIMAGE.INPUT"); // Input file
+    psAssert(input, "We just put it there!");
 
     // add recipe options supplied on command line
-    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, RECIPE_NAME);
+    psMetadata *recipe  = psMetadataLookupPtr(&status, config->recipes, RECIPE_NAME);
 
     // parse the options from the metadata format to the ppImageOptions structure
-    ppImageOptions *options = ppImageOptionsParse (config);
+    ppImageOptions *options = ppImageOptionsParse(config);
 
     // the following are defined from the argument list, if given,
@@ -54,27 +26,33 @@
     // not all input or output images are used in a given recipe
     if (options->doBias) {
-        if (!ppImageDefineFile (config, input->fpa, "PPIMAGE.BIAS", "BIAS", PM_FPA_FILE_IMAGE, PM_DETREND_TYPE_BIAS)) {
-            psError (PS_ERR_IO, false, "Can't find a bias image source");
-            psFree (options);
+        if (!ppImageDefineFile(config, input->fpa, "PPIMAGE.BIAS", "BIAS",
+                               PM_FPA_FILE_IMAGE, PM_DETREND_TYPE_BIAS)) {
+            psError(PS_ERR_IO, false, "Can't find a bias image source");
+            psFree(options);
             return NULL;
         }
     }
     if (options->doDark) {
-        if (!ppImageDefineFile (config, input->fpa, "PPIMAGE.DARK", "DARK", PM_FPA_FILE_DARK, PM_DETREND_TYPE_DARK)) {
-            psError (PS_ERR_IO, false, "Can't find a dark image source");
-            psFree (options);
+        if (!ppImageDefineFile(config, input->fpa, "PPIMAGE.DARK", "DARK",
+                               PM_FPA_FILE_DARK, PM_DETREND_TYPE_DARK)) {
+            psError(PS_ERR_IO, false, "Can't find a dark image source");
+            psFree(options);
             return NULL;
         }
     }
     if (options->doMask) {
-
-        if (!ppImageDefineFile (config, input->fpa, "PPIMAGE.MASK", "MASK", PM_FPA_FILE_MASK, PM_DETREND_TYPE_MASK)) {
-            psError (PS_ERR_IO, false, "Can't find a mask image source");
-            psFree (options);
-            return NULL;
-        }
+        if (!ppImageDefineFile(config, input->fpa, "PPIMAGE.MASK", "MASK",
+                               PM_FPA_FILE_MASK, PM_DETREND_TYPE_MASK)) {
+            psError(PS_ERR_IO, false, "Can't find a mask image source");
+            psFree(options);
+            return NULL;
+        }
+
+#if 0
+        // I think this is now done automatically in the pmFPAfileDefine and pmFPAfileIOChecks -- PAP.
+
         // XXX have ppImageDefineFile return the pmFPAfile?
         pmFPAfile *mask = psMetadataLookupPtr(&status, config->files, "PPIMAGE.MASK");
-        psAssert (mask, "mask not defined?  not possible!");
+        psAssert(mask, "Just defined the mask!");
 
         // Need to read the names of bit masks from the mask header and set them in the
@@ -84,5 +62,5 @@
             // XXX need to load the mask bit names from one of the headers
             // this grabs the first available hdu : no guarantee that it will be valid, though
-            pmHDU *hdu = pmHDUGetFirst (mask->fpa);
+            pmHDU *hdu = pmHDUGetFirst(mask->fpa);
             if (!hdu) {
                 psError(PS_ERR_IO, true, "no valid HDU for PPIMAGE.INPUT.MASK");
@@ -90,14 +68,16 @@
             }
             // XXX is this consistent with the pmConfigMaskReadHeader call above?
-            if (!pmConfigMaskReadHeader (config, hdu->header)) {
+            if (!pmConfigMaskReadHeader(config, hdu->header)) {
                 psError(PS_ERR_IO, false, "error in mask bits");
                 return NULL;
             }
         }
+#endif
     }
     if (options->doShutter) {
-        if (!ppImageDefineFile (config, input->fpa, "PPIMAGE.SHUTTER", "SHUTTER", PM_FPA_FILE_IMAGE, PM_DETREND_TYPE_SHUTTER)) {
-            psError (PS_ERR_IO, false, "Can't find a shutter image source");
-            psFree (options);
+        if (!ppImageDefineFile(config, input->fpa, "PPIMAGE.SHUTTER", "SHUTTER",
+                               PM_FPA_FILE_IMAGE, PM_DETREND_TYPE_SHUTTER)) {
+            psError(PS_ERR_IO, false, "Can't find a shutter image source");
+            psFree(options);
             return NULL;
         }
@@ -105,15 +85,16 @@
 
     if (options->doFlat) {
-        if (!ppImageDefineFile (config, input->fpa, "PPIMAGE.FLAT", "FLAT", PM_FPA_FILE_IMAGE, PM_DETREND_TYPE_FLAT)) {
-            psError (PS_ERR_IO, false, "Can't find a flat image source");
-            psFree (options);
-            return NULL;
-        }
-    }
-
-    int nThreads = psMetadataLookupS32 (&status, config->arguments, "NTHREADS");
+        if (!ppImageDefineFile(config, input->fpa, "PPIMAGE.FLAT", "FLAT",
+                               PM_FPA_FILE_IMAGE, PM_DETREND_TYPE_FLAT)) {
+            psError(PS_ERR_IO, false, "Can't find a flat image source");
+            psFree(options);
+            return NULL;
+        }
+    }
+
+    int nThreads = psMetadataLookupS32(&status, config->arguments, "NTHREADS");
     if (nThreads > 0) {
-        int nScanRows = psMetadataLookupS32 (&status, recipe, "SCAN.ROWS");
-        pmDetrendSetThreadTasks (nScanRows);
+        int nScanRows = psMetadataLookupS32(&status, recipe, "SCAN.ROWS");
+        pmDetrendSetThreadTasks(nScanRows);
     }
 
@@ -166,5 +147,6 @@
 skip_fringe:
     if (options->doFringe) {
-        if (!ppImageDefineFile (config, input->fpa, "PPIMAGE.FRINGE", "FRINGE", PM_FPA_FILE_FRINGE, PM_DETREND_TYPE_FRINGE)) {
+        if (!ppImageDefineFile(config, input->fpa, "PPIMAGE.FRINGE", "FRINGE",
+                               PM_FPA_FILE_FRINGE, PM_DETREND_TYPE_FRINGE)) {
             psError (PS_ERR_IO, false, "Can't find a fringe image source");
             return NULL;
@@ -283,5 +265,6 @@
         // define associated psphot input/output files
         if (!psphotDefineFiles (config, psphotInput)) {
-            psError(PSPHOT_ERR_CONFIG, false, "Trouble defining the additional input/output files for psphot");
+            psError(PSPHOT_ERR_CONFIG, false,
+                    "Trouble defining the additional input/output files for psphot");
             return false;
         }
@@ -291,23 +274,25 @@
     if (options->doAstromChip || options->doAstromMosaic) {
         if (!options->doPhotom) {
-            psError (PSASTRO_ERR_CONFIG, false, "photometry mode is not selected; it is required for astrometry");
+            psError(PSASTRO_ERR_CONFIG, false,
+                    "Photometry mode is not selected; it is required for astrometry");
             return false;
         }
 
-        pmFPAfile *psphotOutput = psMetadataLookupPtr (&status, config->files, "PSPHOT.OUTPUT");
-        PS_ASSERT (psphotOutput, false);
-
-        pmFPAfile *psastroInput = pmFPAfileDefineInput (config, psphotOutput->fpa, NULL, "PSASTRO.INPUT");
-        PS_ASSERT (psastroInput, false);
+        pmFPAfile *psphotOutput = psMetadataLookupPtr(&status, config->files, "PSPHOT.OUTPUT");
+        PS_ASSERT(psphotOutput, false);
+
+        pmFPAfile *psastroInput = pmFPAfileDefineInput(config, psphotOutput->fpa, NULL, "PSASTRO.INPUT");
+        PS_ASSERT(psastroInput, false);
         psastroInput->mode = PM_FPA_MODE_REFERENCE;
 
         // define associated psphot input/output files
-        if (!psastroDefineFiles (config, psastroInput)) {
-            psError(PSPHOT_ERR_CONFIG, false, "Trouble defining the additional input/output files for psastro");
+        if (!psastroDefineFiles(config, psastroInput)) {
+            psError(PSPHOT_ERR_CONFIG, false,
+                    "Trouble defining the additional input/output files for psastro");
             return false;
         }
 
         // deactivate the psastro files, reactive when needed
-        pmFPAfileActivate (config->files, false, "PSASTRO.OUTPUT");
+        pmFPAfileActivate(config->files, false, "PSASTRO.OUTPUT");
     }
 
@@ -325,7 +310,7 @@
 
     // outImage is used as a carrier: input to chipImage -> require the data to remain at the CHIP level
-    outImage->freeLevel = PS_MIN (outImage->freeLevel, PM_FPA_LEVEL_CHIP);
+    outImage->freeLevel = PS_MIN(outImage->freeLevel, PM_FPA_LEVEL_CHIP);
     outImage->dataLevel = outImage->freeLevel;
-    outImage->fileLevel = PS_MIN (outImage->fileLevel, outImage->dataLevel);
+    outImage->fileLevel = PS_MIN(outImage->fileLevel, outImage->dataLevel);
 
     // outMask and outVariance must be freed at the same level as outImage (all freed by pmFPAFreeData)
@@ -342,8 +327,9 @@
 
     // the input data is the same as the outImage data : force the free levels to match
-    input->freeLevel = PS_MIN (outImage->freeLevel, input->freeLevel);
+    input->freeLevel = PS_MIN(outImage->freeLevel, input->freeLevel);
 
     // define the binned target files (which may just be carriers for some camera configurations)
-    pmFPAfile *bin1 = pmFPAfileDefineFromFPA (config, chipImage->fpa, options->xBin1, options->yBin1, "PPIMAGE.BIN1");
+    pmFPAfile *bin1 = pmFPAfileDefineFromFPA(config, chipImage->fpa, options->xBin1, options->yBin1,
+                                             "PPIMAGE.BIN1");
     if (!bin1) {
         psError(PS_ERR_IO, false, _("Unable to generate new file from PPIMAGE.BIN1"));
@@ -357,5 +343,6 @@
     }
 
-    pmFPAfile *bin2 = pmFPAfileDefineFromFPA (config, chipImage->fpa, options->xBin2, options->yBin2, "PPIMAGE.BIN2");
+    pmFPAfile *bin2 = pmFPAfileDefineFromFPA(config, chipImage->fpa, options->xBin2, options->yBin2,
+                                             "PPIMAGE.BIN2");
     if (!bin2) {
         psError(PS_ERR_IO, false, _("Unable to generate new file from PPIMAGE.BIN2"));
@@ -373,5 +360,5 @@
     bin2->freeLevel = PM_FPA_LEVEL_FPA;
 
-    pmFPAfile *jpg1 = pmFPAfileDefineOutput (config, byFPA1->fpa, "PPIMAGE.JPEG1");
+    pmFPAfile *jpg1 = pmFPAfileDefineOutput(config, byFPA1->fpa, "PPIMAGE.JPEG1");
     if (!jpg1) {
         psError(PS_ERR_IO, false, _("Unable to generate new file from PPIMAGE.JPEG1"));
@@ -384,5 +371,5 @@
         return NULL;
     }
-    pmFPAfile *jpg2 = pmFPAfileDefineOutput (config, byFPA2->fpa, "PPIMAGE.JPEG2");
+    pmFPAfile *jpg2 = pmFPAfileDefineOutput(config, byFPA2->fpa, "PPIMAGE.JPEG2");
     if (!jpg2) {
         psError(PS_ERR_IO, false, _("Unable to generate new file from PPIMAGE.JPEG2"));
@@ -404,5 +391,5 @@
     // Chip selection: turn on only the chips specified (pass status to suppress missing-key log msg)
     char *chipLine = psMetadataLookupStr(&status, config->arguments, "CHIP_SELECTIONS");
-    psArray *chips = psStringSplitArray (chipLine, ",", false);
+    psArray *chips = psStringSplitArray(chipLine, ",", false);
     if (chips->n > 0) {
         pmFPASelectChip (input->fpa, -1, true); // deselect all chips
@@ -454,5 +441,5 @@
     if (psTraceGetLevel("ppImage.config") > 0) {
         // Get a look inside all the files.
-        psMetadataIterator *filesIter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD, NULL); // Iterator
+        psMetadataIterator *filesIter = psMetadataIteratorAlloc(config->files, PS_LIST_HEAD, NULL);
         psMetadataItem *item;               // Item from iteration
         fprintf(stderr, "Files:\n");
Index: /trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 23267)
+++ /trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 23268)
@@ -11,4 +11,5 @@
 #include "pmConfig.h"
 #include "pmConfigMask.h"
+#include "pmConfigRun.h"
 #include "pmDetrendDB.h"
 
@@ -216,16 +217,4 @@
         file->imageId = config->imageId;
     }
-
-    // XXX this seems a bit of a hack: use the cameraName to determine the mosaic level...
-    # if (0)
-    if (cameraName) {
-        if (!strcmp(cameraName + strlen(cameraName) - 5, "-CHIP")) {
-            file->mosaicLevel = PM_FPA_LEVEL_CHIP;
-        }
-        if (!strcmp(cameraName + strlen(cameraName) - 5, "-FPA")) {
-            file->mosaicLevel = PM_FPA_LEVEL_FPA;
-        }
-    }
-    # endif
 
     // Use the format we were told to, the format specified in the file rule, or default to the default format
@@ -383,13 +372,15 @@
     }
 
-    psTrace ("psModules.camera", 5, "file: %s, format: %s, fileLevel: %s, extLevel: %s, dataLevel: %s, freeLevel: %s\n",
-             file->name, file->formatName, pmFPALevelToName (file->fileLevel), pmFPALevelToName(extLevel), pmFPALevelToName (file->dataLevel), pmFPALevelToName (file->freeLevel));
+    psTrace("psModules.camera", 5,
+            "file: %s, format: %s, fileLevel: %s, extLevel: %s, dataLevel: %s, freeLevel: %s\n",
+            file->name, file->formatName, pmFPALevelToName(file->fileLevel), pmFPALevelToName(extLevel),
+            pmFPALevelToName(file->dataLevel), pmFPALevelToName(file->freeLevel));
 
     // add argument-supplied OUTPUT name to this file
     char *outname = psMetadataLookupStr(&status, config->arguments, "OUTPUT");
-    psMetadataAddStr(file->names, PS_LIST_TAIL, "OUTPUT", PS_META_NO_REPLACE, "", outname);
+    psMetadataAddStr(file->names, PS_LIST_TAIL, "OUTPUT", PS_META_NO_REPLACE, "Output file name", outname);
 
     // place the resulting file in the config system
-    psMetadataAddPtr (config->files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "", file);
+    psMetadataAddPtr(config->files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "Output file", file);
     psFree(file);                       // we free this copy of file, but 'files' still has a copy
     return file;                        // the returned value is a view into the version on 'files'
@@ -426,11 +417,197 @@
 }
 
-// search for argname on the config->argument list
-// construct an FPA based on the files in this list (must represent a single FPA)
-// built the association between the FPA elements (CHIP/CELL) and the files
-// define the pmFPAfile filename and bind it to this FPA
-// save the pmFPAfile on config->files
-// return the pmFPAfile (a view to the one saved on config->files)
-pmFPAfile *pmFPAfileDefineFromArgs(bool *success, pmConfig *config, const char *filename, const char *argname)
+
+/// Define a file from an array of filenames
+static pmFPAfile *fpaFileDefineFromArray(pmConfig *config, // Configuration
+                                         pmFPAfile *bind, // File to bind to, or NULL
+                                         const char *name, // Name of file
+                                         const psArray *filenames // Array of file names
+    )
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
+
+    pmFPA *fpa = NULL;                  // FPA for file
+    psMetadata *format = NULL;          // Camera format configuration
+    psString formatName = NULL;         // Name of camera format
+    psString cameraName = NULL;         // Name of camera
+    pmFPALevel fileLevel = PM_FPA_LEVEL_NONE; // Level for files
+    psMetadata *phu = NULL;             // Primary header
+    if (bind) {
+        // Use the FPA we're binding to
+        fpa = psMemIncrRefCounter(bind->fpa);
+        fileLevel = bind->fileLevel;
+    } else {
+        // Need to generate an FPA
+        psString realName = pmConfigConvertFilename(filenames->data[0], config, false, false);
+        if (!realName) {
+            psError(PS_ERR_IO, false, "Failed to convert file name %s", (char *)filenames->data[0]);
+            return NULL;
+        }
+
+        // load the header of the first image
+        // EXTWORD (fits->extword) is not relevant to the PHU
+        psFits *fits = psFitsOpen(realName, "r"); // FITS file
+        if (!fits) {
+            psError(PS_ERR_IO, false, "Failed to open file %s", realName);
+            psFree(realName);
+            return NULL;
+        }
+        phu = psFitsReadHeader (NULL, fits); // Primary header
+        if (!phu) {
+            psError(PS_ERR_IO, false, "Failed to read file header %s", realName);
+            psFree(realName);
+            return NULL;
+        }
+        psFitsClose(fits);
+
+        // Determine the current format from the header; determine camera if not specified already.
+        psMetadata *camera = NULL;      // Camera configuration
+        format = pmConfigCameraFormatFromHeader(&camera, &cameraName, &formatName, config, phu, true);
+        if (!format) {
+            psError(PS_ERR_IO, false, "Failed to determine camera format for %s", realName);
+            psFree(camera);
+            psFree(formatName);
+            psFree(realName);
+            psFree(phu);
+            psFree(phu);
+            return NULL;
+        }
+
+        fileLevel = pmFPAPHULevel(format);
+        if (fileLevel == PM_FPA_LEVEL_NONE) {
+            psError(PS_ERR_IO, true, "Unable to determine file level for %s", realName);
+            psFree(camera);
+            psFree(formatName);
+            psFree(realName);
+            psFree(phu);
+            return NULL;
+        }
+
+        // build the template fpa, set up the basic view
+        // XXX do we want this to be the baseCamera name or the metaCamera name?
+        fpa = pmFPAConstruct(camera, cameraName);
+        psFree(camera);
+        if (!fpa) {
+            psError(PS_ERR_IO, false, "Failed to construct FPA from %s", realName);
+            psFree(formatName);
+            psFree(realName);
+            psFree(format);
+            psFree(phu);
+            return NULL;
+        }
+        psFree(realName);
+    }
+
+    // load the given filerule (from config->camera) and bind it to the fpa
+    // the returned file is just a view to the entry on config->files
+    pmFPAfile *file = pmFPAfileDefineInput(config, fpa, cameraName, name); // File, to return
+    if (!file) {
+        psError(PS_ERR_IO, false, "File %s not defined", name);
+        psFree(formatName);
+        psFree(format);
+        psFree(fpa);
+        psFree(phu);
+        return NULL;
+    }
+    psFree(cameraName);
+    psFree(fpa);                        // Drop reference
+
+    file->format = format;
+    file->formatName = formatName;
+    file->fileLevel = fileLevel;
+
+    // We use the filerule and filesrc to identify the files in the file->names data
+    psFree(file->filerule); // this is set in pmFPAfileDefineInput
+    file->filerule = psStringCopy("@FILES");
+    file->filesrc = psStringCopy("{CHIP.NAME}.{CELL.NAME}");
+
+    if (file->type == PM_FPA_FILE_MASK) {
+        if (!pmConfigMaskReadHeader(config, phu)) {
+            psError(PS_ERR_IO, false, "Error reading mask bits");
+            psFree(phu);
+            return NULL;
+        }
+    }
+
+    // Examine the list of input files and validate their cameras
+    // Associate each filename with an element of the FPA
+    // Save the association on file->names
+    for (int i = 0; i < filenames->n; i++) {
+        // Check that the file corresponds to the same camera and format
+        if (!phu) {
+            psString realName = pmConfigConvertFilename(filenames->data[i], config, false, false);
+            if (!realName) {
+                psError(PS_ERR_IO, false, "Failed to convert file name %s", (char*)filenames->data[i]);
+                return NULL;
+            }
+            psFits *fits = psFitsOpen(realName, "r"); // FITS file
+            if (!fits) {
+                psError(PS_ERR_IO, false, "Failed to open file %s", realName);
+                psFree(realName);
+                return NULL;
+            }
+            phu = psFitsReadHeader(NULL, fits);
+            psFitsClose(fits);
+            if (!phu) {
+                psError(PS_ERR_IO, false, "Failed to read file header %s", realName);
+                psFree(realName);
+                return NULL;
+            }
+            psFree(realName);
+        }
+
+        if (bind || i > 0) {
+            if (format) {
+                bool valid = false;
+                if (!pmConfigValidateCameraFormat(&valid, format, phu)) {
+                    psError(PS_ERR_UNKNOWN, false, "Error in config scripts\n");
+                    psFree(phu);
+                    return NULL;
+                }
+                if (!valid) {
+                    psError(PS_ERR_IO, false, "File %s is not from the required camera",
+                            (char*)filenames->data[i]);
+                    psFree(phu);
+                    return NULL;
+                }
+            } else {
+                format = pmConfigCameraFormatFromHeader(NULL, NULL, NULL, config, phu, true);
+                if (!format) {
+                    psError(PS_ERR_IO, false, "Failed to determine camera format from %s",
+                            (char*)filenames->data[i]);
+                    psFree(phu);
+                    return NULL;
+                }
+            }
+        }
+
+        // Set the view to the corresponding entry for this phu
+        pmFPAview *view = NULL;         // View to PHU
+        if (bind) {
+            view = pmFPAIdentifySourceFromHeader(bind->fpa, phu, format);
+        } else {
+            view = pmFPAAddSourceFromHeader(fpa, phu, format);
+        }
+        psFree(phu);
+        phu = NULL;
+        if (!view) {
+            psError(PS_ERR_IO, false, "Unable to determine source for %s", name);
+            return NULL;
+        }
+
+        // Associate the filename with the FPA element
+        psString location = pmFPAfileNameFromRule(file->filesrc, file, view);
+        psFree(view);
+        psMetadataAddStr(file->names, PS_LIST_TAIL, location, 0, "Location of file", filenames->data[i]);
+        psFree(location);
+    }
+
+    return file;
+}
+
+
+pmFPAfile *pmFPAfileDefineFromArgs(bool *success, pmConfig *config,
+                                   const char *filename, const char *argname)
 {
     PS_ASSERT_PTR_NON_NULL(config, NULL);
@@ -438,20 +615,7 @@
     PS_ASSERT_STRING_NON_EMPTY(argname, NULL);
 
-    bool status;
-    pmFPA *fpa = NULL;
-    psFits *fits = NULL;
-    pmFPAfile *file = NULL;
-    psMetadata *phu = NULL;
-    psMetadata *format = NULL;
-    psMetadata *camera = NULL;
-    psString formatName = NULL;
-
-    // use success to identify valid exit conditions (as opposed to 'argument not supplied')
-    if (success) {
-        *success = false;
-    }
-
-    // we search the argument data for the named fileset (argname)
-    psArray *infiles = psMetadataLookupPtr(&status, config->arguments, argname);
+    // Search the argument data for the named fileset (argname)
+    bool status;                        // Status of MD lookup
+    psArray *filenames = psMetadataLookupPtr(&status, config->arguments, argname); // Filenames for file
     if (!status) {
         if (success) {
@@ -460,182 +624,23 @@
         return NULL;
     }
-    if (infiles->n < 1) {
-        psError(PS_ERR_IO, false, "Found n == %ld files in %s in arguments\n", infiles->n, argname);
-        return NULL;
-    }
-
-    // this function is implicitly an INPUT operation: do not create the file
-    psString realName = pmConfigConvertFilename (infiles->data[0], config, false, false);
-    if (!realName) {
-        psError(PS_ERR_IO, false, "Failed to convert file name %s\n", (char *) infiles->data[0]);
-        return NULL;
-    }
-
-    // load the header of the first image
-    // EXTWORD (fits->extword) is not relevant to the PHU
-    fits = psFitsOpen (realName, "r");
-    if (!fits) {
-        psError(PS_ERR_IO, false, "Failed to open file %s\n", realName);
-        psFree (realName);
-        return NULL;
-    }
-    phu = psFitsReadHeader (NULL, fits);
-
-    if (!phu) {
-        psError(PS_ERR_IO, false, "Failed to read file header %s\n", realName);
-        psFree (realName);
-        return NULL;
-    }
-    psFitsClose(fits);
-
-    // Determine the current format from the header; Determine camera if not specified already.
-    // the returned pointers 'camera' and 'formatName' are allocated here
-    psString cameraName = NULL;
-    format = pmConfigCameraFormatFromHeader(&camera, &cameraName, &formatName, config, phu, true);
-    if (!format) {
-        psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", realName);
-        psFree(phu);
-        psFree(camera);
-        psFree(formatName);
-        psFree(realName);
-        return NULL;
-    }
-
-    // build the template fpa, set up the basic view
-    // XXX do we want this to be the baseCamera name or the metaCamera name?
-    fpa = pmFPAConstruct(camera, cameraName);
-    if (!fpa) {
-        psError(PS_ERR_IO, false, "Failed to construct FPA from %s", realName);
-        psFree(phu);
-        psFree(camera);
-        psFree(formatName);
-        psFree(realName);
-        psFree(format);
-        return NULL;
-    }
-    psFree (realName);
-    psFree (camera);
-
-    // load the given filerule (from config->camera) and bind it to the fpa
-    // the returned file is just a view to the entry on config->files
-    file = pmFPAfileDefineInput(config, fpa, cameraName, filename);
-    if (!file) {
-        psError(PS_ERR_IO, false, "file %s not defined\n", filename);
-        psFree(phu);
-        psFree(formatName);
-        psFree(format);
-        psFree(fpa);
-        return NULL;
-    }
-    psFree (cameraName);
-    psFree (file->filerule); // this is set in pmFPAfileDefineInput
-
-    file->format = format;
-    file->formatName = formatName;
-    file->filerule = psStringCopy("@FILES");
-    file->filesrc = psStringCopy("{CHIP.NAME}.{CELL.NAME}");
-    // we use the above rules to identify these files in the file->names data
-
-    file->fileLevel = pmFPAPHULevel(format);
-    if (file->fileLevel == PM_FPA_LEVEL_NONE) {
-        psError(PS_ERR_IO, true, "Unable to determine file level for %s\n", file->name);
-        psFree(phu);
-        psFree(fpa);
-        return NULL;
-    }
-
-    if (file->type == PM_FPA_FILE_MASK) {
-        if (!pmConfigMaskReadHeader (config, phu)) {
-            psError(PS_ERR_IO, false, "error in mask bits");
-            return NULL;
-        }
-    }
-
-    // examine the list of input files and validate their cameras
-    // associated each filename with an element of the FPA
-    // save the association on file->names
-    for (int i = 0; i < infiles->n; i++) {
-        if (i > 0) {
-            // this function is implicitly an INPUT operation: do not create the file
-            psString realName = pmConfigConvertFilename (infiles->data[i], config, false, false);
-            if (!realName) {
-                psError(PS_ERR_IO, false, "Failed to convert file name %s", (char *) infiles->data[i]);
-                psFree(phu);
-                psFree(fpa);
-                return NULL;
-            }
-            // EXTWORD (fits->extword) is not relevant to the PHU
-            fits = psFitsOpen (realName, "r");
-            if (!fits) {
-                psError(PS_ERR_IO, false, "Failed to open file %s\n", realName);
-                psFree(realName);
-                psFree(phu);
-                psFree(fpa);
-                return NULL;
-            }
-            phu = psFitsReadHeader (NULL, fits);
-            if (!phu) {
-                psError(PS_ERR_IO, false, "Failed to read file header %s", realName);
-                psFree(realName);
-                psFitsClose(fits);
-                psFree(phu);
-                psFree(fpa);
-                return NULL;
-            }
-            bool valid = false;
-            if (!pmConfigValidateCameraFormat (&valid, format, phu)) {
-                psError(PS_ERR_UNKNOWN, false, "Error in config scripts\n");
-                psFree(realName);
-                psFitsClose(fits);
-                psFree(phu);
-                psFree(fpa);
-                return NULL;
-            }
-            if (!valid) {
-                psError(PS_ERR_IO, false, "file %s is not from the required camera", realName);
-                psFree(realName);
-                psFitsClose(fits);
-                psFree(phu);
-                psFree(fpa);
-                return NULL;
-            }
-            psFree(realName);
-            psFitsClose(fits);
-        }
-
-        // set the view to the corresponding entry for this phu
-        pmFPAview *view = pmFPAAddSourceFromHeader (fpa, phu, format);
-        if (!view) {
-            psError(PS_ERR_IO, false, "Unable to determine source for %s", file->name);
-            psFree(phu);
-            psFree(fpa);
-            return NULL;
-        }
-
-        // associate the filename with the FPA element
-        char *name = pmFPAfileNameFromRule(file->filesrc, file, view);
-
-        // save the name association in the pmFPAfile structure
-        psMetadataAddStr(file->names, PS_LIST_TAIL, name, 0, "", infiles->data[i]);
-
-        psFree(view);
-        psFree(name);
-        psFree(phu);
-    }
-    psFree(fpa);
+    if (filenames->n == 0) {
+        psError(PS_ERR_IO, false, "No files in array in %s in arguments", argname);
+        if (success) {
+            *success = false;
+        }
+        return NULL;
+    }
+
+    pmFPAfile *file = fpaFileDefineFromArray(config, NULL, filename, filenames); // File of interest
+
     if (success) {
-        *success = true;
-    }
-
-    return file;
-}
-
-// search for argname on the config->argument list
-// construct an FPA based on the files in this list (must represent a single FPA)
-// built the association between the FPA elements (CHIP/CELL) and the files
-// define the pmFPAfile filename and bind it to this FPA
-// save the pmFPAfile on config->files
-// return the pmFPAfile (a view to the one saved on config->files)
-pmFPAfile *pmFPAfileBindFromArgs (bool *success, pmFPAfile *input, pmConfig *config, const char *filename, const char *argname)
+        *success = file ? true : false;
+    }
+
+    return file;
+}
+
+pmFPAfile *pmFPAfileBindFromArgs(bool *success, pmFPAfile *input, pmConfig *config,
+                                 const char *filename, const char *argname)
 {
     PS_ASSERT_PTR_NON_NULL(input, NULL);
@@ -644,18 +649,8 @@
     PS_ASSERT_STRING_NON_EMPTY(argname, NULL);
 
-    bool status;
-    psFits *fits = NULL;
-    pmFPAfile *file = NULL;
-    psMetadata *phu = NULL;
-
-    // use success to identify valid exit conditions (as opposed to 'argument not supplied')
-    if (success) {
-        *success = false;
-    }
-
-    // we search the argument data for the named fileset (argname)
-    psArray *infiles = psMetadataLookupPtr(&status, config->arguments, argname);
+    // Search the argument data for the named fileset (argname)
+    bool status;                        // Status of MD lookup
+    psArray *filenames = psMetadataLookupPtr(&status, config->arguments, argname); // Filenames for file
     if (!status) {
-        // this is not an error: this just means no matching argument was supplied
         if (success) {
             *success = true;
@@ -663,125 +658,23 @@
         return NULL;
     }
-    if (infiles->n < 1) {
-        psError(PS_ERR_IO, false, "Found n == %ld files in %s in arguments\n", infiles->n, argname);
-        return NULL;
-    }
-
-    // load the given filerule (from config->camera) and bind it to the fpa
-    // the returned file is just a view to the entry on config->files
-    file = pmFPAfileDefineInput (config, input->fpa, NULL, filename);
-    if (!file) {
-        psError(PS_ERR_IO, false, "file %s not defined\n", filename);
-        psFree(phu);
-        return NULL;
-    }
-
-    // set derived values
-    file->fileLevel = input->fileLevel;
-
-
-    // define the rule to identify these files in the file->names data
-    psFree (file->filerule);
-    psFree (file->filesrc);
-    file->filerule = psStringCopy ("@FILES");
-    file->filesrc = psStringCopy ("{CHIP.NAME}.{CELL.NAME}");
-
-    // examine the list of input files and validate their cameras
-    // associated each filename with an element of the FPA
-    // save the association on file->names
-    psMetadata *format = NULL;
-    for (int i = 0; i < infiles->n; i++) {
-        // this function is implicitly an INPUT operation: do not create the file
-        psString realName = pmConfigConvertFilename (infiles->data[i], config, false, false);
-        if (!realName) {
-            psError(PS_ERR_IO, false, "Failed to convert file name %s", (char *) infiles->data[i]);
-            return NULL;
-        }
-        // EXTWORD (fits->extword) is not relevant to the PHU
-        fits = psFitsOpen (realName, "r");
-        if (!fits) {
-            psError(PS_ERR_IO, false, "Failed to open file %s\n", realName);
-            psFree(realName);
-            return NULL;
-        }
-        phu = psFitsReadHeader (NULL, fits);
-        if (!phu) {
-            psError(PS_ERR_IO, false, "Failed to read file header %s", realName);
-            psFree(realName);
-            psFitsClose(fits);
-            return NULL;
-        }
-
-        if (!format) {
-            format = pmConfigCameraFormatFromHeader(NULL, NULL, NULL, config, phu, true);
-            if (!format) {
-                psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", realName);
-                psFree(phu);
-                psFree(realName);
-                psFitsClose(fits);
-                return NULL;
-            }
-        } else {
-            bool valid = false;
-            if (!pmConfigValidateCameraFormat(&valid, format, phu)) {
-                psError(PS_ERR_UNKNOWN, false, "Error in config scripts\n");
-                psFree(realName);
-                psFitsClose(fits);
-                return NULL;
-            }
-            if (!valid) {
-                psError(PS_ERR_IO, false, "specified data file %s does not match format of supplied INPUT\n",
-                        realName);
-                psFree(realName);
-                psFitsClose(fits);
-                return NULL;
-            }
-        }
-
-        psFree(realName);
-        psFitsClose(fits);
-
-        // set the view to the corresponding entry for this phu
-        pmFPAview *view = pmFPAIdentifySourceFromHeader (input->fpa, phu, format);
-        if (!view) {
-            psError(PS_ERR_IO, false, "Unable to determine source for %s", file->name);
-            psFree(phu);
-            return NULL;
-        }
-
-        // associate the filename with the FPA element
-        char *name = pmFPAfileNameFromRule(file->filesrc, file, view);
-
-        // save the name association in the pmFPAfile structure
-        psMetadataAddStr (file->names, PS_LIST_TAIL, name, 0, "", infiles->data[i]);
-
-        if ((i == 0) && (file->type == PM_FPA_FILE_MASK)) {
-            if (!pmConfigMaskReadHeader (config, phu)) {
-                psError(PS_ERR_IO, false, "error in mask bits");
-                return NULL;
-            }
-        }
-
-        psFree(view);
-        psFree(name);
-        psFree(phu);
-    }
-    file->format = format;
-    file->formatName = psStringCopy(config->formatName);
+    if (filenames->n == 0) {
+        psError(PS_ERR_IO, false, "No files in array in %s in arguments", argname);
+        if (success) {
+            *success = false;
+        }
+        return NULL;
+    }
+
+    pmFPAfile *file = fpaFileDefineFromArray(config, input, filename, filenames); // File of interest
 
     if (success) {
-        *success = true;
-    }
-    return file;
-}
-
-// search for argname on the config->argument list
-// construct an FPA based on the files in this list (each represents the same FPA)
-// built the association between the FPA elements (CHIP/CELL) and the files
-// define the pmFPAfile filenames and bind them to the FPAs
-// save the pmFPAfiles on config->files
-// return the pmFPAfiles (a view to the one saved on config->files)
-pmFPAfile *pmFPAfileDefineSingleFromArgs (bool *success, pmConfig *config, const char *filename,
-        const char *argname, int entry)
+        *success = file ? true : false;
+    }
+
+    return file;
+}
+
+pmFPAfile *pmFPAfileDefineSingleFromArgs(bool *success, pmConfig *config, const char *filename,
+                                         const char *argname, int entry)
 {
     PS_ASSERT_PTR_NON_NULL(config, NULL);
@@ -789,19 +682,8 @@
     PS_ASSERT_STRING_NON_EMPTY(argname, NULL);
 
-    bool status;
-    pmFPA *fpa = NULL;
-    psFits *fits = NULL;
-    pmFPAfile *file = NULL;
-    psMetadata *phu = NULL;
-    psMetadata *format = NULL;
-
-    if (success) {
-        *success = false;
-    }
-
-    // we search the argument data for the named fileset (argname)
-    psArray *infiles = psMetadataLookupPtr(&status, config->arguments, argname);
+    // Search the argument data for the named fileset (argname)
+    bool status;                        // Status from MD lookup
+    psArray *filenames = psMetadataLookupPtr(&status, config->arguments, argname); // Filenames for file
     if (!status) {
-        psTrace("psModules.camera", 5, "Failed to find %s in argument list", argname);
         if (success) {
             *success = true;
@@ -809,108 +691,52 @@
         return NULL;
     }
-    if (infiles->n <= entry) {
-        psError(PS_ERR_IO, false, "only %ld files in %s in argument, entry %d requested\n",
-                infiles->n, argname, entry);
-        return NULL;
-    }
-
-    // examine the list of input files and validate their cameras
-    // associated each filename with an element of the FPA
-    // save the association on file->names
-    // EXTWORD (fits->extword) is not relevant to the PHU
-    fits = psFitsOpen (infiles->data[entry], "r");
-    phu = psFitsReadHeader (NULL, fits);
-    psFitsClose (fits);
-
-    // on first call to this function, config->camera is not set.
-    // later calls will give an error if the cameras do not match
-    psMetadata *camera = NULL;
-    psString formatName = NULL;
-    psString cameraName = NULL;
-    format = pmConfigCameraFormatFromHeader (&camera, &cameraName, &formatName, config, phu, true);
-    if (!format) {
-        psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", (char *)infiles->data[0]);
-        psFree(phu);
-        psFree(camera);
-        psFree(formatName);
-        return NULL;
-    }
-
-    // build the template fpa, set up the basic view
-    fpa = pmFPAConstruct (camera, cameraName);
-    if (!fpa) {
-        psError(PS_ERR_IO, false, "Failed to construct FPA from %s", (char *)infiles->data[0]);
-        psFree(phu);
-        psFree(camera);
-        psFree(formatName);
-        psFree(format);
-        return NULL;
-    }
-    psFree(camera);
-
-    // load the given filerule (from config->camera) and bind it to the fpa
-    // the returned file is just a view to the entry on config->files
-    // we need a variable name here... (but in filerule)
-    file = pmFPAfileDefineInput (config, fpa, cameraName, filename);
-    if (!file) {
-        psError(PS_ERR_IO, false, "file %s not defined\n", filename);
-        psFree(phu);
-        psFree(fpa);
-        psFree(format);
-        return NULL;
-    }
-    psFree(cameraName);
-    FPA_TEST_ASSERT (file);
-
-    file->format = format;
-    file->formatName = formatName;
-    file->filerule = psStringCopy ("@FILES");
-    file->filesrc = psStringCopy ("{CHIP.NAME}.{CELL.NAME}");
-    // adjust the above rules to identify these files in the file->names data
-
-    file->fileLevel = pmFPAPHULevel(format);
-    if (file->fileLevel == PM_FPA_LEVEL_NONE) {
-        psError(PS_ERR_IO, true, "Unable to determine file level for %s\n", file->name);
-        psFree(phu);
-        psFree(fpa);
-        return NULL;
-    }
-
-    if (file->type == PM_FPA_FILE_MASK) {
-        if (!pmConfigMaskReadHeader (config, phu)) {
-            psError(PS_ERR_IO, false, "error in mask bits");
-            return NULL;
-        }
-    }
-
-    // set the view to the corresponding entry for this phu
-    pmFPAview *view = pmFPAAddSourceFromHeader (fpa, phu, format);
-    if (!view) {
-        psError(PS_ERR_IO, false, "Unable to determine source for %s", file->name);
-        psFree(phu);
-        psFree(fpa);
-        return NULL;
-    }
-
-    // associate the filename with the FPA element
-    char *name = pmFPAfileNameFromRule (file->filesrc, file, view);
-
-    // save the name association in the pmFPAfile structure
-    psMetadataAddStr (file->names, PS_LIST_TAIL, name, 0, "", infiles->data[entry]);
-
-    psFree(phu);
-    psFree(fpa);
-    psFree(view);
-    psFree(name);
+    if (filenames->n <= entry) {
+        psError(PS_ERR_IO, false, "Insufficient files (%ld) in array in %s in arguments",
+                filenames->n, argname);
+        if (success) {
+            *success = false;
+        }
+        return NULL;
+    }
+
+    psArray *single = psArrayAlloc(1);  // Array of single filename of interest
+    single->data[0] = psMemIncrRefCounter(filenames->data[entry]);
+    pmFPAfile *file = fpaFileDefineFromArray(config, NULL, filename, single); // File of interest
+    psFree(single);
 
     if (success) {
-        *success = true;
-    }
-    return file;
-}
+        *success = file ? true : false;
+    }
+
+    return file;
+}
+
+pmFPAfile *pmFPAfileDefineFromRun(bool *success, pmConfig *config, const char *filename)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_STRING_NON_EMPTY(filename, NULL);
+
+    psArray *filenames = pmConfigRunFileGet(config, filename); // Filenames used, or NULL
+    if (!filenames) {
+        if (success) {
+            *success = true;
+        }
+        return NULL;
+    }
+
+    pmFPAfile *file = fpaFileDefineFromArray(config, NULL, filename, filenames); // File of interest
+    psFree(filenames);
+
+    if (success) {
+        *success = file ? true : false;
+    }
+
+    return file;
+}
+
 
 // define the named pmFPAfile from the camera->config
 // only valid for pmFPAfile->mode = READ
-pmFPAfile *pmFPAfileDefineFromConf (bool *success, const pmConfig *config, const char *filename)
+pmFPAfile *pmFPAfileDefineFromConf(bool *success, const pmConfig *config, const char *filename)
 {
     PS_ASSERT_PTR_NON_NULL(config, false);
@@ -991,4 +817,8 @@
     pmFPA *fpa = NULL;
     pmFPAfile *file = NULL;
+
+    if (type == PM_DETREND_TYPE_NONE) {
+        return NULL;
+    }
 
     if (success) {
Index: /trunk/psModules/src/camera/pmFPAfileDefine.h
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileDefine.h	(revision 23267)
+++ /trunk/psModules/src/camera/pmFPAfileDefine.h	(revision 23268)
@@ -53,5 +53,5 @@
 // Note that the returned pmFPAfile is a view only, so it should not be freed by the caller --- the only
 // reference count is held by the config->files metadata.
-pmFPAfile *pmFPAfileDefineFromArgs (bool *found, pmConfig *config, const char *filename, const char *argname);
+pmFPAfile *pmFPAfileDefineFromArgs(bool *found, pmConfig *config, const char *filename, const char *argname);
 
 // look for the given argname on the argument list; bind the associated files to the specified
@@ -59,5 +59,16 @@
 // Note that the returned pmFPAfile is a view only, so it should not be freed by the caller --- the only
 // reference count is held by the config->files metadata.
-pmFPAfile *pmFPAfileBindFromArgs (bool *found, pmFPAfile *input, pmConfig *config, const char *filename, const char *argname);
+pmFPAfile *pmFPAfileBindFromArgs(bool *found, pmFPAfile *input, pmConfig *config, const char *filename, const char *argname);
+
+/// Define a file based on the filenames in the RUN metadata in the configuration
+///
+/// Note that the returned pmFPAfile is a view only, so it should not be freed by the caller --- the only
+/// reference count is held by the config->files metadata.
+pmFPAfile *pmFPAfileDefineFromRun(
+    bool *found,                        ///< Found files?
+    pmConfig *config,                   ///< Configuration
+    const char *filename                ///< Name of file
+    );
+
 
 // look for the given argname on the argument list.  find the give filename from the file rules
Index: /trunk/psModules/src/config/pmConfigRun.c
===================================================================
--- /trunk/psModules/src/config/pmConfigRun.c	(revision 23267)
+++ /trunk/psModules/src/config/pmConfigRun.c	(revision 23268)
@@ -71,4 +71,39 @@
 }
 
+psArray *pmConfigRunFileGet(pmConfig *config, const char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_STRING_NON_EMPTY(name, false);
+
+    psMetadata *run = configRun(config);// RUN information
+    psAssert(run, "Require run-time information");
+    psMetadata *files = configElement(run, "FILES", "Filerules used during execution");
+    psAssert(files, "Require list of files");
+
+    psList *list = psListAlloc(NULL);   // List of file names
+
+    psString regex = NULL;              // Regular expression for iteration
+    psStringAppend(&regex, "^%s$", name);
+    psMetadataIterator *iter = psMetadataIteratorAlloc(files, PS_LIST_HEAD, regex);
+    psFree(regex);
+    psMetadataItem *item;               // Item from iteration
+    while ((item = psMetadataGetAndIncrement(iter))) {
+        psAssert(item->type == PS_DATA_STRING, "We only put STRING types here.");
+        psListAdd(list, PS_LIST_TAIL, item->data.str);
+    }
+    psFree(iter);
+
+    if (psListLength(list) == 0) {
+        // Didn't find anything
+        psFree(list);
+        return NULL;
+    }
+
+    psArray *array = psListToArray(list); // Array of file names, to return
+    psFree(list);
+
+    return array;
+}
+
 
 bool pmConfigRunCommand(pmConfig *config, int argc, char **argv)
Index: /trunk/psModules/src/config/pmConfigRun.h
===================================================================
--- /trunk/psModules/src/config/pmConfigRun.h	(revision 23267)
+++ /trunk/psModules/src/config/pmConfigRun.h	(revision 23268)
@@ -10,4 +10,10 @@
     pmConfig *config,                   ///< Configuration
     const pmFPAfile *file               ///< File to add
+    );
+
+/// Retrieve file names for a symbolic file from the run-time information
+psArray *pmConfigRunFileGet(
+    pmConfig *config,                   ///< Configuration
+    const char *name                    ///< Name of symbolic file (pmFPAfile)
     );
 
Index: /trunk/psModules/src/detrend/pmDetrendDB.c
===================================================================
--- /trunk/psModules/src/detrend/pmDetrendDB.c	(revision 23267)
+++ /trunk/psModules/src/detrend/pmDetrendDB.c	(revision 23268)
@@ -20,14 +20,15 @@
 
 //
-static void pmDetrendSelectOptionsFree (pmDetrendSelectOptions *options)
-{
-
-    if (!options)
+static void pmDetrendSelectOptionsFree(pmDetrendSelectOptions *options)
+{
+
+    if (!options) {
         return;
-
-    psFree (options->camera);
-    psFree (options->filter);
-    psFree (options->dettype);
-    psFree (options->version);
+    }
+
+    psFree(options->camera);
+    psFree(options->filter);
+    psFree(options->dettype);
+    psFree(options->version);
 
     return;
@@ -37,5 +38,4 @@
 pmDetrendSelectOptions *pmDetrendSelectOptionsAlloc(const char *camera, psTime time, pmDetrendType type)
 {
-
     pmDetrendSelectOptions *options = psAlloc(sizeof(pmDetrendSelectOptions));
     psMemSetDeallocator(options, (psFreeFunc) pmDetrendSelectOptionsFree);
@@ -63,11 +63,12 @@
 }
 
-static void pmDetrendSelectResultsFree (pmDetrendSelectResults *results)
-{
-
-    if (!results)
+static void pmDetrendSelectResultsFree(pmDetrendSelectResults *results)
+{
+
+    if (!results) {
         return;
-
-    psFree (results->detID);
+    }
+
+    psFree(results->detID);
     psFree(results->level);
 
@@ -75,5 +76,5 @@
 }
 
-pmDetrendSelectResults *pmDetrendSelectResultsAlloc ()
+pmDetrendSelectResults *pmDetrendSelectResultsAlloc(void)
 {
 
@@ -87,20 +88,21 @@
 }
 
-psString pmDetrendTypeToString (pmDetrendType type)
-{
-
-    # define DETREND_STRING_CASE(TTT) \
-case PM_DETREND_TYPE_##TTT: \
-    return psStringCopy (#TTT);
+psString pmDetrendTypeToString(pmDetrendType type)
+{
+
+#define DETREND_STRING_CASE(TYPE) \
+  case PM_DETREND_TYPE_##TYPE: \
+    return psStringCopy(#TYPE);
 
     switch (type) {
-        DETREND_STRING_CASE (MASK);
-        DETREND_STRING_CASE (BIAS);
-        DETREND_STRING_CASE (DARK);
-        DETREND_STRING_CASE (FLAT);
-        DETREND_STRING_CASE (FLATCORR);
-        DETREND_STRING_CASE (SHUTTER);
-        DETREND_STRING_CASE (FRINGE);
-        DETREND_STRING_CASE (ASTROM);
+        DETREND_STRING_CASE(NONE);
+        DETREND_STRING_CASE(MASK);
+        DETREND_STRING_CASE(BIAS);
+        DETREND_STRING_CASE(DARK);
+        DETREND_STRING_CASE(FLAT);
+        DETREND_STRING_CASE(FLATCORR);
+        DETREND_STRING_CASE(SHUTTER);
+        DETREND_STRING_CASE(FRINGE);
+        DETREND_STRING_CASE(ASTROM);
     default:
         return NULL;
@@ -111,6 +113,5 @@
 // detselect -camera (camera) -time (time) -type (type) [others]
 // returns: (type) (class) (exp_flag) DONE
-pmDetrendSelectResults *pmDetrendSelect (const pmDetrendSelectOptions *options,
-        const pmConfig *config)
+pmDetrendSelectResults *pmDetrendSelect(const pmDetrendSelectOptions *options, const pmConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(options, NULL);
Index: /trunk/psModules/src/detrend/pmDetrendDB.h
===================================================================
--- /trunk/psModules/src/detrend/pmDetrendDB.h	(revision 23267)
+++ /trunk/psModules/src/detrend/pmDetrendDB.h	(revision 23268)
@@ -25,4 +25,5 @@
 
 typedef enum {
+    PM_DETREND_TYPE_NONE,
     PM_DETREND_TYPE_MASK,
     PM_DETREND_TYPE_BIAS,
@@ -59,5 +60,5 @@
 } pmDetrendSelectResults;
 
-psString pmDetrendTypeToString (pmDetrendType type);
+psString pmDetrendTypeToString(pmDetrendType type);
 
 pmDetrendSelectOptions *pmDetrendSelectOptionsAlloc(const char *camera, psTime time, pmDetrendType type);
