Index: /trunk/psastro/src/Makefile.am
===================================================================
--- /trunk/psastro/src/Makefile.am	(revision 23411)
+++ /trunk/psastro/src/Makefile.am	(revision 23412)
@@ -10,9 +10,13 @@
 # FORCE: ;
 
-bin_PROGRAMS = psastro psastroModel psastroModelFit gpcModel
+bin_PROGRAMS = psastro psastroExtract psastroModel psastroModelFit gpcModel
 
 psastro_CFLAGS = $(PSASTRO_CFLAGS) $(PPSTATS_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
 psastro_LDFLAGS = $(PSASTRO_LIBS) $(PPSTATS_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
 psastro_LDADD = libpsastro.la
+
+psastroExtract_CFLAGS = $(PSASTRO_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
+psastroExtract_LDFLAGS = $(PSASTRO_LIBS) $(PSMODULE_LIBS) $(PSLIB_LIBS)
+psastroExtract_LDADD = libpsastro.la
 
 psastroModel_CFLAGS = $(PSASTRO_CFLAGS) $(PSMODULE_CFLAGS) $(PSLIB_CFLAGS)
@@ -35,4 +39,12 @@
 	psastroDataSave.c           \
 	psastroMetadataStats.c      \
+	psastroCleanup.c
+
+psastroExtract_SOURCES = \
+	psastroExtract.c		    \
+        psastroExtractArguments.c	    \
+	psastroExtractParseCamera.c   \
+	psastroExtractDataLoad.c      \
+	psastroExtractAnalysis.c      \
 	psastroCleanup.c
 
Index: /trunk/psastro/src/psastro.h
===================================================================
--- /trunk/psastro/src/psastro.h	(revision 23411)
+++ /trunk/psastro/src/psastro.h	(revision 23412)
@@ -61,10 +61,10 @@
 bool              psPlaneDistortIsIdentity (psPlaneDistort *distort);
 
-psArray          *psastroLoadRefstars (pmConfig *config);
+psArray          *psastroLoadRefstars (pmConfig *config, const char *source);
 bool              psastroChipAstrom (pmConfig *config);
 bool              psastroOneChip (pmFPA *fpa, pmChip *chip, psArray *refset, psArray *rawset, psMetadata *recipe, psMetadata *updates);
 bool              psastroOneChipGrid (pmFPA *fpa, pmChip *chip, psArray *refset, psArray *rawset, psMetadata *recipe, psMetadata *updates);
 bool              psastroOneChipFit (pmFPA *fpa, pmChip *chip, psArray *refset, psArray *rawset, psMetadata *recipe, psMetadata *updates);
-bool              psastroChooseRefstars (pmConfig *config, psArray *refs);
+bool              psastroChooseRefstars (pmConfig *config, psArray *refs, const char *source);
 bool              psastroRefstarSubset (pmReadout *readout);
 pmLumFunc        *psastroLuminosityFunction (psArray *stars, pmLumFunc *rawFunc);
@@ -121,4 +121,5 @@
 bool              psastroDumpCorners (char *filenameU, char *filenameD, pmFPA *fpa);
 
+char             *psastroSetMagLimit (float *minMag, float *maxRho, pmConfig *config, const char *source);
 
 psArray          *psastroReadGetstarCatalog (psFits *fits);
@@ -133,4 +134,11 @@
 bool psastroZeroPointFromRecipe (float *zeropt, float *exptime, pmFPA *fpa, psMetadata *recipe);
 
+// psastroExtract functions
+bool psastroExtractAnalysis (pmConfig *config);
+psImage *psastroExtractStar (psImage *input, float x, float y, float dX, float dY);
+bool psastroExtractParseCamera (pmConfig *config);
+bool psastroExtractDataLoad (pmConfig *config);
+pmConfig *psastroExtractArguments (int argc, char **argv);
+
 ///@}
 # endif /* PSASTRO_H */
Index: /trunk/psastro/src/psastroAnalysis.c
===================================================================
--- /trunk/psastro/src/psastroAnalysis.c	(revision 23411)
+++ /trunk/psastro/src/psastroAnalysis.c	(revision 23412)
@@ -45,5 +45,5 @@
 
     // load the reference stars overlapping the data stars
-    psArray *refs = psastroLoadRefstars(config);
+    psArray *refs = psastroLoadRefstars(config, "PSASTRO.INPUT");
     if (!refs) {
         psError (PSASTRO_ERR_UNKNOWN, false, "failed to load reference data\n");
@@ -56,9 +56,10 @@
     }
 
-    if (!psastroChooseRefstars (config, refs)) {
+    if (!psastroChooseRefstars (config, refs, "PSASTRO.INPUT")) {
         psError (PSASTRO_ERR_UNKNOWN, false, "failed to select reference data for chips\n");
         psFree(refs);
         return false;
     }
+    psFree (refs);  // refs of interest are saved on readout->analysis
 
     // check the command-line arguments first
@@ -79,5 +80,4 @@
         if (!psastroChipAstrom (config)) {
             psError (PSASTRO_ERR_UNKNOWN, false, "failed to perform single chip astrometry\n");
-            psFree(refs);
             return false;
         }
@@ -86,5 +86,4 @@
         if (!psastroMosaicAstrom (config)) {
             psError (PSASTRO_ERR_UNKNOWN, false, "failed to perform mosaic camera astrometry\n");
-            psFree(refs);
             return false;
         }
@@ -100,5 +99,4 @@
     // psastroStackAstrom (config, refs);
 
-    psFree (refs);
     return true;
 }
Index: /trunk/psastro/src/psastroChooseRefstars.c
===================================================================
--- /trunk/psastro/src/psastroChooseRefstars.c	(revision 23411)
+++ /trunk/psastro/src/psastroChooseRefstars.c	(revision 23412)
@@ -20,5 +20,5 @@
 }
 
-bool psastroChooseRefstars (pmConfig *config, psArray *refs) {
+bool psastroChooseRefstars (pmConfig *config, psArray *refs, const char *source) {
 
     bool status;
@@ -35,5 +35,5 @@
 
     // select the input data sources
-    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSASTRO.INPUT");
+    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, source);
     if (!input) {
         psError(PSASTRO_ERR_CONFIG, true, "Can't find input data!\n");
Index: /trunk/psastro/src/psastroExtract.c
===================================================================
--- /trunk/psastro/src/psastroExtract.c	(revision 23412)
+++ /trunk/psastro/src/psastroExtract.c	(revision 23412)
@@ -0,0 +1,59 @@
+/** @file psastroExtract.c
+ *
+ *  @brief
+ *
+ *  @ingroup psastroExtract
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "psastroStandAlone.h"
+
+int main (int argc, char **argv) {
+
+    pmConfig *config = NULL;
+
+    psTimerStart ("complete");
+
+    psastroErrorRegister();              // register our error codes/messages
+
+    // model inits are needed in pmSourceIO
+    // models defined in psphot/src/models are not available in psastro
+    pmModelClassInit ();
+
+    // load configuration information
+    config = psastroExtractArguments (argc, argv);
+
+    // load identify the data sources
+    if (!psastroExtractParseCamera (config)) {
+	psErrorStackPrint(stderr, "error setting up the camera\n");
+	exit (1);
+    }
+
+    // load the raw pixel data (from PSPHOT.SOURCES)
+    // select subset of stars for astrometry
+    if (!psastroExtractDataLoad (config)) {
+	psErrorStackPrint(stderr, "error loading input data\n");
+	exit (1);
+    }
+
+    // run the full astrometry analysis (chip and/or mosaic)
+    if (!psastroExtractAnalysis (config)) {
+	psErrorStackPrint(stderr, "failure in psastro model analysis\n");
+	exit (1);
+    }
+    
+    // XXX save the results; is this needed?
+    // if (!psastroExtractDataSave (config)) {
+    // psErrorStackPrint(stderr, "error saving output data\n");
+    // exit (1);
+    // }
+
+    psLogMsg ("psastro", 3, "complete psastro run: %f sec\n", psTimerMark ("complete"));
+
+    psastroCleanup (config);
+    exit (EXIT_SUCCESS);
+}
Index: /trunk/psastro/src/psastroExtractAnalysis.c
===================================================================
--- /trunk/psastro/src/psastroExtractAnalysis.c	(revision 23412)
+++ /trunk/psastro/src/psastroExtractAnalysis.c	(revision 23412)
@@ -0,0 +1,229 @@
+/** @file psastroExtractAnalysis.c
+ *
+ *  @brief 
+ *
+ *  @ingroup psastroExtract
+ *
+ *  @author IfA
+ *  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "psastroInternal.h"
+
+# define ESCAPE {							\
+	psError(PS_ERR_UNKNOWN, false, "I/O failure in psastroMaskUpdate"); \
+	psFree (view);							\
+	return false;							\
+    }
+
+# define TEST_OUTPUT 1
+
+psImage *psastroExtractStar (psImage *input, float x, float y, float dX, float dY);
+
+/**
+ * create a mask or mask regions based on the collection of reference stars that * are in the vicinity of each chip
+ */
+bool psastroExtractAnalysis (pmConfig *config) {
+
+    bool status;
+    pmChip *chip = NULL;
+    pmCell *cell = NULL;
+    pmReadout *readout = NULL;
+    float zeropt, exptime;
+    char extname[81];
+
+    // select the current recipe
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSASTRO_RECIPE);
+    if (!recipe) {
+        psError(PSASTRO_ERR_CONFIG, true, "Can't find PSASTRO recipe");
+        return false;
+    }
+
+    // force this recipe value to be false (would cause an error in psastroChooseRefstars -- no rawstars!)
+    psMetadataAddBool (recipe, PS_LIST_TAIL, "PSASTRO.MATCH.LUMFUNC", PS_META_REPLACE, "do not match luminosity functions", false);
+
+    psLogMsg ("psastro", PS_LOG_INFO, "extracting bright-star subrasters");
+
+    // load the reference stars overlapping the data stars
+    psArray *refs = psastroLoadRefstars(config, "PSASTRO.EXTRACT.ASTROM");
+    if (!refs) {
+        psError (PSASTRO_ERR_UNKNOWN, false, "failed to load reference data\n");
+        return false;
+    }
+    if (refs->n == 0) {
+        psError(PSASTRO_ERR_REFSTARS, true, "no reference stars found");
+        psFree(refs);
+        return false;
+    }
+
+    if (!psastroChooseRefstars (config, refs, "PSASTRO.EXTRACT.ASTROM")) {
+        psError (PSASTRO_ERR_UNKNOWN, false, "failed to select reference data for chips\n");
+        psFree(refs);
+        return false;
+    }
+    psFree(refs);
+
+    double EXTRACT_MAX_MAG = psMetadataLookupF32 (&status, recipe, "EXTRACT_MAX_MAG");
+
+    // we have two input pmFPAfiles: PSASTRO.EXTRACT.INPUT and PSASTRO.EXTRACT.ASTROM.  both are in chip-mosaic or fpa format
+    // we have already loaded the headers from PSASTRO.EXTRACT.ASTROM and determined the astrometry terms
+
+    // select the input astrometry data (also carries the refstars)
+    pmFPAfile *astrom = psMetadataLookupPtr (NULL, config->files, "PSASTRO.EXTRACT.ASTROM");
+    if (!astrom) {
+        psError(PSASTRO_ERR_CONFIG, true, "Can't find input data");
+        return false;
+    }
+    pmFPA *fpa = astrom->fpa;
+
+    // select the input data sources
+    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSASTRO.EXTRACT.INPUT");
+    if (!input) {
+        psError(PSASTRO_ERR_CONFIG, true, "Can't find input data");
+        return false;
+    }
+
+    // only load data from INPUT
+    pmFPAfileActivate(config->files, false, NULL);
+    pmFPAfileActivate(config->files, true, "PSASTRO.EXTRACT.INPUT");
+
+    // really error-out here?  or just skip?
+    if (!psastroZeroPointFromRecipe (&zeropt, &exptime, fpa, recipe)) {
+        psLogMsg ("psastro", PS_LOG_INFO, "failed to load zeropt data from recipe");
+        return false;
+    }
+
+    // recipe values are given in instrumental magnitudes
+    // use the zero point and exposure time to convert to apparent mags: M_ap = M_inst + C_0 + 2.5*log(exptime)
+    float MagOffset = zeropt + 2.5*log10(exptime);
+    EXTRACT_MAX_MAG += MagOffset;
+
+    int nExt = 0;
+
+    // open the output file handle: we are just saving a series of extensions to this file
+    char *filename = psMetadataLookupStr (&status, config->arguments, "OUTPUT");
+    if (!filename) {
+	psLogMsg ("psastro", PS_LOG_INFO, "output filename not supplieda");
+	return false;
+    }
+    psFits *outStars = psFitsOpen (filename, "w");
+    if (!outStars) {
+	psError(PS_ERR_IO, false, "error opening file %s\n", filename);
+	return false;
+    }
+
+    pmFPAview *view = pmFPAviewAlloc (0);
+
+    // open/load files as needed
+    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
+
+    // this loop selects the matched stars for all chips
+    while ((chip = pmFPAviewNextChip (view, fpa, 1)) != NULL) {
+        psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
+        if (!chip->process || !chip->file_exists) { continue; }
+        if (!chip->fromFPA) { continue; }
+
+        if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
+
+        // text output file for testing
+        FILE *f = NULL;
+        if (TEST_OUTPUT) {
+	    char *filename = NULL;
+	    char *chipname = psMetadataLookupStr (&status, chip->concepts, "CHIP.NAME");
+	    psStringAppend (&filename, "bright.%s.dat", chipname);
+	    f = fopen (filename, "w");
+	    if (!f) {
+		psWarning ("cannot create test output file %s\n", filename);
+		continue;
+	    }
+	    psFree (filename);
+        }
+
+        while ((cell = pmFPAviewNextCell (view, fpa, 1)) != NULL) {
+            psTrace ("psastro", 4, "Cell %d: %x %x\n", view->cell, cell->file_exists, cell->process);
+            if (!cell->process || !cell->file_exists) { continue; }
+
+            // process each of the readouts
+            while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) {
+                if (! readout->data_exists) { continue; }
+
+                // select the raw objects for this readout (loaded in psastroExtract.c)
+                psArray *refstars = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.REFSTARS");
+                if (refstars == NULL) { continue; }
+
+                // identify the bright stars of interest
+                for (int i = 0; i < refstars->n; i++) {
+                    pmAstromObj *ref = refstars->data[i];
+                    if (ref->Mag > EXTRACT_MAX_MAG) continue;
+
+                    if (TEST_OUTPUT) {
+			fprintf (f, "stars %f %f  %f %f   %f\n", ref->chip->x, ref->chip->y, ref->FP->x, ref->FP->y, ref->Mag);
+                    }
+
+		    pmReadout *inReadout = pmFPAviewThisReadout (view, input->fpa);
+		    psImage *subraster = psastroExtractStar (inReadout->image, ref->chip->x, ref->chip->y, 100.0, 100.0);
+		    if (!subraster) continue;
+		    
+		    snprintf (extname, 80, "extname.%05d", nExt);
+		    psFitsWriteImage (outStars, NULL, subraster, 0, extname);
+		    nExt ++;
+		    
+		    psFree (subraster);
+                }
+                if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+            }
+            if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+        }
+        if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+
+	fclose (f);
+    }
+    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+
+    psFitsClose (outStars);
+    psFree (view);
+    return true;
+}
+
+psImage *psastroExtractStar (psImage *input, float x, float y, float dX, float dY) {
+
+    // skip if no pixels are on the image
+    // skip if center is not on the image
+    // if bounds fall off image, paste into a full-size image.
+
+    if (x < 0) return NULL;
+    if (y < 0) return NULL;
+    if (x >= input->numCols) return NULL;
+    if (y >= input->numRows) return NULL;
+
+    int xo = x; // index of center pixel (eg, 6.00 to 6.99 -> 6)
+    int yo = y;
+
+    // build an output image of size 2dX + 1, 2dY + 1
+    // psRegion fullRegion = psRegionSet (xo - dX, x + dX + 1, y - dY, y + dY + 1);
+    // psRegion realRegion = psRegionForImage (input, fullRegion);
+    // psImage *subset = psImageSubset (input, realRegion);
+
+    psImage *subset = psImageAlloc (2*dX+1, 2*dY+1, PS_TYPE_F32);
+    psImageInit (subset, 0.0);
+
+    // fill in the subset image with the values from the subset
+    // I must already have done this elsewhere...
+
+    for (int iy = yo - dY; iy < yo + dY + 1; iy++) {
+	for (int ix = xo - dX; ix < xo + dX + 1; ix++) {
+
+	    if (ix < input->col0) continue;
+	    if (iy < input->row0) continue;
+	    if (ix >= input->numCols) continue;
+	    if (iy >= input->numRows) continue;
+	
+	    int jx = ix + dX - xo; // runs from 0 to 2dX
+	    int jy = iy + dY - yo;
+	    subset->data.F32[jy][jx] = input->data.F32[iy][ix];
+	}
+    }
+    return subset;
+}
Index: /trunk/psastro/src/psastroExtractArguments.c
===================================================================
--- /trunk/psastro/src/psastroExtractArguments.c	(revision 23412)
+++ /trunk/psastro/src/psastroExtractArguments.c	(revision 23412)
@@ -0,0 +1,78 @@
+/** @file psastroExtractArguments.c
+ *
+ *  @brief
+ *
+ *  @ingroup psastroExtract
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "psastroStandAlone.h"
+
+static char *usage = "USAGE: psastroExtract [-outroot root] -astrom (cmffiles)";
+
+pmConfig *psastroExtractArguments (int argc, char **argv) {
+
+    int N;
+
+    if (argc == 1) {
+        psError(PSASTRO_ERR_ARGUMENTS, true, "No arguments supplied");
+        psErrorStackPrint(stderr, "%s", usage);
+	exit (1);
+    }
+
+    // load config data from default locations
+    pmConfig *config = pmConfigRead(&argc, argv, PSASTRO_RECIPE);
+    if (config == NULL) {
+        psError(PSASTRO_ERR_CONFIG, false, "Can't read site configuration");
+        psErrorStackPrint(stderr, "%s", usage);
+	exit (1);
+    }
+
+    // save the following additional recipe values based on command-line options
+    // these options override the PSASTRO recipe values loaded from recipe files
+    // psMetadata *options = pmConfigRecipeOptions (config, PSASTRO_RECIPE);
+
+    // define the image pixel data
+    if (!pmConfigFileSetsMD (config->arguments, &argc, argv, "INPUT", "-file", "-list")) {
+        psError(PSASTRO_ERR_ARGUMENTS, true, "Missing -file (input) or -list (input)");
+        psErrorStackPrint(stderr, "%s", usage);
+	exit (1);
+    }
+
+    // define the astrometry data (XXX make this optional and use the image header?)
+    if (!pmConfigFileSetsMD(config->arguments, &argc, argv, "ASTROM",   "-astrom", "-astromlist")) {
+        psError(PSASTRO_ERR_ARGUMENTS, true, "Missing -astrom (smf) or -astromlist (smf)");
+        psErrorStackPrint(stderr, "%s", usage);
+	exit (1);
+    }
+
+    // define the output filename
+    N = psArgumentGet (argc, argv, "-output");
+    if (!N) {
+	psError(PSASTRO_ERR_ARGUMENTS, true, "Missing -output (root)");
+        psErrorStackPrint(stderr, "%s", usage);
+	exit (1);
+    }
+    psArgumentRemove (N, &argc, argv);
+    psMetadataAddStr (config->arguments, PS_LIST_TAIL, "OUTPUT", 0, "", 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_SELECTIONS", PS_META_REPLACE, "", argv[N]);
+        psArgumentRemove (N, &argc, argv);
+    }
+    
+    if (argc < 1) {
+        psError(PSASTRO_ERR_ARGUMENTS, true, "Incorrect arguments supplied");
+        psErrorStackPrint(stderr, "exit");
+	exit (1);
+    }
+
+    return (config);
+}
Index: /trunk/psastro/src/psastroExtractDataLoad.c
===================================================================
--- /trunk/psastro/src/psastroExtractDataLoad.c	(revision 23412)
+++ /trunk/psastro/src/psastroExtractDataLoad.c	(revision 23412)
@@ -0,0 +1,165 @@
+/** @file psastroExtractDataLoad.c
+ *
+ *  @brief
+ *
+ *  @ingroup psastroExtract
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "psastroStandAlone.h"
+
+# define ESCAPE { \
+  psError(PS_ERR_UNKNOWN, false, "Failure in psastroExtractDataLoad"); \
+  psFree (view); \
+  return false; \
+}
+  
+/**
+ * this loop loads the header data from the input files, using the output 
+ * pmFPAfile to guide the chip selection and related issues
+ * all of the different astrometry analysis modes use the same data load loop
+ */
+bool psastroExtractDataLoad (pmConfig *config) {
+
+    bool status;
+    pmChip *chip;
+
+    bool newFPA = true;
+    double RAmin  = +FLT_MAX;
+    double RAmax  = -FLT_MAX;
+    double DECmin = +FLT_MAX;
+    double DECmax = -FLT_MAX;
+
+    double RAminSky = NAN;
+    double RAmaxSky = NAN;
+
+    psTimerStart ("psastro");
+
+    // select the current recipe
+    psMetadata *recipe  = psMetadataLookupPtr (NULL, config->recipes, PSASTRO_RECIPE);
+    if (!recipe) {
+	psError(PSASTRO_ERR_CONFIG, true, "Can't find PSASTRO recipe!\n");
+	return false;
+    }
+
+    // physical pixel scale in microns per pixel
+    double pixelScale = psMetadataLookupF32 (&status, recipe, "PSASTRO.PIXEL.SCALE");
+    if (!status) {
+	psError(PS_ERR_IO, true, "Failed to lookup pixel scale"); 
+	return false; 
+    } 
+
+    // select the input data sources
+    pmFPAfile *astrom = psMetadataLookupPtr (NULL, config->files, "PSASTRO.EXTRACT.ASTROM");
+    if (!astrom) psAbort ("PSASTRO.EXTRACT.ASTROM not listed in config->files");
+    pmFPA *fpa = astrom->fpa;
+
+    pmFPAfileActivate(config->files, false, NULL);
+    pmFPAfileActivate(config->files, true, "PSASTRO.EXTRACT.ASTROM");
+
+    pmFPAview *view = pmFPAviewAlloc (0);
+
+    // files associated with the science image
+    if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
+
+    // load the headers from the astrometry files
+    while ((chip = pmFPAviewNextChip (view, astrom->fpa, 1)) != NULL) {
+        psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
+        if (!chip->process) { continue; }
+	if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
+    }
+    psLogMsg ("psastro", 3, "load headers : %f sec\n", psTimerMark ("psastro"));
+
+    // check PHU header to see if we are using mosaic-level or per-chip astrometry
+    bool bilevelAstrometry = false;
+    pmHDU *phu = pmFPAviewThisPHU (view, astrom->fpa);
+    if (phu) {
+      char *ctype = psMetadataLookupStr (NULL, phu->header, "CTYPE1");
+      if (ctype) bilevelAstrometry = !strcmp (&ctype[4], "-DIS");
+    }
+    if (bilevelAstrometry) {
+      pmAstromReadBilevelMosaic (astrom->fpa, phu->header);
+    } 
+
+    // apply the header astrometry to the astrometry structures
+    while ((chip = pmFPAviewNextChip (view, astrom->fpa, 1)) != NULL) {
+      psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
+      if (!chip->process || !chip->file_exists || !chip->data_exists) { continue; }
+
+      if (newFPA) {
+	newFPA = false;
+	while (fpa->toSky->R <        0) fpa->toSky->R += 2.0*M_PI;
+	while (fpa->toSky->R > 2.0*M_PI) fpa->toSky->R -= 2.0*M_PI;
+	RAminSky = fpa->toSky->R - M_PI;
+	RAmaxSky = fpa->toSky->R + M_PI;
+      }
+
+      // read WCS data from the corresponding header
+      pmHDU *hdu = pmFPAviewThisHDU (view, astrom->fpa);
+      int nAstro = psMetadataLookupS32 (&status, hdu->header, "NASTRO");
+      if (!nAstro) continue;
+
+      if (bilevelAstrometry) {
+	if (!pmAstromReadBilevelChip (chip, hdu->header)) {
+	  psWarning("Could not get WCS information from header for chip %d, skipping", view->chip); 
+	  continue;
+	} 
+      } else {
+	if (!pmAstromReadWCS (astrom->fpa, chip, hdu->header, pixelScale)) {
+	  psWarning("Could not get WCS information from header for chip %d, skipping", view->chip); 
+	  continue;
+	} 
+      }
+      
+      // determine RA,DEC of 4 corners, use to find RA_MIN,MAX, DEC_MIN,MAX
+      psRegion *region = pmChipPixels (chip);
+      psPlane ptCH[4], ptFP, ptTP;
+      psSphere ptSky;
+      ptCH[0].x = region->x0;
+      ptCH[0].y = region->y0;
+      ptCH[1].x = region->x1;
+      ptCH[1].y = region->y0;
+      ptCH[2].x = region->x1;
+      ptCH[2].y = region->y1;
+      ptCH[3].x = region->x0;
+      ptCH[3].y = region->y1;
+      psFree (region);
+      
+      for (int i = 0; i < 4; i++) {
+	psPlaneTransformApply (&ptFP, chip->toFPA, &ptCH[i]);
+	psPlaneTransformApply (&ptTP, fpa->toTPA, &ptFP);
+	psDeproject (&ptSky, &ptTP, fpa->toSky);
+
+	// rationalize ra to sky range centered on boresite
+	while (ptSky.r < RAminSky) ptSky.r += 2.0*M_PI;
+	while (ptSky.r > RAmaxSky) ptSky.r -= 2.0*M_PI;
+
+	RAmin = PS_MIN (ptSky.r, RAmin);
+	RAmax = PS_MAX (ptSky.r, RAmax);
+	
+	DECmin = PS_MIN (ptSky.d, DECmin);
+	DECmax = PS_MAX (ptSky.d, DECmax);
+
+	psLogMsg ("psastro", 2, "chip %d (corner %d) : %f %f  -> %f %f -> %f %f -> %f %f\n",
+		  view->chip, i, ptCH[i].x, ptCH[i].y, ptFP.x, ptFP.y, ptTP.x, ptTP.y, 
+		  DEG_RAD*ptSky.r, DEG_RAD*ptSky.d);
+      }
+    }
+    psLogMsg ("psastro", 3, "convert wcs terms to internal format : %f sec\n", psTimerMark ("psastro"));
+
+    psLogMsg ("psastro", 2, "loaded raw data from %f,%f to %f,%f\n",
+              DEG_RAD*RAmin, DEG_RAD*DECmin,
+              DEG_RAD*RAmax, DEG_RAD*DECmax);
+
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "RA_MIN",  PS_META_REPLACE, "", RAmin);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "RA_MAX",  PS_META_REPLACE, "", RAmax);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "DEC_MIN", PS_META_REPLACE, "", DECmin);
+    psMetadataAddF32 (recipe, PS_LIST_TAIL, "DEC_MAX", PS_META_REPLACE, "", DECmax);
+
+    psFree (view);
+    return true;
+}
Index: /trunk/psastro/src/psastroExtractDataSave.c
===================================================================
--- /trunk/psastro/src/psastroExtractDataSave.c	(revision 23412)
+++ /trunk/psastro/src/psastroExtractDataSave.c	(revision 23412)
@@ -0,0 +1,52 @@
+/** @file psastroModelDataSave.c
+ *
+ *  @brief
+ *
+ *  @ingroup psastroModel
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "psastroStandAlone.h"
+# define NONLIN_TOL 0.001 ///< tolerance in pixels 
+
+# define ESCAPE { \
+  psError(PS_ERR_UNKNOWN, false, "Failure in psastroModelDataSave"); \
+  psFree (view); \
+  return false; \
+}
+  
+bool psastroModelDataSave (pmConfig *config) {
+
+    bool status;
+
+    // select the current recipe
+    psMetadata *recipe  = psMetadataLookupPtr (&status, config->recipes, PSASTRO_RECIPE);
+    if (!recipe) {
+	psError(PSASTRO_ERR_CONFIG, true, "Can't find PSASTRO recipe");
+	return false;
+    }
+
+    pmFPAfile *output = psMetadataLookupPtr (&status, config->files, "PSASTRO.OUT.MODEL");
+    if (!status) psAbort ("Can't find output pmFPAfile PSASTRO.OUT.MODEL");
+
+    pmFPAview *view = pmFPAviewAlloc (0);
+    pmChip *chip = NULL;
+
+    while ((chip = pmFPAviewNextChip (view, output->fpa, 1)) != NULL) {
+        psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, chip->file_exists, chip->process);
+        if (!chip->process) { continue; }
+	if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+    }
+    if (!pmFPAfileIOChecks (config, view, PM_FPA_AFTER)) ESCAPE;
+
+    psLogMsg ("psastro", 3, "save headers : %f sec\n", psTimerMark ("psastro"));
+
+    return true;
+}
+
+
+
Index: /trunk/psastro/src/psastroExtractParseCamera.c
===================================================================
--- /trunk/psastro/src/psastroExtractParseCamera.c	(revision 23412)
+++ /trunk/psastro/src/psastroExtractParseCamera.c	(revision 23412)
@@ -0,0 +1,68 @@
+/** @file psastroExtractParseCamera.c
+ *
+ *  @brief
+ *
+ *  @ingroup psastroExtract
+ *
+ *  @author IfA
+ *  @version $Revision: 1.3 $ 
+ *  @date $Date: 2009-02-07 02:03:34 $
+ *  Copyright 2009 Institute for Astronomy, University of Hawaii
+ */
+
+# include "psastroInternal.h"
+
+bool psastroExtractParseCamera (pmConfig *config) {
+
+    bool status = false;
+
+    // the input image(s) are required arguments; they define the camera
+    status = false;
+    pmFPAfile *input = pmFPAfileDefineFromArgs(&status, config, "PSASTRO.EXTRACT.INPUT", "INPUT");
+    if (!input || !status) {
+        psError(PSASTRO_ERR_CONFIG, false, "Failed to build FPA from PSASTRO.EXTRACT.INPUT");
+        return false;
+    }
+
+    // the input image(s) are required arguments; they define the camera
+    status = false;
+    pmFPAfile *astrom = pmFPAfileDefineFromArgs(&status, config, "PSASTRO.EXTRACT.ASTROM", "ASTROM");
+    if (!astrom || !status) {
+        psError (PS_ERR_UNKNOWN, false, "failed to load astrometry definition");
+        return NULL;
+    }
+
+# if (0)    
+    // XXX for now, don't use the pmFPAfile methods
+    // set up an output fpa structure & file based on the last input file
+    pmFPAfile *output = pmFPAfileDefineOutput (config, input->fpa, "PSASTRO.OUT.MODEL");
+    if (!output) {
+	psError(PSASTRO_ERR_CONFIG, false, "Failed to build FPA for PSASTRO.OUT.MODEL from input");
+	return false;
+    }
+    output->save = true;
+# endif
+
+    // Chip selection: turn on only the chips specified (option is not required)
+    char *chipLine = psMetadataLookupStr(&status, config->arguments, "CHIP_SELECTIONS"); 
+    psArray *chips = psStringSplitArray (chipLine, ",", false);
+    if (chips->n > 0) {
+	pmFPASelectChip (input->fpa, -1, true); // deselect all chips
+	pmFPASelectChip (astrom->fpa, -1, true); // deselect all chips
+	for (int i = 0; i < chips->n; i++) {
+	    int chipNum = atoi(chips->data[i]);
+	    if (! pmFPASelectChip(input->fpa, chipNum, false)) {
+		psError(PSASTRO_ERR_CONFIG, true, "Chip number %d doesn't exist in camera.\n", chipNum);
+		return false;
+	    }
+	    if (! pmFPASelectChip(astrom->fpa, chipNum, false)) {
+		psError(PSASTRO_ERR_CONFIG, true, "Chip number %d doesn't exist in camera.\n", chipNum);
+		return false;
+	    }
+        }
+    }
+    psFree (chips);
+
+    psTrace("psastro", 1, "Done with psastroExtractParseCamera...\n");
+    return true;
+}
Index: /trunk/psastro/src/psastroLoadRefstars.c
===================================================================
--- /trunk/psastro/src/psastroLoadRefstars.c	(revision 23411)
+++ /trunk/psastro/src/psastroLoadRefstars.c	(revision 23412)
@@ -14,7 +14,5 @@
 # define ELIXIR_MODE 1
 
-char *psastroSetMagLimit (float *minMag, float *maxRho, pmConfig *config);
-
-psArray *psastroLoadRefstars (pmConfig *config) {
+psArray *psastroLoadRefstars (pmConfig *config, const char *source) {
 
     int fd;
@@ -69,5 +67,5 @@
     float minMag;
     float maxRho;
-    char *photcode = psastroSetMagLimit (&minMag, &maxRho, config);
+    char *photcode = psastroSetMagLimit (&minMag, &maxRho, config, source);
     PS_ASSERT (photcode, NULL);
 
@@ -240,5 +238,5 @@
   goto escape; }
 
-char *psastroSetMagLimit (float *minMag, float *maxRho, pmConfig *config) {
+char *psastroSetMagLimit (float *minMag, float *maxRho, pmConfig *config, const char *source) {
 
     bool status;
@@ -249,5 +247,5 @@
 
     // select the input data sources
-    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, "PSASTRO.INPUT");
+    pmFPAfile *input = psMetadataLookupPtr (NULL, config->files, source);
     if (!input) {
         psLogMsg ("psastro", PS_LOG_DETAIL, "no supplied reference header data");
