Index: /trunk/psphot/src/Makefile.am
===================================================================
--- /trunk/psphot/src/Makefile.am	(revision 6310)
+++ /trunk/psphot/src/Makefile.am	(revision 6311)
@@ -1,16 +1,15 @@
-lib_LTLIBRARIES = libpsphot.la
-bin_PROGRAMS = psphot psphotTest
+# lib_LTLIBRARIES = libpsphot.la
+# libpsphot_la_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(psphot_CFLAGS)
+# libpsphot_la_LDFLAGS = $(PSMODULE_LIBS) $(PSLIB_LIBS)
 
-libpsphot_la_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(psphot_CFLAGS)
-libpsphot_la_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS)
+bin_PROGRAMS = psphot
+psphot_CPPFLAGS = $(PSLIB_CFLAGS) $(PSMODULE_CFLAGS) $(psphot_CFLAGS)
+psphot_LDFLAGS = $(PSLIB_LIBS) $(PSMODULE_LIBS)
 
-psphot_CPPFLAGS = $(libpsphot_la_CPPFLAGS)
-psphot_LDADD = libpsphot.la
+# psphot_CPPFLAGS = $(libpsphot_la_CPPFLAGS)
+# psphot_LDFLAGS =  $(PSMODULE_LIBS) $(PSLIB_LIBS)
+# psphot_LDADD = libpsphot.la
 
-psphotTest_CPPFLAGS = $(libpsphot_la_CPPFLAGS)
-psphotTest_LDADD = libpsphot.la
-
-
-libpsphot_la_SOURCES =		\
+psphot_SOURCES =		\
 	psphotReadout.c		\
 	psphotImageStats.c	\
@@ -46,20 +45,12 @@
 	pmModelFitSet.c		\
 	pmCellSetMask.c		\
-	pmSourceFitSet.c     
-
-
-psphot_SOURCES =		\
+	pmSourceFitSet.c     	\
 	psphot.c		\
 	psphotArguments.c	\
 	psphotParseCamera.c	\
-	psphotImageLoop.c	\
-	psphotModelTest.c
+	psphotModelTest.c	\
+	psphotImageLoop.c	
 
-psphotTest_SOURCES =		\
-	psphotTest.c		\
-	psImageJpeg.c		\
-	psphotTestArguments.c
-
-include_HEADERS =		\
+noinst_HEADERS =		\
 	psLibUtils.h		\
 	psModulesUtils.h	\
Index: /trunk/psphot/src/pmCellSetMask.c
===================================================================
--- /trunk/psphot/src/pmCellSetMask.c	(revision 6310)
+++ /trunk/psphot/src/pmCellSetMask.c	(revision 6311)
@@ -6,4 +6,7 @@
 
     // mask the excluded outer pixels
+    // these coordinates refer to the parent image
+    // these bounds will saturate on the subimage
+    // negative upper bounds will subtract from the *subimage*
     float XMIN  = psMetadataLookupF32 (&status, recipe, "XMIN");
     float XMAX  = psMetadataLookupF32 (&status, recipe, "XMAX");
@@ -17,5 +20,9 @@
         pmReadout *readout = readouts->data[i]; // The readout of interest
 
+	// psRegionForImage creates a region for the subimage, not the parent
+	// XXX I propose that psRegionForImage treat the region as referring to the parent...
 	psRegion keep = psRegionForImage (readout->image, valid);
+
+	// psImageKeepRegion assumes the region refers to the parent coordinates
 	psImageKeepRegion (readout->mask, keep, "OR", PSPHOT_MASK_INVALID);
     }
Index: /trunk/psphot/src/psLibUtils.h
===================================================================
--- /trunk/psphot/src/psLibUtils.h	(revision 6310)
+++ /trunk/psphot/src/psLibUtils.h	(revision 6311)
@@ -14,4 +14,5 @@
 bool	     psLineInit (psLine *line);
 bool	     psLineAdd (psLine *line, char *format, ...);
+int          psStringStrip (char *string);
 
 # endif
Index: /trunk/psphot/src/psLine.c
===================================================================
--- /trunk/psphot/src/psLine.c	(revision 6310)
+++ /trunk/psphot/src/psLine.c	(revision 6311)
@@ -47,2 +47,20 @@
 }
 
+#ifndef whitespace
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+#endif
+
+/* Strip whitespace from the start and end of STRING. */
+int psStringStrip (char *string) {
+
+  int i;
+
+  if (string == (char *) NULL) return (FALSE);
+
+  for (i = 0; whitespace (string[i]); i++);
+  if (i) memmove (string, string + i, strlen(string+i)+1);
+  for (i = strlen (string) - 1; (i > 0) && whitespace (string[i]); i--);
+  string[++i] = 0;
+  return (i);
+
+}
Index: /trunk/psphot/src/psModulesUtils.c
===================================================================
--- /trunk/psphot/src/psModulesUtils.c	(revision 6310)
+++ /trunk/psphot/src/psModulesUtils.c	(revision 6311)
@@ -193,4 +193,5 @@
   config->recipe = NULL;
   config->arguments = NULL;
+  config->options = NULL;
   config->database = NULL;
 
