Index: /trunk/psastro/src/psastro.c
===================================================================
--- /trunk/psastro/src/psastro.c	(revision 6790)
+++ /trunk/psastro/src/psastro.c	(revision 6791)
@@ -3,11 +3,16 @@
 int main (int argc, char **argv) {
 
+    psTimerStart ("complete");
+
     psMetadata *header = NULL;
 
     // load configuration information
-    psMetadata *config = psastroArguments (&argc, argv);
+    pmConfig *config = psastroArguments (&argc, argv);
 
-    // load the input data (cmp file)
-    psArray *rawstars = psastroReadCMP (&header, argv[2]);
+    // load input data (config and images (signal, noise, mask)
+    psastroParseCamera (config);
+
+    // perform the astrometric solution
+    psastroDataLoop (input, config);
 
     // simple layout interpretation, basic WCS conversion
@@ -23,4 +28,6 @@
     psastroWriteCMP (fpa, argv[3]);
 
+    psLogMsg ("psphot", 3, "complete psphot run: %f sec\n", psTimerMark ("complete"));
+
     psFree (config);
     psFree (fpa);
Index: /trunk/psastro/src/psastro.h
===================================================================
--- /trunk/psastro/src/psastro.h	(revision 6790)
+++ /trunk/psastro/src/psastro.h	(revision 6791)
@@ -10,4 +10,30 @@
 # define toTPA toTangentPlane
 # define toSky projection
+
+// How much of the FPA to load at a time
+typedef enum {
+    PP_LOAD_NONE,                       // Don't load anything
+    PP_LOAD_FPA,                        // Load the entire FPA at once
+    PP_LOAD_CHIP,                       // Load by chip
+    PP_LOAD_CELL,                       // Load by cell
+} ppImageLoadDepth;
+
+// Configuration data
+typedef struct {
+    psMetadata *site;                   // The site configuration
+    psMetadata *camera;                 // The camera configuration
+    psMetadata *recipe;                 // The recipe (i.e., specific setups)
+    psMetadata *arguments;              // Command-line arguments
+    psMetadata *options;                // Command-line recipe options
+    psDB       *database;               // Database handle
+} ppConfig;
+
+// A file to process
+typedef struct {
+    char *filename;                     // File name
+    psFits *fits;                       // The FITS file handle
+    psMetadata *phu;                    // The FITS header
+    pmFPA *fpa;                         // The FPA, with pixels and extensions
+} ppFile;
 
 bool              pmAstromReadWCS (psPlaneTransform **toFPA, psProjection **toSky, psMetadata *header);
Index: /trunk/psastro/src/psastroArguments.c
===================================================================
--- /trunk/psastro/src/psastroArguments.c	(revision 6790)
+++ /trunk/psastro/src/psastroArguments.c	(revision 6791)
@@ -1,50 +1,95 @@
 # include "psastro.h"
-
-static void usage (void);
-static void usage_test (void);
-
-psMetadata *psastroArguments (int *argc, char **argv) {
-
-    unsigned int Nfail;
-
-    // basic pslib options
-    fprintf (stderr, "starting... %s\n", psLibVersion());
-    psLogSetFormat ("M");
-    psLogArguments (argc, argv);
-    psTraceArguments (argc, argv);
-
-    if (*argc != 4) usage ();
-
-    // load config information
-    psMetadata *config = psMetadataAlloc ();
-    config = psMetadataConfigParse (config, &Nfail, argv[1], FALSE);
-    return (config);
-}
+# include <glob.h>
 
 static void usage (void) {
-    fprintf (stderr, "USAGE: psastro (config) (input) (output)\n");
+    fprintf (stderr, "USAGE: psastro [-file image(s)] [-list imagelist] (output)\n");
     exit (2);
 }
 
-psMetadata *testArguments (int *argc, char **argv) {
+pmConfig *psastroArguments (int *argc, char **argv) {
 
-    unsigned int Nfail;
+    int N;
+
+    if (*argc == 1) usage ();
 
     // basic pslib options
-    fprintf (stderr, "starting... %s\n", psLibVersion());
     psLogSetFormat ("M");
-    psLogArguments (argc, argv);
-    psTraceArguments (argc, argv);
 
-    if (*argc != 6) usage_test ();
+    // these other options override the PSPHOT recipe options
+    psMetadata *options = psMetadataAlloc ();
 
-    // load config information
-    psMetadata *config = psMetadataAlloc ();
-    config = psMetadataConfigParse (config, &Nfail, argv[1], FALSE);
+    // photcode : used in output to supplement header data (argument or recipe?)
+    if ((N = psArgumentGet (*argc, argv, "-photcode"))) {
+	psArgumentRemove (N, argc, argv);
+	psMetadataAddStr (options, PS_LIST_TAIL, "PHOTCODE", PS_META_REPLACE, "", argv[N]);
+	psArgumentRemove (N, argc, argv);
+    }
+
+    // load config data from default locations 
+    pmConfig *config = pmConfigRead(argc, argv);
+
+    // Storage for other command-line arguments
+    config->arguments = psMetadataAlloc ();
+
+    // save these recipe options until we have loaded the options
+    psMetadataAddPtr (config->arguments, PS_LIST_TAIL, "PSASTRO.OPTIONS",  PS_DATA_METADATA, "", options);
+
+    // we load all input files onto a psArray, to be parsed later
+    psArray *input = psArrayAlloc (16);
+    input->n = 0;
+
+    // load the list of filenames the supplied file (may be a glob: "file*.fits")
+    if ((N = psArgumentGet (*argc, argv, "-file"))) {
+	glob_t globList;
+	psArgumentRemove (N, argc, argv);
+	globList.gl_offs = 0;
+	glob (argv[N], 0, NULL, &globList);
+	for (int i = 0; i < globList.gl_pathc; i++) {
+	    char *filename = psStringCopy (globList.gl_pathv[i]);
+	    psArrayAdd (input, 16, filename);
+	}
+	psArgumentRemove (N, argc, argv);
+    }
+
+    // load the list from the supplied text file
+    if ((N = psArgumentGet (*argc, argv, "-list"))) {
+	int nItems;
+	char line[1024]; // XXX limits the list lines to 1024 chars
+	char word[1024];
+	char *filename;
+
+	psArgumentRemove (N, argc, argv);
+	FILE *f = fopen (argv[N], "r");
+	if (f == NULL) {
+	    psAbort ("psphot", "unable to open specified list file");
+	}
+	while (fgets (line, 1024, f) != NULL) {
+	    nItems = sscanf (line, "%s", word);
+	    switch (nItems) {
+	      case 0:
+		break;
+	      case 1:
+		filename = psStringCopy (word);
+		psArrayAdd (input, 16, filename);
+		break;
+	      default:
+		// rigid format, no comments allowed?
+		psAbort ("psphot", "error parsing input list file");
+		break;
+	    }
+	}
+	psArgumentRemove (N, argc, argv);
+    }		
+    if (input->n < 1) usage ();
+
+    // input list gets places as an array on the config->arguements list
+    psMetadataAddPtr (config->arguments, PS_LIST_TAIL, "INPUT",  PS_DATA_ARRAY, "", input);
+
+    if (*argc != 2) usage ();
+
+    // output positions is fixed
+    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "", argv[2]);
+
+    psTrace(__func__, 1, "Done with psphotArguments...\n");
     return (config);
 }
-
-static void usage_test (void) {
-    fprintf (stderr, "USAGE: psastro-mktest (config) (cmpfile) (catfile) (rawfile) (reffile)\n");
-    exit (2);
-}
Index: /trunk/psastro/src/psastroDataLoop.c
===================================================================
--- /trunk/psastro/src/psastroDataLoop.c	(revision 6791)
+++ /trunk/psastro/src/psastroDataLoop.c	(revision 6791)
@@ -0,0 +1,64 @@
+# include "psastro.h"
+
+bool psastroDataLoop (ppFile *file, ppConfig *config) {
+
+    bool status;
+    ppImageLoadDepth imageLoadDepth;
+
+    // determine the load depth
+    const char *depth = psMetadataLookupStr(&status, config->recipe, "LOAD.DEPTH");
+    if (! status || ! depth || strlen(depth) == 0) {
+        psLogMsg("psastro", 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);
+    }
+
+    if (imageLoadDepth == PP_LOAD_FPA) {
+        psTrace(__func__, 1, "data pixels for FPA...\n");
+        psastroLoadSMF(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
+
+        psLogMsg ("psastro", 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);
+	    psastroLoadSMF(file, config->database, i, -1);
+        }
+
+        for (int j = 0; j < chip->cells->n; j++) {
+            pmCell *cell = chip->cells->data[j]; // Cell of interest in input image
+
+            psLogMsg ("psastro", 4, "Cell %d: %x %x\n", j, cell->exists, cell->process);
+            if (! cell->process) { continue; }
+
+            if (imageLoadDepth == PP_LOAD_CELL) {
+                psTrace(__func__, 1, "Loading pixels for chip %d, cell %d...\n", i, j);
+		psastroLoadSMF(file, config->database, i, j);
+            }
+	    
+	    // 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
+
+		// run a single-model test if desired
+		psphotModelTest (readout, config->arguments, config->recipe);
+		psphotReadout (readout, config->recipe);
+		psphotOutput (readout, config->arguments);
+	    }
+        }
+    }
+    return true;
+}
+
+/* this is currently written only for single-chip analysis */
Index: /trunk/psastro/src/psastroIO.c
===================================================================
--- /trunk/psastro/src/psastroIO.c	(revision 6790)
+++ /trunk/psastro/src/psastroIO.c	(revision 6791)
@@ -36,5 +36,5 @@
     stars->n = 0;
 
