Index: trunk/psModules/src/camera/pmFPAfile.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfile.c	(revision 27597)
+++ trunk/psModules/src/camera/pmFPAfile.c	(revision 27657)
@@ -111,5 +111,6 @@
     file->save = false;
 
-    file->index = fileNum++;
+    file->fileIndex = fileNum++;
+    file->fileID = 0;
 
     file->imageId = 0;
@@ -372,6 +373,14 @@
         // Number of the file in list
         psString num = NULL;            // Number to use
-        psStringAppend(&num, "%d", file->index);
+        psStringAppend(&num, "%d", file->fileIndex);
         psStringSubstitute(&newRule, num, "{FILE.INDEX}");
+        psFree(num);
+    }
+
+    if (strstr(newRule, "{FILE.ID}")) {
+        // Number of the file in list
+        psString num = NULL;            // Number to use
+        psStringAppend(&num, "%03d", file->fileID);
+        psStringSubstitute(&newRule, num, "{FILE.ID}");
         psFree(num);
     }
@@ -638,5 +647,5 @@
     psFree(iter);
 
-    psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find instance %d of file %s", num, name);
+    psLogMsg("psModules.camera", PS_LOG_MINUTIA, "Unable to find instance %d of file %s", num, name);
     return NULL;
 }
Index: trunk/psModules/src/camera/pmFPAfile.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfile.h	(revision 27597)
+++ trunk/psModules/src/camera/pmFPAfile.h	(revision 27657)
@@ -111,5 +111,6 @@
     psString formatName;                // name of the camera format
 
-    int index;                          // Index of file
+    int fileIndex;			// Index of file
+    int fileID;				// internal sequence number
 
     psS64 imageId, sourceId;            // Image and source identifiers
Index: trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 27597)
+++ trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 27657)
@@ -1271,6 +1271,11 @@
     file->name = psStringCopy (name);
 
+    // free a previously existing readout
+    psFree(file->readout);
     file->readout = readout;
-    psMetadataAddPtr(files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN, "", file);
+
+    // allow for multiple entries
+    // XXX handle replace vs multiple?
+    psMetadataAddPtr(files, PS_LIST_TAIL, name, PS_DATA_UNKNOWN | PS_META_DUPLICATE_OK, "", file);
     psFree(file);
     // we free this copy of file, but 'files' still has a copy
@@ -1313,14 +1318,16 @@
                                 const char *name, // name of internal/external file
                                 const pmFPA *fpa, // use this fpa to generate
-                                const psImageBinning *binning) {
+                                const psImageBinning *binning,
+                                int index) {
   pmReadout *readout = NULL;
 
-  bool status = true;
-  pmFPAfile *file = psMetadataLookupPtr(&status, config->files, name);
+  pmFPAfile *file = pmFPAfileSelectSingle(config->files, name, index);
 
   // if the file does not exist, it is not being used as an I/O file: define an internal version
   if (file == NULL) {
-    readout = pmFPAfileDefineInternal (config->files, name, binning->nXruff, binning->nYruff, PS_TYPE_F32);
-    return readout;
+      // XXX currently, we do not guarantee that the defined file lands on entry 'index'
+      psAssert (binning, "internal files must be supplied a psImageBinning for the output images size"); 
+      readout = pmFPAfileDefineInternal (config->files, name, binning->nXruff, binning->nYruff, PS_TYPE_F32);
+      return readout;
   }
 
Index: trunk/psModules/src/camera/pmFPAfileDefine.h
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.h	(revision 27597)
+++ trunk/psModules/src/camera/pmFPAfileDefine.h	(revision 27657)
@@ -172,5 +172,7 @@
                                 const char *name, // name of internal/external file
                                 const pmFPA *fpa, // use this fpa to generate
-                                const psImageBinning *binning);
+                                const psImageBinning *binning,
+				int index
+    );
 
 /// @}
Index: trunk/psModules/src/objects/Makefile.am
===================================================================
--- trunk/psModules/src/objects/Makefile.am	(revision 27597)
+++ trunk/psModules/src/objects/Makefile.am	(revision 27657)
@@ -20,4 +20,5 @@
 	pmModelUtils.c \
 	pmSource.c \
+	pmPhotObj.c \
 	pmSourceMasks.c \
 	pmSourceMoments.c \
@@ -80,4 +81,5 @@
 	pmModelUtils.h \
 	pmSource.h \
+	pmPhotObj.h \
 	pmSourceMasks.h \
 	pmSourceDiffStats.h \
Index: trunk/psModules/src/objects/pmPeaks.h
===================================================================
--- trunk/psModules/src/objects/pmPeaks.h	(revision 27597)
+++ trunk/psModules/src/objects/pmPeaks.h	(revision 27657)
@@ -63,5 +63,5 @@
     bool assigned;                      ///< is peak assigned to a source?
     pmPeakType type;                    ///< Description of peak.
-    pmFootprint *footprint;     ///< reference to containing footprint
+    pmFootprint *footprint;		///< reference to containing footprint
 }
 pmPeak;