Index: /trunk/psphot/src/psModulesUtils.h
===================================================================
--- /trunk/psphot/src/psModulesUtils.h	(revision 6310)
+++ /trunk/psphot/src/psModulesUtils.h	(revision 6311)
@@ -22,5 +22,6 @@
     psMetadata *camera;                 // The camera configuration
     psMetadata *recipe;                 // The recipe (i.e., specific setups)
-    psMetadata *arguments;              // The command-line arguments
+    psMetadata *arguments;              // Command-line arguments
+    psMetadata *options;                // Command-line recipe options
     psDB       *database;               // Database handle
 } ppConfig;
Index: /trunk/psphot/src/psphot.c
===================================================================
--- /trunk/psphot/src/psphot.c	(revision 6310)
+++ /trunk/psphot/src/psphot.c	(revision 6311)
@@ -15,6 +15,6 @@
     ppFile *input = psphotParseCamera (config);
 
-    // run a single-model test if desired - XXX push in psphotImageLoop?
-    // psphotModelTest (input, options);
+    // check on output mode,format, setup basic filename, etc
+    psphotOutputPrep (input, config);
 
     // call psphot for each readout
Index: /trunk/psphot/src/psphot.h
===================================================================
--- /trunk/psphot/src/psphot.h	(revision 6310)
+++ /trunk/psphot/src/psphot.h	(revision 6311)
@@ -24,5 +24,5 @@
 bool            psphotImageLoop (ppFile *input, ppConfig *config);
 
-bool            psphotModelTest (pmReadout *readout, psMetadata *config);
+bool            psphotModelTest (pmReadout *readout, psMetadata *arguments, psMetadata *recipe);
 bool            psphotReadout (pmReadout *readout, psMetadata *config);
 bool            ppImageLoadPixels (ppFile *input, psDB *db, int chipNum, int cellNum);
@@ -36,5 +36,5 @@
 bool            psphotBasicDeblend (psArray *sources, psMetadata *config, psStats *sky);
 pmPSF          *psphotChoosePSF (psMetadata *config, psArray *sources, psStats *sky);
-void            psphotOutput (pmReadout *readout, psMetadata *config);
+void            psphotOutput (pmReadout *readout, psMetadata *arguments);
 
 // optional object analysis steps
@@ -80,5 +80,5 @@
 bool 	     	pmMomentsWriteText (psArray *sources, char *filename);
 
-bool 		psphotSamplePSFs (psMetadata *config, pmPSF *psf, psImage *image);
+bool            psphotSamplePSFs (pmPSF *psf, psImage *image, char *output);
 bool 		psphotDumpMoments (psMetadata *config, psArray *sources);
 int             psphotSaveImage (psMetadata *header, psImage *image, char *filename);
@@ -86,4 +86,8 @@
 int  	     	pmSourcesDophotType (pmSource *source);
 bool            psMetadataItemTransfer (psMetadata *out, psMetadata *in, char *key);
+
+char           *psphotSplitName (psMetadata *header);
+void            psphotOutputPrep (ppFile *file, ppConfig *config);
+char           *psphotNameSubstitute (char *input, char *replace, char *key);
 
 bool            psphotMagnitudes (psMetadata *config, psArray *sources, pmPSF *psf);
Index: /trunk/psphot/src/psphotArguments.c
===================================================================
--- /trunk/psphot/src/psphotArguments.c	(revision 6310)
+++ /trunk/psphot/src/psphotArguments.c	(revision 6311)
@@ -1,9 +1,11 @@
 # include "psphot.h"
 