-    // we have fixed bytes / line : use that info
+
     for (int i = 0; i < nStars; i++) {
 	fread (line, 1, 66, f);
Index: /trunk/psastro/src/psastroLoadData.c
===================================================================
--- /trunk/psastro/src/psastroLoadData.c	(revision 6791)
+++ /trunk/psastro/src/psastroLoadData.c	(revision 6791)
@@ -0,0 +1,38 @@
+# include "psphot.h"
+
+bool psastroLoadData (ppFile *input, psDB *db, int chipNum, int cellNum)
+{
+    // an input chip is valid for processing if:
+    // (((chipNum == i) || (chipNum == -1)) && chip.process)
+
+    // If we have not opened the file, skip it
+    if (input->fits == NULL) {
+        return false;
+    }
+
+    psTrace(__func__, 1, "Loading %d,%d for %s\n", chipNum, cellNum, input->filename);
+
+    // set input:valid flags according to process and chipNum/cellNum
+    for (int i = 0; i < input->fpa->chips->n; i++) {
+        pmChip *chip = input->fpa->chips->data[i]; // Chip in input image
+        chip->process = (! chip->exists && ((chipNum == i) || (chipNum == -1)));
+
+        for (int j = 0; j < chip->cells->n; j++) {
+            pmCell *cell = chip->cells->data[j]; // Cell in input image
+            cell->process &= chip->process;
+            cell->process = (! cell->exists && ((cellNum == i) || (cellNum == -1)));
+        }
+    }
+    
+    // Read in the input pixels
+    if (! pmFPARead(input->fpa, input->fits, input->phu, db)) {
+        psErrorStackPrint(stderr, "Unable to populate camera from input FITS file\n");
+        exit(EXIT_FAILURE);
+    }
+
+    return true;
+}
+
+// XXX this is not very efficient with fseeks : each pmFPARead is randomly accessing the file
+// XXX does this handle multi-file data?
+// XXX this does NOT preserve the state of the input valid flags
Index: /trunk/psastro/src/psastroParseCamera.c
===================================================================
--- /trunk/psastro/src/psastroParseCamera.c	(revision 6791)
+++ /trunk/psastro/src/psastroParseCamera.c	(revision 6791)
@@ -0,0 +1,84 @@
+# include "psphot.h"
+
+ppFile *psastroParseCamera (ppConfig *config) {
+
+    ppFile *input = ppFileAlloc ();
+
+    input->filename = psMetadataLookupStr(NULL, config->arguments, "INPUT_FILE");
+    psMemCopy (input->filename); // keep for external use
+
+    // Open the input image
+    psLogMsg("psphot", PS_LOG_INFO, "Opening input image: %s\n", input->filename);
+    input->fits = psFitsOpen (input->filename, "r"); // File handle for FITS file
+    if (! input->fits) {
+        psErrorStackPrint(stderr, "Can't open input image: %s\n", input->filename);
+        exit(EXIT_FAILURE);
+    }
+    input->phu = psFitsReadHeader(NULL, input->fits); // FITS header
+
+    // Get camera configuration from header if not already defined
+    if (! config->camera) {
+        config->camera = pmConfigCameraFromHeader(config->site, input->phu);
+        if (! config->camera) {
+             // There's no point in continuing if we can't recognize what we've got
+            psErrorStackPrint(stderr, "Can't find camera configuration!\n");
+            exit(EXIT_FAILURE);
+        }
+   } else if (! pmConfigValidateCamera(config->camera, input->phu)) {
+       // There's no point in continuing if what we've got doesn't match what we've been told
+        psError(PS_ERR_IO, true, "%s does not seem to be from the specified camera.\n",
+                input->filename);
+        exit(EXIT_FAILURE);
+    }
+
+    // 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) {
+	    psErrorStackPrint(stderr, "Can't find recipe configuration!\n");
+	    exit(EXIT_FAILURE);
+	}
+    }
+
+    // recipe override values (command-line options):
+    psMetadataItem *item = 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);
+    }
+    psFree (iter);
+
+    // set default recipe values here
+    psMetadataAddStr (recipe, PS_LIST_TAIL, "PHOTCODE", PS_META_NO_REPLACE, "default fitting mode", "NONE");
+    psMetadataAddStr (recipe, PS_LIST_TAIL, "BREAK_POINT", PS_META_NO_REPLACE, "default fitting mode", "NONE");
+
+    // Chip selection: if we are using a single chip, select it for each FPA
+    // Chip numbers to work on: -chip 1,2,3,5,8,10
+    # if (0)
+    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;
+        }
+    }
+    # endif
+
+    psTrace(__func__, 1, "Done with psphotParseCamera...\n");
+    return input;
+}
Index: /trunk/psastro/src/testPSastroLoop.c
===================================================================
--- /trunk/psastro/src/testPSastroLoop.c	(revision 6791)
+++ /trunk/psastro/src/testPSastroLoop.c	(revision 6791)
@@ -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;
+}
