Index: /trunk/psphot/src/psModulesUtils.c
===================================================================
--- /trunk/psphot/src/psModulesUtils.c	(revision 6521)
+++ /trunk/psphot/src/psModulesUtils.c	(revision 6522)
@@ -312,2 +312,23 @@
     return false;
 }
+
+ppImageLoadDepth ppImageCheckDepth (psMetadata *recipe, char *name) {
+
+    bool status;
+
+    // determine the load depth
+    const char *depth = psMetadataLookupStr(&status, recipe, name);
+    if (! status || ! depth || strlen(depth) == 0) {
+        psLogMsg("psphot", PS_LOG_ERROR, "%s not specified in recipe.", name);
+        exit(EXIT_FAILURE);
+    }
+
+    if (!strcasecmp(depth, "FPA"))  return (PP_LOAD_FPA);
+    if (!strcasecmp(depth, "CHIP")) return (PP_LOAD_CHIP);
+    if (!strcasecmp(depth, "CELL")) return (PP_LOAD_CELL);
+
+    psLogMsg(__func__, PS_LOG_ERROR, "%s in recipe is not FPA, CHIP or CELL.", name);
+    exit(EXIT_FAILURE);
+
+    return PP_LOAD_NONE;
+}
Index: /trunk/psphot/src/psModulesUtils.h
===================================================================
--- /trunk/psphot/src/psModulesUtils.h	(revision 6521)
+++ /trunk/psphot/src/psModulesUtils.h	(revision 6522)
@@ -35,4 +35,14 @@
 } ppFile;
 
+typedef struct {
+    ppFile *input;
+    ppFile *resid;
+    ppFile *background;
+    ppFile *backSub;
+    ppFile *output;
+    ppFile *psfdata;
+    ppFile *psfsample;
+} psphotData;
+
 // psModule extra utilities
 // bool	     pmSourceFitModel_EAM(pmSource *source, pmModel *model, const bool PSF);