-static void usage (psMetadata *arguments) ;
+static void usage (void);
 
 ppConfig *psphotArguments (int *argc, char **argv) {
 
     int N;
+
+    if (*argc == 1) usage ();
 
     // basic pslib options
@@ -22,10 +24,32 @@
 
     // arguments (must be supplied for each run, or not used)
-    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-psf", 0, "input psf file", "");
-    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-mask", 0,   "Name of the mask image", "");
-    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-resid", 0,  "Name of the output residual image", "");
-    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-weight", 0, "Name of the weight image", "");
-    psMetadataAddS32(config->arguments, PS_LIST_TAIL, "-chip", 0, "Chip number to process (if positive)", -1);
-    
+    // mask image (input) is used by psphotImageLoop
+    if ((N = psArgumentGet (*argc, argv, "-mask"))) {
+	psArgumentRemove (N, argc, argv);
+	psMetadataAddStr (config->arguments, PS_LIST_TAIL, "MASK_IMAGE", PS_META_REPLACE, "", psStringCopy(argv[N]));
+	psArgumentRemove (N, argc, argv);
+    }
+
+    // weight image (input) is used by psphotImageLoop
+    if ((N = psArgumentGet (*argc, argv, "-weight"))) {
+	psArgumentRemove (N, argc, argv);
+	psMetadataAddStr (config->arguments, PS_LIST_TAIL, "WEIGHT_IMAGE", PS_META_REPLACE, "", psStringCopy(argv[N]));
+	psArgumentRemove (N, argc, argv);
+    }
+
+    // residual image (output) is used by psphotOutput
+    if ((N = psArgumentGet (*argc, argv, "-resid"))) {
+	psArgumentRemove (N, argc, argv);
+	psMetadataAddStr (config->arguments, PS_LIST_TAIL, "RESID_IMAGE", PS_META_REPLACE, "", psStringCopy(argv[N]));
+	psArgumentRemove (N, argc, argv);
+    }
+
+    // chip selection is used to limit chips to be processed
+    if ((N = psArgumentGet (*argc, argv, "-chip"))) {
+	psArgumentRemove (N, argc, argv);
+	psMetadataAddStr (config->arguments, PS_LIST_TAIL, "CHIP_SELECTION", PS_META_REPLACE, "", psStringCopy(argv[N]));
+	psArgumentRemove (N, argc, argv);
+    }
+
     // run the test model (requires X,Y coordinate)
     if ((N = psArgumentGet (*argc, argv, "-modeltest"))) {
@@ -58,36 +82,39 @@
     }
 
-    // Parse command-line overrides of recipe values
-    psMetadata *recipe = psMetadataAlloc ();
+    // these other options override the recipe options
+    config->options = psMetadataAlloc ();
 
-    psMetadataAddStr(config->arguments, PS_LIST_TAIL, "-photcode", 0, "photometry code", "NONE");
-    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "-break", 0, "", "NONE");
-    psMetadataAddS32 (config->arguments, PS_LIST_TAIL, "-fitmode", 0, "", 2);
-
-    // analysis region : XXX override recipe 
-    if ((N = psArgumentGet (*argc, argv, "-photcode"))) {
+    // PSF : optional psf file to be loaded
+    if ((N = psArgumentGet (*argc, argv, "-psf"))) {
 	psArgumentRemove (N, argc, argv);
-	psMetadataAddStr (recipe, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "", psStringCopy(argv[N]));
+	psMetadataAddStr (config->options, PS_LIST_TAIL, "PSF_INPUT_FILE", PS_META_REPLACE, "", psStringCopy(argv[N]));
 	psArgumentRemove (N, argc, argv);
     }
 
-    // analysis region : XXX override recipe 
-    if ((N = psArgumentGet (*argc, argv, "-break"))) {
+    // photcode : used in output to supplement header data (argument or recipe?)
+    if ((N = psArgumentGet (*argc, argv, "-photcode"))) {
 	psArgumentRemove (N, argc, argv);
-	psMetadataAddStr (recipe, PS_LIST_TAIL, "BREAK_POINT", PS_META_REPLACE, "", psStringCopy(argv[N]));
+	psMetadataAddStr (config->options, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "", psStringCopy(argv[N]));
 	psArgumentRemove (N, argc, argv);
     }
 
-    // analysis region : XXX override recipe 
-    if ((N = psArgumentGet (*argc, argv, "-fitmode"))) {
+    // break : used from recipe throughout psphotReadout 
+    if ((N = psArgumentGet (*argc, argv, "-break"))) {
 	psArgumentRemove (N, argc, argv);
-	psMetadataAddStr (recipe, PS_LIST_TAIL, "FITMODE", PS_META_REPLACE, "", psStringCopy(argv[N]));
+	psMetadataAddStr (config->options, PS_LIST_TAIL, "BREAK_POINT", PS_META_REPLACE, "", psStringCopy(argv[N]));
 	psArgumentRemove (N, argc, argv);
     }
 
-    // analysis region : XXX override recipe 
+    // fitmode : used from recipe throughout psphotReadout 
+    if ((N = psArgumentGet (*argc, argv, "-fitmode"))) {
+	psArgumentRemove (N, argc, argv);
+	psMetadataAddStr (config->options, PS_LIST_TAIL, "FITMODE", PS_META_REPLACE, "", psStringCopy(argv[N]));
+	psArgumentRemove (N, argc, argv);
+    }
+
+    // analysis region : overrides recipe value, used in psphotReadout/psphotEnsemblePSF
     if ((N = psArgumentGet (*argc, argv, "-region"))) {
 	psArgumentRemove (N, argc, argv);
-	psMetadataAddStr (recipe, PS_LIST_TAIL, "ANALYSIS_REGION", 0, "", psStringCopy(argv[N]));
+	psMetadataAddStr (config->options, PS_LIST_TAIL, "ANALYSIS_REGION", 0, "", psStringCopy(argv[N]));
 	psArgumentRemove (N, argc, argv);
     }
@@ -96,5 +123,5 @@
     while ((N = psArgumentGet (*argc, argv, "-D"))) {
 	psArgumentRemove (N, argc, argv);
-	psMetadataAddStr (recipe, PS_LIST_TAIL, argv[N], 0, "", argv[N+1]);
+	psMetadataAddStr (config->options, PS_LIST_TAIL, argv[N], 0, "", argv[N+1]);
 	psArgumentRemove (N, argc, argv);
 	psArgumentRemove (N, argc, argv);
@@ -104,5 +131,5 @@
     while ((N = psArgumentGet (*argc, argv, "-Df"))) {
 	psArgumentRemove (N, argc, argv);
-	psMetadataAddF32 (recipe, PS_LIST_TAIL, argv[N], 0, "", atof(argv[N+1]));
+	psMetadataAddF32 (config->options, PS_LIST_TAIL, argv[N], 0, "", atof(argv[N+1]));
 	psArgumentRemove (N, argc, argv);
 	psArgumentRemove (N, argc, argv);
@@ -112,26 +139,22 @@
     while ((N = psArgumentGet (*argc, argv, "-Di"))) {
 	psArgumentRemove (N, argc, argv);
-	psMetadataAddS32 (recipe, PS_LIST_TAIL, argv[N], 0, "", atoi(argv[N+1]));
+	psMetadataAddS32 (config->options, PS_LIST_TAIL, argv[N], 0, "", atoi(argv[N+1]));
 	psArgumentRemove (N, argc, argv);
 	psArgumentRemove (N, argc, argv);
     }
 
-    // place the recipe options on the arguments stack
-    psMetadataAddPtr (config->arguments, PS_LIST_TAIL, "RECIPE.OPTIONS", PS_DATA_UNKNOWN, "", recipe);
-
-    if (!psArgumentParse(config->arguments, argc, argv)) usage (config->arguments);
-    if (*argc != 3) usage (config->arguments);
+    if (*argc != 3) usage ();
 
     // input and output positions are fixed
-    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "-input",  PS_META_REPLACE, "", argv[1]);
-    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "-output", PS_META_REPLACE, "", argv[2]);
+    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "INPUT_FILE",  PS_META_REPLACE, "", argv[1]);
+    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "OUTPUT_ROOT", PS_META_REPLACE, "", argv[2]);
 
+    psTrace(__func__, 1, "Done with psphotArguments...\n");
     return (config);
 }
 
