Index: trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 23259)
+++ 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 23259)
+++ 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 23259)
+++ 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 23259)
+++ 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 23259)
+++ 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 23259)
+++ 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);