Index: trunk/psModules/src/objects/pmPhotObj.c
===================================================================
--- trunk/psModules/src/objects/pmPhotObj.c	(revision 27597)
+++ trunk/psModules/src/objects/pmPhotObj.c	(revision 27657)
@@ -17,4 +17,5 @@
 #include <pslib.h>
 #include "pmPhotObj.h"
+#include "pmSource.h"
 
 static void pmPhotObjFree (pmPhotObj *tmp)
@@ -38,2 +39,27 @@
 }
 
+bool pmPhotObjAddSource(pmPhotObj *object, pmSource *source) {
+
+    psAssert (source, "programming error: NULL source");
+    if (!source->peak) {
+	psError(PS_ERR_UNKNOWN, true, "source missing peak");
+	return false; 
+    }
+    if (!finite(source->peak->xf)) {
+	psError(PS_ERR_UNKNOWN, true, "NAN peak coordinate");
+	return false; 
+    }
+    if (!finite(source->peak->yf)) {
+	psError(PS_ERR_UNKNOWN, true, "NAN peak coordinate");
+	return false; 
+    }
+
+    // XXX we should probably use the fitted position if it exists
+    if (!object->sources) {
+	object->sources = psArrayAllocEmpty(1);
+	object->x = source->peak->xf;
+	object->y = source->peak->yf;
+    }
+    psArrayAdd (object->sources, 1, source);
+    return true;
+}
Index: trunk/psModules/src/objects/pmPhotObj.h
===================================================================
--- trunk/psModules/src/objects/pmPhotObj.h	(revision 27597)
+++ trunk/psModules/src/objects/pmPhotObj.h	(revision 27657)
@@ -34,8 +34,15 @@
  */
 typedef struct {
-  int seq;                            ///< ID for output (generated on write OR set on read)
-  psArray *sources;
+    int id;                            ///< ID for output (generated on write OR set on read)
+    psArray *sources;
+    int flags;
+    float x;
+    float y;
 } pmPhotObj;
+
+bool pmPhotObjAddSource(pmPhotObj *object, pmSource *source);
+pmPhotObj *pmPhotObjAlloc(void);
 
 /// @}
 # endif /* PM_PHOT_OBJ_H */
+
Index: trunk/psModules/src/objects/pmSource.c
===================================================================
--- trunk/psModules/src/objects/pmSource.c	(revision 27597)
+++ trunk/psModules/src/objects/pmSource.c	(revision 27657)
@@ -180,4 +180,5 @@
     source->type = in->type;
     source->mode = in->mode;
+    source->imageID = in->imageID;
 
     return(source);
@@ -1058,4 +1059,19 @@
     psF32 fA = (A->peak == NULL) ? 0 : A->peak->y;
     psF32 fB = (B->peak == NULL) ? 0 : B->peak->y;
+
+    psF32 diff = fA - fB;
+    if (diff > FLT_EPSILON) return (+1);
+    if (diff < FLT_EPSILON) return (-1);
+    return (0);
+}
+
+// sort by X (ascending)
+int pmSourceSortByX (const void **a, const void **b)
+{
+    pmSource *A = *(pmSource **)a;
+    pmSource *B = *(pmSource **)b;
+
+    psF32 fA = (A->peak == NULL) ? 0 : A->peak->x;
+    psF32 fB = (B->peak == NULL) ? 0 : B->peak->x;
 
     psF32 diff = fA - fB;
Index: trunk/psModules/src/objects/pmSource.h
===================================================================
--- trunk/psModules/src/objects/pmSource.h	(revision 27597)
+++ trunk/psModules/src/objects/pmSource.h	(revision 27657)
@@ -43,4 +43,5 @@
     PM_SOURCE_TMPF_SIZE_MEASURED     = 0x0004,
     PM_SOURCE_TMPF_SIZE_CR_CANDIDATE = 0x0008,
+    PM_SOURCE_TMPF_MOMENTS_MEASURED  = 0x0010,
 } pmSourceTmpF;
 
@@ -90,4 +91,5 @@
     pmSourceExtendedPars *extpars;      ///< extended source parameters
     pmSourceDiffStats *diffStats;       ///< extra parameters for difference detections
+    int imageID;
 };
 
@@ -245,4 +247,5 @@
 int  pmSourceSortBySN (const void **a, const void **b);
 int  pmSourceSortByY (const void **a, const void **b);
+int  pmSourceSortByX (const void **a, const void **b);
 int  pmSourceSortBySeq (const void **a, const void **b);
 
Index: trunk/psModules/src/psmodules.h
===================================================================
--- trunk/psModules/src/psmodules.h	(revision 27597)
+++ trunk/psModules/src/psmodules.h	(revision 27657)
@@ -124,4 +124,5 @@
 #include <pmSourceMasks.h>
 #include <pmSource.h>
+#include <pmPhotObj.h>
 #include <pmSourceUtils.h>
 #include <pmSourceIO.h>