-static void usage (psMetadata *arguments) {
+static void usage (void) {
 
     fprintf (stderr, "USAGE: psphot (image) (output)\n");
-    psArgumentHelp (arguments);
     exit (2);
 }
Index: /trunk/psphot/src/psphotDefinePixels.c
===================================================================
--- /trunk/psphot/src/psphotDefinePixels.c	(revision 6310)
+++ /trunk/psphot/src/psphotDefinePixels.c	(revision 6311)
@@ -1,4 +1,5 @@
 # include "psphot.h"
 
+// x,y are defined in the parent image coords of readout->image
 bool psphotDefinePixels(pmSource *mySource, 
 			const pmReadout *readout,
Index: /trunk/psphot/src/psphotFindPeaks.c
===================================================================
--- /trunk/psphot/src/psphotFindPeaks.c	(revision 6310)
+++ /trunk/psphot/src/psphotFindPeaks.c	(revision 6311)
@@ -16,6 +16,10 @@
 
     psImage *smooth = psImageCopy (NULL, readout->image, PS_TYPE_F32);
+    psphotSaveImage (NULL, smooth, "presmooth.fits");
+
     psImageSmooth (smooth, SIGMA, NSIGMA);
     psLogMsg ("psphot", 4, "smooth: %f sec\n", psTimerMark ("psphot"));
+
+    psphotSaveImage (NULL, smooth, "smooth.fits");
 
     psTimerStart ("psphot");
Index: /trunk/psphot/src/psphotGrowthCurve.c
===================================================================
--- /trunk/psphot/src/psphotGrowthCurve.c	(revision 6310)
+++ /trunk/psphot/src/psphotGrowthCurve.c	(revision 6311)
@@ -15,7 +15,7 @@
     pmModel *modelRef = pmModelAlloc(psf->type);
 
-    // use this image region
-    xc = 0.5*readout->image->numCols;
-    yc = 0.5*readout->image->numRows;
+    // use center of the image 
+    xc = 0.5*(readout->image->numCols + readout->image->col0);
+    yc = 0.5*(readout->image->numRows + readout->image->row0);
     dx = psf->growth->maxRadius + 1;
     dy = psf->growth->maxRadius + 1;
Index: /trunk/psphot/src/psphotImageBackground.c
===================================================================
--- /trunk/psphot/src/psphotImageBackground.c	(revision 6310)
+++ /trunk/psphot/src/psphotImageBackground.c	(revision 6311)
@@ -28,6 +28,6 @@
 	double frnd = psRandomUniform (rnd);
 	int pixel = Npixels * frnd;
-	int ix = pixel / image->numCols;
-	int iy = pixel % image->numCols;
+	int ix = pixel % image->numCols;
+	int iy = pixel / image->numCols;
 	float value = image->data.F32[iy][ix];
 	if (fabs(value - Sky) > dSky) continue;
Index: /trunk/psphot/src/psphotImageLoop.c
===================================================================
--- /trunk/psphot/src/psphotImageLoop.c	(revision 6310)
+++ /trunk/psphot/src/psphotImageLoop.c	(revision 6311)
@@ -5,5 +5,4 @@
     bool status;
     ppImageLoadDepth imageLoadDepth;
-    char filename[1024];
 
     // determine the load depth
@@ -27,8 +26,4 @@
     }
 
-    char *outputRoot = psMetadataLookupPtr (&status, config->arguments, "-output");
-    if (!status) psAbort ("psphot", "output file not specified");
-
-    int Nout = 0;
     for (int i = 0; i < file->fpa->chips->n; i++) {
         pmChip *chip = file->fpa->chips->data[i]; // Chip of interest in input image
@@ -53,4 +48,6 @@
             }
 
+	    // 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
 	    pmCellSetWeights(cell);
 
@@ -58,23 +55,13 @@
 	    pmCellSetMask (cell, config->recipe); 
 
-
 	    // process each of the readouts
 	    for (int k = 0; k < cell->readouts->n; k++) {
 		pmReadout *readout = cell->readouts->data[k]; // Readout of interest in input image
 
-		// psphotSaveImage (NULL, readout->image, "image.fits");
-		// psphotSaveImage (NULL, readout->weight, "weight.fits");
-		// psphotSaveImage (NULL, readout->mask, "mask.fits");
+		// run a single-model test if desired
+		psphotModelTest (readout, config->arguments, config->recipe);
 
 		psphotReadout (readout, config->recipe);
-
-		// XXX EAM : temporarily write out only CMF with fixed extension
-		sprintf (filename, "%s.%02d.cmf", outputRoot, Nout);
-		psMetadata *header = pmReadoutGetHeader (readout);
-
-		psArray *sources = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.SOURCES");
-
-		pmSourcesWriteCMF (sources, filename, header);
-		Nout++;
+		psphotOutput (readout, config->arguments);
 	    }
         }