Index: /trunk/psphot/src/psphotArguments.c
===================================================================
--- /trunk/psphot/src/psphotArguments.c	(revision 6521)
+++ /trunk/psphot/src/psphotArguments.c	(revision 6522)
@@ -176,5 +176,4 @@
 
 static void usage (void) {
-
     fprintf (stderr, "USAGE: psphot (image) (output)\n");
     exit (2);
Index: /trunk/psphot/src/psphotImageLoop.c
===================================================================
--- /trunk/psphot/src/psphotImageLoop.c	(revision 6521)
+++ /trunk/psphot/src/psphotImageLoop.c	(revision 6522)
@@ -1,39 +1,17 @@
 # include "psphot.h"
 
-bool psphotImageLoop (ppFile *file, ppConfig *config) {
+bool psphotImageLoop (psphotData *data, ppConfig *config) {
 
-    bool status;
-    ppImageLoadDepth imageLoadDepth;
+    pmFPA *fpa = data->input->fpa;
 
-    // determine the load depth
-    const char *depth = psMetadataLookupStr(&status, config->recipe, "LOAD.DEPTH");
-    if (! status || ! depth || strlen(depth) == 0) {
-        psLogMsg("psphot", PS_LOG_ERROR, "LOAD.DEPTH not specified in recipe.");
-        exit(EXIT_FAILURE);
-    }
-    imageLoadDepth = PP_LOAD_NONE;
-    if (!strcasecmp(depth, "FPA")) imageLoadDepth = PP_LOAD_FPA;
-    if (!strcasecmp(depth, "CHIP")) imageLoadDepth = PP_LOAD_CHIP;
-    if (!strcasecmp(depth, "CELL")) imageLoadDepth = PP_LOAD_CELL;
-    if (imageLoadDepth == PP_LOAD_NONE) {
-        psLogMsg(__func__, PS_LOG_ERROR, "LOAD.DEPTH in recipe is not FPA, CHIP or CELL.");
-        exit(EXIT_FAILURE);
-    }
+    psphotDataIO (data, config, -1, -1);
 
-    if (imageLoadDepth == PP_LOAD_FPA) {
-        psTrace(__func__, 1, "Loading pixels for FPA...\n");
-        ppImageLoadPixels(file, config->database, -1, -1);
-    }
-
-    for (int i = 0; i < file->fpa->chips->n; i++) {
-        pmChip *chip = file->fpa->chips->data[i]; // Chip of interest in input image
+    for (int i = 0; i < fpa->chips->n; i++) {
+        pmChip *chip = fpa->chips->data[i]; // Chip of interest in input image
 
         psLogMsg ("psphot", 4, "Chip %d: %x %x\n", i, chip->exists, chip->process);
         if (! chip->process) { continue; }
 
-	if (imageLoadDepth == PP_LOAD_CHIP) {
-            psTrace(__func__, 1, "Loading pixels for chip %d...\n", i);
-            ppImageLoadPixels(file, config->database, i, -1);
-        }
+	psphotDataIO (data, config, i, -1);
 
         for (int j = 0; j < chip->cells->n; j++) {
@@ -43,9 +21,6 @@
             if (! cell->process) { continue; }
 
-            if (imageLoadDepth == PP_LOAD_CELL) {
-                psTrace(__func__, 1, "Loading pixels for chip %d, cell %d...\n", i, j);
-                ppImageLoadPixels(file, config->database, i, j);
-            }
-	    
+	    psphotDataIO (data, config, i, j);
+
 	    // XXX optional mask and weight input image should be loaded here?
 	    // this sets the weight map and basic mask applying CELL.BAD and CELL.SATURATION
@@ -61,9 +36,14 @@
 		// run a single-model test if desired
 		psphotModelTest (readout, config->arguments, config->recipe);
-		psphotReadout (readout, config->recipe);
-		psphotOutput (readout, config->arguments);
+
+		// run the actual photometry analysis
+		psphotReadout (readout, data, config);
+
+		// XXX what do we do if we have multiple readouts?
+		psphotOutput (readout, data, config);
 	    }
         }
     }
+    psphotOutputClose (data);
     return true;
 }
Index: /trunk/psphot/src/psphotOutput.c
===================================================================
--- /trunk/psphot/src/psphotOutput.c	(revision 6521)
+++ /trunk/psphot/src/psphotOutput.c	(revision 6522)
@@ -14,16 +14,34 @@
 static char *psfSample  = NULL;
 
-void psphotOutputCleanup () {
-
-    psFree (outputRoot);
-    psFree (outputName);
-    psFree (outputMode);
-    psFree (outputFormat);
-    psFree (extNumberFormat);
-    psFree (extNameKey);
-    psFree (extRoot);
-    psFree (psfFile);
-    psFree (psfSample);
-    return;
+static psFits *outputFits = NULL;
+static FILE   *outputFile = NULL;
+
+bool psphotDataIO (psphotData *data, ppConfig *config, int chip, int cell) {
+
+    // load input data, if depth is appropriate
+    ppImageLoadDepth loadDepth = ppImageCheckDepth (config->recipe, "LOAD.DEPTH");
+    if ((chip == -1) && (cell == -1) && (loadDepth == PP_LOAD_FPA)) {
+        psTrace(__func__, 1, "Loading pixels for FPA...\n");
+        ppImageLoadPixels(data->input, config->database, -1, -1);
+    }
+    if ((chip != -1) && (cell == -1) && (loadDepth == PP_LOAD_CHIP)) {
+	psTrace(__func__, 1, "Loading pixels for chip %d...\n", i);
+        ppImageLoadPixels(data->input, config->database, chip, -1);
+    }
+    if ((chip != -1) && (cell != -1) && (loadDepth == PP_LOAD_CELL)) {
+	psTrace(__func__, 1, "Loading pixels for chip %d, cell %d...\n", i, j);
+        ppImageLoadPixels(data->input, config->database, chip, cell);
+    }
+
+
+
+    if (saveDepth == PP_LOAD_FPA) {
+        psTrace(__func__, 1, "Saving objects for FPA...\n");
+        psphotOutputOpen (file->fpa->phu);
+    }
+
+    ppImageLoadDepth saveDepth = ppImageCheckDepth (config->recipe, "SAVE.DEPTH");
+    
+
 }
 
@@ -46,4 +64,7 @@
     extNameKey      = psMetadataLookupStr (&status, config->recipe, "EXTNAME");
     extRoot         = psMetadataLookupStr (&status, config->recipe, "EXTROOT");
+
+    headExtname     = psMetadataLookupStr (&status, config->recipe, "HEAD_EXTNAME");
+    dataExtname     = psMetadataLookupStr (&status, config->recipe, "DATA_EXTNAME");
 
     if (extNumberFormat == NULL) {
@@ -76,9 +97,11 @@
     }
 
-    // for MEF output, we need to open a file up front
+    // for MEF output, we only allow certain output formats
     if (!strcasecmp (outputMode, "MEF")) {
+	if (!strcasecmp (outputFormat, "CMF")) goto valid_format;
 	psLogMsg ("psphot", PS_LOG_ERROR, "MEF output mode unavailable");
 	exit (1);
     }
+valid_format:
 
     // register background image-file names
@@ -99,74 +122,31 @@
 }
 
-// generate the SPLIT filenames
-char *psphotSplitName (psMetadata *header) {
-
-    bool status;
-
-    char *newName = NULL;     // destination for resulting name
-    char *extNameWord = NULL; // this contains the per-extension word to add
-    char  extNumberWord[16];  // this will store the string-formatted number
-
-    // extNumberFormat must be set to a valid entry in psphotOutputPrep
-    sprintf (extNumberWord, extNumberFormat, extNumber);
-
-    // find the extname:
-    char *extNameVal = psMetadataLookupStr (&status, header, extNameKey);
-	    
-    extNameWord = extNameVal;
-    if ((extRoot != NULL) && (extNameVal != NULL)) {
-	// check that the extNameVal matches the expected root 
-	if (strncmp (extNameVal, extRoot, strlen(extRoot))) {
-	    psLogMsg ("psphotSplitName", PS_LOG_WARN, "header entry does not match expected format");
+bool psphotOutputOpen (psMetadata *phu){
+
+    /* outputFile is used by text-format outputs */
+
+    psFree (outputFile);
+    outputFile = psphotOutputName (phu, outputName);
+
+    /* for fits-format output, open outputFits */
+    if (!strcasecmp (outputFormat, "CMF")) {
+	if (outputFits != NULL) {
+	    psFitsClose (outputFits);
 	}
-	extNameWord = extNameVal + strlen(extRoot);
-    }
-
-    if (extNameWord != NULL) {
-	psStringStrip (extNameWord);
-    }
-
-    // note : if the user mis-specifies the output name, we will happily overwrite files
-    newName = psStringCopy (outputName);
-    newName = psphotNameSubstitute (newName, outputRoot, "%r");
-    newName = psphotNameSubstitute (newName, extNameWord, "%x");
-    newName = psphotNameSubstitute (newName, extNumberWord, "%n");
-
-    return newName;
-}
-
-
-// given the input string, search for the key, and replace with the replacement
-// the input string may be freed if not needed
-char *psphotNameSubstitute (char *input, char *replace, char *key) {
-
-    char *p;
-
-    if (key == NULL) return input;
-    if (strlen(key) == 0) return input;
-
-    p = strstr (input, key);
-    if (p == NULL) return input;
-
-    // we have input = xxxkeyxxx
-    // we want output = xxxreplacexxx
-
-    // this is safe since we will subtract strlen(key) elements from input
-    char *output = psAlloc(strlen(input) + strlen(replace) + 1);
-    int Nc = p - input;
-
-    // copy the first segement into 'output'
-    strncpy (output, input, Nc);
-
-    // copy the key replacement to the start of the key
-
-    strcpy (&output[Nc], replace);
-    Nc += strlen (replace);
-    
-    // copy the remainder to the end of the replacement
-    strcpy (&output[Nc], p + strlen(key));
-
-    psFree (input);
-    return output;
+	outputFits = psFitsOpen (outputFile, "w");
+
+	if (!strcasecmp (outputMode, "MEF")) {
+	    psFitsWriteHeader (outputFits, phu);
+	}
+    }
+    return true;
+}
+
+bool psphotOutputClose (void) {
+
+    if (outputFile != NULL) {
+	psFitsClose (outputFile);
+    }
+    return true;
 }
 
@@ -190,6 +170,13 @@
     } 
 
+    if (!strcasecmp (outputMode, "MEF")) {
+	headExt = psphotOutputName (header, headExtname);
+	dataExt = psphotOutputName (header, dataExtname);
+    } 
+    if (!strcasecmp (outputMode, "SPLIT")) {
+	dataExt = psphotOutputName (header, dataExtname);
+    } 
+
     char *residImage = psMetadataLookupStr (&status, arguments, "RESID_IMAGE");
-
     if (psfSample != NULL) psphotSamplePSFs (psf, readout->image, psfSample);
     if (residImage != NULL) psphotSaveImage (header, readout->image, residImage);
@@ -225,5 +212,5 @@
     }
     if (!strcasecmp (outputFormat, "CMF")) {
-	pmSourcesWriteCMF (sources, outputFile, header);
+	pmSourcesWriteCMF (sources, header, headExt, dataExt);
 	psFree (outputFile);
 	return;
@@ -483,8 +470,8 @@
 	psMetadataAdd (row, PS_LIST_TAIL, "MAG_RAW", PS_DATA_F32, "", source->fitMag + ZERO_POINT);
 	psMetadataAdd (row, PS_LIST_TAIL, "MAG_ERR", PS_DATA_F32, "", (int)(1000*dmag));
-	psMetadataAdd (row, PS_LIST_TAIL, "MAG_GAL", PS_DATA_F32, "", type);
-	psMetadataAdd (row, PS_LIST_TAIL, "MAG_AP",  PS_DATA_F32, "", lsky);
-	psMetadataAdd (row, PS_LIST_TAIL, "LOG_SKY", PS_DATA_F32, "", 32.0);
-	psMetadataAdd (row, PS_LIST_TAIL, "FWHM_X",  PS_DATA_F32, "", source->apMag + ZERO_POINT); 
+	psMetadataAdd (row, PS_LIST_TAIL, "MAG_GAL", PS_DATA_F32, "", 32.0);
+	psMetadataAdd (row, PS_LIST_TAIL, "MAG_AP",  PS_DATA_F32, "", source->apMag + ZERO_POINT);
+	psMetadataAdd (row, PS_LIST_TAIL, "LOG_SKY", PS_DATA_F32, "", lsky);
+	psMetadataAdd (row, PS_LIST_TAIL, "FWHM_X",  PS_DATA_F32, "", type); 
 	psMetadataAdd (row, PS_LIST_TAIL, "FWHM_Y",  PS_DATA_F32, "", PAR[4]);
 	psMetadataAdd (row, PS_LIST_TAIL, "THETA",   PS_DATA_F32, "", PAR[5]);
Index: /trunk/psphot/src/psphotReadout.c
===================================================================
--- /trunk/psphot/src/psphotReadout.c	(revision 6521)
+++ /trunk/psphot/src/psphotReadout.c	(revision 6522)
@@ -12,4 +12,7 @@
     // generate a background model (median, smoothed image)
     skymodel = psphotImageMedian (readout, config);
+
+    // optional output of background-subtracted image
+    psphot
 
     // find the peaks in the image
Index: /trunk/psphot/src/testPPimageLoop.c
===================================================================
--- /trunk/psphot/src/testPPimageLoop.c	(revision 6522)
+++ /trunk/psphot/src/testPPimageLoop.c	(revision 6522)
@@ -0,0 +1,116 @@
+# include "psphot.h"
+
+bool FileList () {
+
+    psArray *filenames = psArrayFromGlob (char *names);
+    
+    psFits *fits = psFitsOpen (filenames->data[0], "r");
+    psMetadata *phu = psFitsReadHeader (NULL, fits);
+    camera = pmConfigCameraFromHeader (site, phu);
+    psFitsClose (fits);
+    
+    fpa = pmFPAConstruct (camera);
+    pmFPAview *fpi = pmFPAviewAlloc (fpa, config->camera, 0);
+
+    pmFile *file = pmFileDefine (fpi, config->camera, "PPIMAGE.INPUT");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.OUTPUT");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.BIN16");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.BIN64");
+
+    for (int i = 1; i < filenames->n; i++) {
+	fits = psFitsOpen (filenames->data[i], "r");
+	phu = psFitsReadHeader (NULL, fits);
+	pmConfigValidateCamera (camera, phu);
+
+	// set the view to the corresponding entry for this phu
+	pmFPAsetView (fpi, phu);
+
+	name = pmConfigNameFromRule (file->rulename, camera, fpi);
+	
+	psMetadataAdd (fpi->IO, name);
+
+    psRegion region = {0,0,0,0};
+    pmFPA *fpa = data->input->fpa;
+    pmFPAview *fpi = pmFPAviewAlloc (fpa, region);
+
+    }
+}
+
+bool ImageLoop (psphotData *data, ppConfig *config) {
+
+
+    // files associated with the science image
+    pmFileIOChecks (fpi);
+
+    // fpa views for the detrend images
+    pmFPAview *bias = pmFPAviewAlloc (data->bias->fpa, region);
+    pmFPAview *dark = pmFPAviewAlloc (data->dark->fpa, region);
+    pmFPAview *mask = pmFPAviewAlloc (data->mask->fpa, region);
+    pmFPAview *flat = pmFPAviewAlloc (data->flat->fpa, region);
+
+    // files associated with detrend images
+    pmFileDefine (bias, config->camera, "PPIMAGE.BIAS");
+    pmFileDefine (dark, config->camera, "PPIMAGE.DARK");
+    pmFileDefine (mask, config->camera, "PPIMAGE.MASK");
+    pmFileDefine (flat, config->camera, "PPIMAGE.FLAT");
+
+    while ((chip = pmFPAviewNextChip (fpi, 1)) != NULL) {
+	pmFPAviewNextChip (bias, 1);
+	pmFPAviewNextChip (dark, 1);
+	pmFPAviewNextChip (mask, 1);
+	pmFPAviewNextChip (flat, 1);
+
+        psLogMsg ("psphot", 4, "Chip %d: %x %x\n", i, chip->exists, chip->process);
+        if (! chip->process) { continue; }
+	pmFileIOChecks (fpi);
+	pmFileIOChecks (bias);
+	pmFileIOChecks (dark);
+	pmFileIOChecks (mask);
+	pmFileIOChecks (flat);
+
+	while ((cell = pmFPAviewNextCell (fpi, 1)) != NULL) {
+	    detrend.bias = pmFPAviewNextCell (bias, 1);
+	    detrend.dark = pmFPAviewNextCell (dark, 1);
+	    detrend.mask = pmFPAviewNextCell (mask, 1);
+	    detrend.flat = pmFPAviewNextCell (flat, 1);
+
+            psLogMsg ("psphot", 4, "Cell %d: %x %x\n", j, cell->exists, cell->process);
+            if (! cell->process) { continue; }
+	    pmFileIOChecks (fpi);
+	    pmFileIOChecks (bias);
+	    pmFileIOChecks (dark);
+	    pmFileIOChecks (mask);
+	    pmFileIOChecks (flat);
+
+	    // process each of the readouts
+	    while ((readout = pmFPAviewNextReadout (fpi)) != NULL) {
+		pmFileIOChecks (fpi);
+		
+		// run the actual photometry analysis
+		ppImageDetrend (&detrend, options, config);
+		pmFileWrite (fpi, "PPIMAGE.OUTPUT");
+	    }
+	    pmFileWrite (fpi, "PPIMAGE.OUTPUT");
+	}
+	pmFileWrite (fpi, "PPIMAGE.OUTPUT");
+	new = pmChipMosaic (chip);
+
+	pmChipRebin (chip, 16);
+	pmFileWrite (fpi, "PPIMAGE.BIN16");
+    }
+    pmFileWrite (fpi, "PPIMAGE.OUTPUT");
+    pmFileWrite (fpi, "PPIMAGE.BIN16");
+
+    pmFPAMosaic (fpa);
+    pmFPARebin (chip, 4);
+    pmFileWrite (fpi, "PPIMAGE.BIN64");
+
+    pmFileClose (fpi);
+    pmFileClose (bias);
+    pmFileClose (dark);
+    pmFileClose (mask);
+    pmFileClose (flat);
+
+    return true;
+}
+
Index: /trunk/psphot/src/testPSastroLoop.c
===================================================================
--- /trunk/psphot/src/testPSastroLoop.c	(revision 6522)
+++ /trunk/psphot/src/testPSastroLoop.c	(revision 6522)
@@ -0,0 +1,36 @@
+
+bool ImageLoop (psphotData *data, ppConfig *config) {
+
+    psRegion region = {0,0,0,0};
+    pmFPA *fpa = data->input->fpa;
+    pmFPAiterator *fpi = pmFPAiteratorAlloc (fpa, region);
+
+    // the depths are probably interpreted from the camera config file
+    pmFileAlloc (fpi, config->camera, "PSASTRO.INPUT");
+    pmFileAlloc (fpi, config->camera, "PSASTRO.OUTPUT");
+    pmFileIOChecks (fpi);
+
+    while ((chip = pmChipNext (fpi)) != NULL) {
+
+        psLogMsg ("psphot", 4, "Chip %d: %x %x\n", i, chip->exists, chip->process);
+        if (! chip->process) { continue; }
+	pmFileIOChecks (fpi);
+
+	while ((cell = pmCellNext (fpi)) != NULL) {
+
+            psLogMsg ("psphot", 4, "Cell %d: %x %x\n", j, cell->exists, cell->process);
+            if (! cell->process) { continue; }
+	    pmFileIOChecks (fpi);
+
+	    // process each of the readouts
+	    while ((readout = pmReadoutNext (fpi) != NULL) {
+		pmFileIOChecks (fpi);
+
+		// run the actual photometry analysis
+		psphotReadout (readout, fpi, config);
+	    }
+        }
+    }
+    psphotOutputClose (data);
+    return true;
+}
Index: /trunk/psphot/src/testPSphotLoop.c
===================================================================
--- /trunk/psphot/src/testPSphotLoop.c	(revision 6522)
+++ /trunk/psphot/src/testPSphotLoop.c	(revision 6522)
@@ -0,0 +1,45 @@
+# include "psphot.h"
+
+bool psphotLoop (psphotData *data, ppConfig *config) {
+
+    psRegion region = {0,0,0,0};
+    pmFPA *fpa = data->input->fpa;
+    pmFPAiterator *fpi = pmFPAiteratorAlloc (fpa, region);
+
+    // files associated with the science image
+    pmFileDefine (fpi, config->camera, "PPIMAGE.INPUT");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.OUTPUT.HEAD");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.OUTPUT.DATA");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.BACKGND");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.BACKSUB");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.RESID");
+    pmFileDefine (fpi, config->camera, "PPIMAGE.PSF");
+    pmFileIOChecks (fpi);
+
+    while ((chip = pmChipNext (fpi)) != NULL) {
+
+        psLogMsg ("psphot", 4, "Chip %d: %x %x\n", i, chip->exists, chip->process);
+        if (! chip->process) { continue; }
+	pmFileIOChecks (fpi);
+
+	while ((cell = pmCellNext (fpi)) != NULL) {
+
+            psLogMsg ("psphot", 4, "Cell %d: %x %x\n", j, cell->exists, cell->process);
+            if (! cell->process) { continue; }
+	    pmFileIOChecks (fpi);
+
+	    // process each of the readouts
+	    while ((readout = pmReadoutNext (fpi)) != NULL) {
+		pmFileIOChecks (fpi);
+		
+		// run the actual photometry analysis
+		psphotReadout (readout, config);
+
+		// write out the desired output dataset(s)
+		psphotOutput (readout, config);
+	    }
+	}
+    }
+    pmFileClose (fpi);
+    return true;
+}