Index: /trunk/psphot/src/psphotModelTest.c
===================================================================
--- /trunk/psphot/src/psphotModelTest.c	(revision 6310)
+++ /trunk/psphot/src/psphotModelTest.c	(revision 6311)
@@ -2,5 +2,5 @@
 # include "psEllipse.h"
 
-bool psphotModelTest (pmReadout *readout, psMetadata *config) {
+bool psphotModelTest (pmReadout *readout, psMetadata *arguments, psMetadata *recipe) {
 
     bool status;
@@ -14,8 +14,8 @@
 
     // run model fitting tests on a single source
-    if (!psMetadataLookupBool (&status, config, "TEST_FIT")) return false;
+    if (!psMetadataLookupBool (&status, arguments, "TEST_FIT")) return false;
 
     // what fitting mode to use?
-    char *psfModeWord = psMetadataLookupPtr (&status, config, "TEST_FIT_MODE");
+    char *psfModeWord = psMetadataLookupPtr (&status, arguments, "TEST_FIT_MODE");
     if (!status) {
 	psfModeWord = psStringCopy ("EXT");
@@ -25,5 +25,5 @@
     // in psfMode, psf sets the model type
     if (psfMode) {
-	char *psfFile = psMetadataLookupPtr (&status, config, "PSF_INPUT_FILE");
+	char *psfFile = psMetadataLookupPtr (&status, arguments, "PSF_INPUT_FILE");
 	if (!status) psAbort ("psphotModelTest", "PSF_INPUT_FILE not supplied");
 	psMetadata *psfData = psMetadataConfigParse (NULL, &Nfail, psfFile, FALSE);
@@ -32,12 +32,20 @@
     } else {
 	// find the model: supplied by user or first in the PSF_MODEL list
-	char *modelName  = psMetadataLookupPtr (&status, config, "TEST_FIT_MODEL");
+	char *modelName  = psMetadataLookupPtr (&status, arguments, "TEST_FIT_MODEL");
 	if (modelName == NULL) {
 	    // get the list pointers for the PSF_MODEL entries
-	    psMetadataItem *mdi = psMetadataLookup (config, "PSF_MODEL");
-	    if (mdi == NULL) psAbort ("psphotChoosePSF", "missing PSF_MODEL selection");
+
+	    psList *list = NULL;
+	    psMetadataItem *mdi = psMetadataLookup (recipe, "PSF_MODEL");
+	    if (mdi == NULL) psAbort ("psphotModelTest", "missing PSF_MODEL selection");
+	    if (mdi->type == PS_DATA_STRING) {
+		list = psListAlloc(NULL);
+		psListAdd (list, PS_LIST_HEAD, mdi);
+	    } else {
+		if (mdi->type != PS_DATA_METADATA_MULTI) psAbort ("psphotChoosePSF", "missing PSF_MODEL selection");
+		list = psMemIncrRefCounter(mdi->data.list);
+	    }
 
 	    // take the first list element
-	    psList *list = (psList *) mdi->data.list;
 	    item = psListGet (list, PS_LIST_HEAD);
 	    modelName = item->data.V;
@@ -48,27 +56,27 @@
 
     // find the fitting parameters (try test values first)
-    float INNER = psMetadataLookupF32 (&status, config, "TEST_FIT_INNER_RADIUS");
+    float INNER = psMetadataLookupF32 (&status, arguments, "TEST_FIT_INNER_RADIUS");
     if (!status) {
-	INNER = psMetadataLookupF32 (&status, config, "SKY_INNER_RADIUS");
+	INNER = psMetadataLookupF32 (&status, recipe, "SKY_INNER_RADIUS");
     }
 
-    float OUTER = psMetadataLookupF32 (&status, config, "TEST_FIT_OUTER_RADIUS");
+    float OUTER = psMetadataLookupF32 (&status, arguments, "TEST_FIT_OUTER_RADIUS");
     if (!status) {
-	OUTER = psMetadataLookupF32 (&status, config, "SKY_OUTER_RADIUS");
+	OUTER = psMetadataLookupF32 (&status, recipe, "SKY_OUTER_RADIUS");
     }
 
-    float RADIUS = psMetadataLookupF32 (&status, config, "TEST_FIT_RADIUS");
+    float RADIUS = psMetadataLookupF32 (&status, arguments, "TEST_FIT_RADIUS");
     if (!status) {
-	RADIUS = psMetadataLookupF32 (&status, config, "PSF_FIT_RADIUS");
+	RADIUS = psMetadataLookupF32 (&status, recipe, "PSF_FIT_RADIUS");
     }
 
-    float mRADIUS = psMetadataLookupF32 (&status, config, "TEST_MOMENTS_RADIUS");
+    float mRADIUS = psMetadataLookupF32 (&status, arguments, "TEST_MOMENTS_RADIUS");
     if (!status) {
-	mRADIUS = psMetadataLookupF32 (&status, config, "PSF_MOMENTS_RADIUS");
+	mRADIUS = psMetadataLookupF32 (&status, recipe, "PSF_MOMENTS_RADIUS");
     }
 
     // define the source of interest
-    float xObj     = psMetadataLookupF32 (&status, config, "TEST_FIT_X");
-    float yObj     = psMetadataLookupF32 (&status, config, "TEST_FIT_Y");
+    float xObj     = psMetadataLookupF32 (&status, arguments, "TEST_FIT_X");
+    float yObj     = psMetadataLookupF32 (&status, arguments, "TEST_FIT_Y");
 
     // construct the source structures
@@ -111,5 +119,5 @@
 	}
 	sprintf (name, "TEST_FIT_PAR%d", i);
-	value = psMetadataLookupF32 (&status, config, name);
+	value = psMetadataLookupF32 (&status, arguments, name);
 	if (status) {
 	    params[i] = value;
@@ -145,5 +153,5 @@
     psImageKeepCircle (source->mask, xObj, yObj, RADIUS, "OR", PSPHOT_MASK_MARKED);
 
-    char *fitset = psMetadataLookupPtr (&status, config, "TEST_FIT_SET");
+    char *fitset = psMetadataLookupPtr (&status, arguments, "TEST_FIT_SET");
     if (status) {
 	status = psphotFitSet (source, model, fitset, psfMode);
Index: /trunk/psphot/src/psphotOutput.c
===================================================================
--- /trunk/psphot/src/psphotOutput.c	(revision 6310)
+++ /trunk/psphot/src/psphotOutput.c	(revision 6311)
@@ -1,8 +1,146 @@
 # include "psphot.h"
 
+static int   extNumber  = -1;
+
+static char *outputName = NULL;
+static char *outputRoot = NULL;
+static char *outputMode = NULL;
+static char *outputFormat = NULL;
+
+static char *extNumberFormat = NULL;
+static char *extNameKey = NULL;
+static char *extRoot    = NULL;
+
+void psphotOutputPrep (ppFile *file, ppConfig *config) {
+
+    bool status;
+
+    outputRoot   = psMetadataLookupPtr (&status, config->arguments, "OUTPUT_ROOT");
+    if (!status) psAbort ("psphot", "output file not specified");
+
+    outputName   = psMetadataLookupPtr (&status, config->recipe, "OUTPUT_NAME");
+    outputMode   = psMetadataLookupPtr (&status, config->recipe, "OUTPUT_MODE");
+    outputFormat = psMetadataLookupPtr (&status, config->recipe, "OUTPUT_FORMAT");
+
+    // rules to construct output names
+    extNumberFormat = psMetadataLookupPtr (&status, config->recipe, "EXTNUMBER_FORMAT");
+    extNameKey      = psMetadataLookupPtr (&status, config->recipe, "EXTNAME");
+    extRoot         = psMetadataLookupPtr (&status, config->recipe, "EXTROOT");
+
+    if (extNumberFormat == NULL) {
+	extNumberFormat = psStringCopy ("%02d");
+    }
+
+    psStringStrip (outputName);
+    psStringStrip (extNameKey);
+    psStringStrip (extRoot);
+
+    // validate the outputMode and outputFormat
+    status = false;
+    status |= !strcasecmp (outputFormat, "TEXT");
+    status |= !strcasecmp (outputFormat, "OBJ");
+    status |= !strcasecmp (outputFormat, "SX");
+    status |= !strcasecmp (outputFormat, "CMP");
+    status |= !strcasecmp (outputFormat, "CMF");
+    if (!status) {
+	psLogMsg ("psphot", PS_LOG_ERROR, "invalid output format %s", outputFormat);
+	exit (1);
+    }
+
+    // validate the outputMode and outputFormat
+    status = false;
+    status |= !strcasecmp (outputMode, "MEF");
+    status |= !strcasecmp (outputMode, "SPLIT");
+    if (!status) {
+	psLogMsg ("psphot", PS_LOG_ERROR, "invalid output mode %s", outputMode);
+	exit (1);
+    }
+
+    // for MEF output, we need to open a file up front
+    if (!strcasecmp (outputMode, "MEF")) {
+	psLogMsg ("psphot", PS_LOG_ERROR, "MEF output mode unavailable");
+	exit (1);
+    }
+
+    return;
+}
+
+// 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 = psMetadataLookupPtr (&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");
+	}
+	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;
+}
+
 // output functions: we have several fixed modes (sx, obj, cmp)
-void psphotOutput (pmReadout *readout, psMetadata *config) {
+void psphotOutput (pmReadout *readout, psMetadata *arguments) {
 
     bool status;
+    char *outputFile;
 
     psTimerStart ("psphot");
@@ -13,11 +151,24 @@
     pmPSF *psf = psMetadataLookupPtr (&status, readout->analysis, "PSPHOT.PSF");
 
-    char *outputMode = psMetadataLookupPtr (&status, config, "OUTPUT_MODE");
-    char *outputFile = psMetadataLookupPtr (&status, config, "OUTPUT_FILE");
-    char *residImage = psMetadataLookupPtr (&status, config, "RESID_IMAGE");
-    char *psfFile    = psMetadataLookupPtr (&status, config, "PSF_OUTPUT_FILE");
-
+    // starting value is -1
+    extNumber ++;
+
+    // for SPLIT output, we need to open a file for each output call
+    if (!strcasecmp (outputMode, "SPLIT")) {
+	outputFile = psphotSplitName (header);
+    } else {
+	// construct appropriate extname
+	psAbort ("psphotOutput", "programming error");
+    }
+    
+    fprintf (stderr, "output file: %s\n", outputFile);
+    return;
+
+    char *psfFile    = psMetadataLookupPtr (&status, arguments, "PSF_OUTPUT_FILE");
+    char *psfSample  = psMetadataLookupPtr (&status, arguments, "PSF_SAMPLE_FILE");
+    char *residImage = psMetadataLookupPtr (&status, arguments, "RESID_IMAGE");
+
+    if (psfSample != NULL) psphotSamplePSFs (psf, readout->image, psfSample);
     if (residImage != NULL) psphotSaveImage (header, readout->image, residImage);
-    psphotSamplePSFs (config, psf, readout->image);
 
     if (psfFile != NULL) {
@@ -30,30 +181,30 @@
 	return;
     }
-    if (outputMode == NULL) {
-	psLogMsg ("output", 3, "no data output mode selected");
+    if (outputFormat == NULL) {
+	psLogMsg ("output", 3, "no data output format selected");
 	return;
     }
-    if (!strcasecmp (outputMode, "SX")) {
+    if (!strcasecmp (outputFormat, "SX")) {
 	pmSourcesWriteSX (sources, outputFile);
 	return;
     }
-    if (!strcasecmp (outputMode, "OBJ")) {
+    if (!strcasecmp (outputFormat, "OBJ")) {
 	pmSourcesWriteOBJ (sources, outputFile);
 	return;
     }
-    if (!strcasecmp (outputMode, "CMP")) {
+    if (!strcasecmp (outputFormat, "CMP")) {
 	pmSourcesWriteCMP (sources, outputFile, header);
 	return;
     }
-    if (!strcasecmp (outputMode, "CMF")) {
+    if (!strcasecmp (outputFormat, "CMF")) {
 	pmSourcesWriteCMF (sources, outputFile, header);
 	return;
     }
-    if (!strcasecmp (outputMode, "TEXT")) {
+    if (!strcasecmp (outputFormat, "TEXT")) {
 	pmSourcesWriteText (sources, outputFile);
 	return;
     }
 
-    psAbort ("psphot", "unknown output mode %s", outputMode);
+    psAbort ("psphot", "unknown output mode %s", outputFormat);
 }
 
@@ -560,8 +711,5 @@
 }
 
-
-bool psphotSamplePSFs (psMetadata *config, pmPSF *psf, psImage *image) {
-
-    bool status;
+bool psphotSamplePSFs (pmPSF *psf, psImage *image, char *output) {
 
     // make sample PSFs for 4 corners and the center
@@ -569,7 +717,4 @@
 
     // optional dump of all rough source data
-    char *output = psMetadataLookupPtr (&status, config, "PSF_SAMPLE_FILE");
-    if (!status) return false;
-    if (output == NULL) return false;
     if (output[0] == 0) return false;
 
@@ -580,4 +725,5 @@
     psFits *fits = psFitsOpen (output, "w");
 
+    // the centers are in parent coordinates; they do not need to correspond to valid pixels...
     sample = pmModelPSFatXY (image, modelEXT, psf, 25, 25, 25, 25);
     psFitsWriteImage (fits, NULL, sample, 0);
Index: /trunk/psphot/src/psphotParseCamera.c
===================================================================
--- /trunk/psphot/src/psphotParseCamera.c	(revision 6310)
+++ /trunk/psphot/src/psphotParseCamera.c	(revision 6311)
@@ -1,11 +1,16 @@
 # include "psphot.h"
+
+# define METADATA_ADD_DEFAULT(CONFIG, TYPE, NAME, VALUE, COMMENT)\
+    { psMetadataItem *ITEM; \
+      ITEM = psMetadataLookup (CONFIG, NAME); \
+      if (ITEM == NULL) { \
+	psMetadataAdd##TYPE (CONFIG, PS_LIST_TAIL, NAME, 0, COMMENT, VALUE); \
+      } else { psFree (ITEM); } }
 
 ppFile *psphotParseCamera (ppConfig *config) {
 
-    bool status;
-
     ppFile *input = ppFileAlloc ();
 
-    input->filename = psMemIncrRefCounter(psMetadataLookupStr(NULL, config->arguments, "-input"));
+    input->filename = psMemIncrRefCounter(psMetadataLookupStr(NULL, config->arguments, "INPUT_FILE"));
 
     // Open the input image
@@ -33,8 +38,7 @@
     }
 
-    // Determine the correct recipe to use
-    // if the user specifies a recipe, no default values are supplied
+    // Determine the correct recipe to use (from camera or from user)
+    // if config->recipe is not NULL, it is a user-supplied recipe
     if (!config->recipe) {
-
 	config->recipe = pmConfigRecipeFromCamera(config->camera, PSPHOT_RECIPE);
 	if (config->recipe == NULL) {
@@ -43,9 +47,8 @@
 	}
     }
-    
-    // recipe override values:
-    psMetadata *recipe = psMetadataLookupPtr (&status, config->arguments, "RECIPE.OPTIONS");
+
+    // recipe override values (command-line options):
     psMetadataItem *item = NULL;
-    psMetadataIterator *iter = psMetadataIteratorAlloc (recipe, PS_LIST_HEAD, NULL);
+    psMetadataIterator *iter = psMetadataIteratorAlloc (config->options, PS_LIST_HEAD, NULL);
     while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
 	psMetadataAddItem (config->recipe, item, PS_LIST_TAIL, PS_META_REPLACE);
@@ -54,17 +57,33 @@
     psFree (iter);
 
-    psMetadataAddStr (config->recipe, PS_LIST_TAIL, "FITMODE", 0, "", "NONE");
-    psMetadataAddStr (config->recipe, PS_LIST_TAIL, "PHOTCODE", 0, "", "NONE");
-    psMetadataAddStr (config->recipe, PS_LIST_TAIL, "BREAK_POINT", 0, "", "NONE");
+    // set default recipe values here
+    METADATA_ADD_DEFAULT (config->recipe, Str, "FITMODE", "NONE", "");
+    METADATA_ADD_DEFAULT (config->recipe, Str, "PHOTCODE", "NONE", "");
+    METADATA_ADD_DEFAULT (config->recipe, Str, "BREAK_POINT", "NONE", "");
+    METADATA_ADD_DEFAULT (config->recipe, Str, "OUTPUT_FORMAT", "CMP", "");
+    METADATA_ADD_DEFAULT (config->recipe, Str, "OUTPUT_MODE", "SPLIT", "");
 
-    // XXX EAM : extend this to allow an array of selected chips by name
     // Chip selection: if we are using a single chip, select it for each FPA
-    int chipNum = psMetadataLookupS32(NULL, config->arguments, "-chip"); // Chip number to work on
-    if (chipNum >= 0) {
-        if (! pmFPASelectChip(input->fpa, chipNum)) {
-            psErrorStackPrint(stderr, "Chip number %d doesn't exist in camera.\n", chipNum);
-            exit(EXIT_FAILURE);
+    // Chip numbers to work on: -chip 1,2,3,5,8,10
+    char *chips = psMetadataLookupStr(NULL, config->arguments, "CHIP_SELECTIONS"); 
+    if (chips != NULL) {
+	char *p = chips;
+	while (strlen(p)) {
+	    char *q = strchr (p, ',');
+	    if (q == NULL) { 
+		q = p + strlen(p);
+	    } else {
+		*q = 0;
+		q = q + 1;
+	    }
+	    int chipNum = atoi(p);
+	    // XXX EAM : extend this to allow an array of selected chips (by name)
+	    if (! pmFPASelectChip(input->fpa, chipNum)) {
+		psErrorStackPrint(stderr, "Chip number %d doesn't exist in camera.\n", chipNum);
+		exit(EXIT_FAILURE);
+	    }
+	    psLogMsg("psphot", PS_LOG_INFO, "Operating only on chip %d\n", chipNum);
+	    p = q;
         }
-        psLogMsg("psphot", PS_LOG_INFO, "Operating only on chip %d\n", chipNum);
     }
 
@@ -72,4 +91,5 @@
     input->fpa = pmFPAConstruct(config->camera);
 
+    psTrace(__func__, 1, "Done with psphotParseCamera...\n");
     return input;
 }
Index: /trunk/psphot/src/psphotReadout.c
===================================================================
--- /trunk/psphot/src/psphotReadout.c	(revision 6310)
+++ /trunk/psphot/src/psphotReadout.c	(revision 6311)
@@ -8,4 +8,8 @@
     psStats     *sky     = NULL;
     bool         status;
+
+    psphotSaveImage (NULL, readout->mask, "mask.fits");
+    psphotSaveImage (NULL, readout->image, "image.fits");
+    psphotSaveImage (NULL, readout->weight, "weight.fits");
 
     // measure image stats for initial guess 
