Index: /trunk/psastro/src/psastro.h
===================================================================
--- /trunk/psastro/src/psastro.h	(revision 10879)
+++ /trunk/psastro/src/psastro.h	(revision 10880)
@@ -56,13 +56,13 @@
 
 // mosaic fitting functions
-psArray *psastroMosaicGradients (pmFPA *fpa, psMetadata *recipe);
+bool psastroMosaicGradients (pmFPA *fpa, psMetadata *recipe);
 bool psastroMosaicCommonScale (pmFPA *fpa, psMetadata *recipe);
 bool psastroMosaicAstrom (pmConfig *config, psArray *refs);
-bool psastroMosaicChipAstrom (pmFPA *fpa, psMetadata *recipe, int iteration);
+bool psastroMosaicChipAstrom (pmFPA *fpa, psMetadata *recipe, bool nonlinear);
 bool psastroMosaicSetMatch (pmFPA *fpa, psMetadata *recipe, int iteration);
 bool psastroMosaicSetAstrom (pmFPA *fpa);
 bool psastroMosaicHeaders (pmConfig *config);
 bool psastroMosaicRescaleChips (pmFPA *fpa);
-bool psastroMosaicOneChip (pmChip *chip, pmReadout *readout, psMetadata *recipe, psMetadata *updates, int iteration);
+bool psastroMosaicOneChip (pmChip *chip, pmReadout *readout, psMetadata *recipe, psMetadata *updates, bool nonlinear);
 
 // Return version strings.
@@ -77,4 +77,5 @@
 bool psastroDumpRawstars (psArray *rawstars, pmFPA *fpa, pmChip *chip);
 bool psastroDumpRefstars (psArray *refstars);
+bool psastroDumpMatches (pmFPA *fpa, char *filename);
 
 bool psastroMosaicSetAstrom_tmp (pmFPA *fpa);
Index: /trunk/psastro/src/psastroChipAstrom.c
===================================================================
--- /trunk/psastro/src/psastroChipAstrom.c	(revision 10879)
+++ /trunk/psastro/src/psastroChipAstrom.c	(revision 10880)
@@ -4,5 +4,4 @@
 bool psastroChipAstrom (pmConfig *config, psArray *refs) {
 
-    bool status;
     pmChip *chip = NULL;
     pmCell *cell = NULL;
@@ -22,7 +21,4 @@
 	return false;
     }
-
-    double plateScale = psMetadataLookupF32 (&status, recipe, "PSASTRO.PLATE.SCALE");
-    if (!status) plateScale = 1.0;
 
     pmFPAview *view = pmFPAviewAlloc (0);
Index: /trunk/psastro/src/psastroChooseRefstars.c
===================================================================
--- /trunk/psastro/src/psastroChooseRefstars.c	(revision 10879)
+++ /trunk/psastro/src/psastroChooseRefstars.c	(revision 10880)
@@ -56,6 +56,4 @@
                 psArray *refstars = psArrayAllocEmpty (100);
 
-		FILE *f = fopen ("refstars.dat", "w");
-
                 // select the reference objects within range of this readout
                 // project the reference objects to this chip
@@ -66,10 +64,4 @@
                     psPlaneTransformApply (ref->FP, fpa->fromTPA, ref->TP);
                     psPlaneTransformApply (ref->chip, chip->fromFPA, ref->FP);
-
-		    fprintf (f, "%d  %f %f  %f %f  %f %f  %f %f\n", i,
-			     ref->sky->r, ref->sky->d, 
-			     ref->TP->x, ref->TP->y, 
-			     ref->FP->x, ref->FP->y, 
-			     ref->chip->x, ref->chip->y);
 
                     // limit the X,Y range of the refs to the selected chip
@@ -83,5 +75,4 @@
                     psFree (ref);
                 }
-		fclose (f);
                 psTrace ("psastro", 4, "Added %ld refstars\n", refstars->n);
 
Index: /trunk/psastro/src/psastroDemoDump.c
===================================================================
--- /trunk/psastro/src/psastroDemoDump.c	(revision 10879)
+++ /trunk/psastro/src/psastroDemoDump.c	(revision 10880)
@@ -58,2 +58,62 @@
     return true;
 }
+
+bool psastroDumpMatches (pmFPA *fpa, char *filename) {
+
+    pmChip *chip = NULL;
+    pmCell *cell = NULL;
+    pmReadout *readout = NULL;
+    pmFPAview *view = pmFPAviewAlloc (0);
+
+    FILE *f = fopen (filename, "w");
+
+    // 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;
+	
+	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
+	    // XXX there can only be one readout per chip, right?
+	    while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) {
+		if (! readout->data_exists) continue;
+
+		// select the raw objects for this readout
+		psArray *rawstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.RAWSTARS");
+		if (rawstars == NULL) continue;
+
+		// select the raw objects for this readout
+		psArray *refstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.REFSTARS");
+		if (refstars == NULL) continue;
+		psTrace ("psastro", 4, "Trying %ld refstars\n", refstars->n);
+
+		psArray *matches = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.MATCH");
+		if (matches == NULL) continue;
+
+		for (int i = 0; i < matches->n; i++) {
+		    pmAstromMatch *match = matches->data[i];
+
+		    pmAstromObj *raw = rawstars->data[match->raw];
+		    fprintf (f, "%f %f  %f %f  %f %f  %f %f  %f   |   ",  
+			     DEG_RAD*raw->sky->r, DEG_RAD*raw->sky->d, 
+			     raw->TP->x, raw->TP->y, 
+			     raw->FP->x, raw->FP->y, 
+			     raw->chip->x, raw->chip->y, raw->Mag);
+
+		    pmAstromObj *ref = refstars->data[match->ref];
+		    fprintf (f, "%f %f  %f %f  %f %f  %f %f  %f\n", 
+			     DEG_RAD*ref->sky->r, DEG_RAD*ref->sky->d, 
+			     ref->TP->x, ref->TP->y, 
+			     ref->FP->x, ref->FP->y, 
+			     ref->chip->x, ref->chip->y, ref->Mag);
+		}
+	    }
+	}
+    }
+    fclose (f);
+    psFree (view);
+    return true;
+}
Index: /trunk/psastro/src/psastroLuminosityFunction.c
===================================================================
--- /trunk/psastro/src/psastroLuminosityFunction.c	(revision 10879)
+++ /trunk/psastro/src/psastroLuminosityFunction.c	(revision 10880)
@@ -68,5 +68,4 @@
   // exclude bins with no stars
   // exclude points after the peak with N < 0.8*peak
-  FILE *f = fopen ("psastro.dat", "w");
   int n = 0;
   for (int i = 0; i < nMags->n; i++) {
@@ -75,8 +74,6 @@
     lnMag->data.F32[n] = log10 (nMags->data.F32[i]);
     Mag->data.F32[n] = mMin + (i + 0.5)*dMag;
-    fprintf (f, "%d  %f %.0f %f\n", n, Mag->data.F32[n], nMags->data.F32[i], lnMag->data.F32[n]);
     n++;
   }
-  fclose (f);
   lnMag->n = n;
   Mag->n = n;
Index: /trunk/psastro/src/psastroMosaicAstrom.c
===================================================================
--- /trunk/psastro/src/psastroMosaicAstrom.c	(revision 10879)
+++ /trunk/psastro/src/psastroMosaicAstrom.c	(revision 10880)
@@ -4,7 +4,4 @@
 // XXX require this fpa to have multiple chip extensions and a PHU?
 bool psastroMosaicAstrom (pmConfig *config, psArray *refs) {
-
-    bool status;
-    psArray *gradients = NULL;
 
     // select the current recipe
@@ -29,5 +26,7 @@
 
     // given the existing per-chip astrometry, determine matches between raw and ref stars
+    // is this needed? yes, if we didn't do SingleChip astrometry first
     psastroMosaicSetMatch (fpa, recipe, 0);
+    if (psTraceGetLevel("psastro.dump") > 0) { psastroDumpMatches (fpa, "match.0.dat"); }
 
     // fitted chips will follow the local plate-scale, hiding the distortion
@@ -35,59 +34,36 @@
     // then recalculate raw and ref positions
     psastroMosaicCommonScale (fpa, recipe);
-    psastroMosaicSetAstrom (fpa);
+    if (psTraceGetLevel("psastro.dump") > 0) { psastroDumpMatches (fpa, "match.1.dat"); }
 
-    gradients = psastroMosaicGradients (fpa, recipe);
+    // fit the distortion by fitting its gradient
+    // apply the new distortion terms up and down
+    // refit the per-chip terms with linear fits only
+    psastroMosaicGradients (fpa, recipe);
+    if (psTraceGetLevel("psastro.dump") > 0) { psastroDumpMatches (fpa, "match.2.dat"); }
 
-    // allocate mosaic-level polynomial transformation and set masks needed by DVO
-    int order = psMetadataLookupF32 (&status, recipe, "PSASTRO.MOSAIC.ORDER");
-    if (!status) {
-	psError(PSASTRO_ERR_UNKNOWN, false, "failed to find single-chip fit order\n");
-        return false;
-    }
-    psFree (fpa->toTPA);
-    fpa->toTPA = psPlaneTransformAlloc (order, order);
-    for (int i = 0; i <= fpa->toTPA->x->nX; i++) {
-        for (int j = 0; j <= fpa->toTPA->x->nY; j++) {
-            if (i + j > order) {
-		fpa->toTPA->x->mask[i][j] = 1;
-		fpa->toTPA->y->mask[i][j] = 1;
-            }
-        }
-    }
+    psastroMosaicChipAstrom (fpa, recipe, false);
+    if (psTraceGetLevel("psastro.dump") > 0) { psastroDumpMatches (fpa, "match.3.dat"); }
 
-    // fit the measured gradients with the telescope distortion model (polynomial order based on toTPA)
-    pmAstromFitDistortion (fpa, gradients, recipe);
-    psFree (gradients);
-
-    // apply the new distortion terms up and down
     // re-perform the match with a slightly tighter circle
-    // XXX modify match radius
-    // XXX set chip.order to 1
-    psastroMosaicSetAstrom_tmp (fpa);
     psastroMosaicSetMatch (fpa, recipe, 1);
-    psastroMosaicChipAstrom (fpa, recipe, 1);
 
     // do a second pass on the distortion with improved chip positions and rotations
-    // XXX do we need to iterate with this step until the distortions don't change? 
     psastroMosaicCommonScale (fpa, recipe);
-    gradients = psastroMosaicGradients (fpa, recipe);
-    pmAstromFitDistortion (fpa, gradients, recipe);
-    psFree (gradients);
+    psastroMosaicGradients (fpa, recipe);
+    psastroMosaicChipAstrom (fpa, recipe, false);
+    psastroMosaicSetMatch (fpa, recipe, 1);
     
     // now fit the chips under the common distortion with higher-order terms
-    // XXX modify match radius
-    // XXX set chip.order to NORDER
-    psastroMosaicSetAstrom (fpa);
-    psastroMosaicSetMatch (fpa, recipe, 2);
-    psastroMosaicChipAstrom (fpa, recipe, 2);
+    // first, re-perform the match with a slightly tighter circle
+    psastroMosaicChipAstrom (fpa, recipe, true);
 
     // save WCS and analysis metadata in update header
-    // XXX need to add global summary statistics
     psMetadata *updates = psMetadataAlloc();
     pmAstromWriteBilevelMosaic (updates, fpa, NONLIN_TOL);
-    psMetadataAdd (fpa->analysis, PS_LIST_TAIL, "PSASTRO.HEADER",  PS_DATA_METADATA, "psastro header stats", updates);
+    psMetadataAddMetadata (fpa->analysis, PS_LIST_TAIL, "PSASTRO.HEADER",  PS_META_REPLACE, "psastro header stats", updates);
     psFree (updates);
 
     // update the headers based on the results
+    // XXX need to add global summary statistics
     // psastroMosaicHeaders (config);
 
Index: /trunk/psastro/src/psastroMosaicChipAstrom.c
===================================================================
--- /trunk/psastro/src/psastroMosaicChipAstrom.c	(revision 10879)
+++ /trunk/psastro/src/psastroMosaicChipAstrom.c	(revision 10880)
@@ -2,5 +2,5 @@
 # define NONLIN_TOL 0.001 /* tolerance in pixels */
 
-bool psastroMosaicChipAstrom (pmFPA *fpa, psMetadata *recipe, int iteration) {
+bool psastroMosaicChipAstrom (pmFPA *fpa, psMetadata *recipe, bool nonlinear) {
 
     pmChip *chip = NULL;
@@ -26,15 +26,14 @@
 		psMetadata *updates = psMetadataAlloc();
 
-		psastroMosaicOneChip (chip, readout, recipe, updates, iteration);
+		psastroMosaicOneChip (chip, readout, recipe, updates, nonlinear);
 
+		// create the header keywords to descripe the results
 		pmAstromWriteBilevelChip (updates, chip, NONLIN_TOL);
-		psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSASTRO.HEADER",  PS_DATA_METADATA, "psastro header stats", updates);
+		psMetadataAddMetadata (readout->analysis, PS_LIST_TAIL, "PSASTRO.HEADER",  PS_META_REPLACE, "psastro header stats", updates);
 		psFree (updates);
 	    }
 	}
     }
+    psFree (view);
     return true;
 }
-
-/* the iteration value may be 1 or 2.
- */
Index: /trunk/psastro/src/psastroMosaicGradients.c
===================================================================
--- /trunk/psastro/src/psastroMosaicGradients.c	(revision 10879)
+++ /trunk/psastro/src/psastroMosaicGradients.c	(revision 10880)
@@ -1,6 +1,7 @@
 # include "psastro.h"
 
-psArray *psastroMosaicGradients (pmFPA *fpa, psMetadata *recipe) {
+bool psastroMosaicGradients (pmFPA *fpa, psMetadata *recipe) {
 
+    bool status;
     pmChip *chip = NULL;
     pmCell *cell = NULL;
@@ -36,9 +37,32 @@
 
 		// measure the local gradients for this set of stars
-		// XXX update the function prototype to accept an incoming gradient structure to which the new elements are added
 		gradients = pmAstromMeasureGradients (gradients, rawstars, refstars, match, recipe);
 	    }
 	}
     }
-    return (gradients);
+
+    // allocate mosaic-level polynomial transformation and set masks needed by DVO
+    int order = psMetadataLookupF32 (&status, recipe, "PSASTRO.MOSAIC.ORDER");
+    if (!status) {
+	psError(PSASTRO_ERR_UNKNOWN, false, "failed to find single-chip fit order\n");
+        return false;
+    }
+    psFree (fpa->toTPA);
+    fpa->toTPA = psPlaneTransformAlloc (order, order);
+    for (int i = 0; i <= fpa->toTPA->x->nX; i++) {
+        for (int j = 0; j <= fpa->toTPA->x->nY; j++) {
+            if (i + j > order) {
+		fpa->toTPA->x->mask[i][j] = 1;
+		fpa->toTPA->y->mask[i][j] = 1;
+            }
+        }
+    }
+
+    // fit the measured gradients with the telescope distortion model (polynomial order based on toTPA)
+    pmAstromFitDistortion (fpa, gradients, recipe);
+    psastroMosaicSetAstrom (fpa);
+
+    psFree (gradients);
+    psFree (view);
+    return true;
 }
Index: /trunk/psastro/src/psastroMosaicOneChip.c
===================================================================
--- /trunk/psastro/src/psastroMosaicOneChip.c	(revision 10879)
+++ /trunk/psastro/src/psastroMosaicOneChip.c	(revision 10880)
@@ -1,5 +1,11 @@
 # include "psastro.h"
 
-bool psastroMosaicOneChip (pmChip *chip, pmReadout *readout, psMetadata *recipe, psMetadata *updates, int iteration) {
+# define REQUIRED_RECIPE_VALUE(VALUE, NAME, TYPE, MESSAGE)\
+  VALUE = psMetadataLookup##TYPE (&status, recipe, NAME); \
+  if (!status) { \
+   psError(PSASTRO_ERR_CONFIG, false, MESSAGE); \
+   return false; } 
+
+bool psastroMosaicOneChip (pmChip *chip, pmReadout *readout, psMetadata *recipe, psMetadata *updates, bool nonlinear) {
 
     bool status;
@@ -20,25 +26,28 @@
     if (match == NULL) return false;
 
-    if ((iteration < 1) || (iteration > 2)) {
-	psError(PSASTRO_ERR_UNKNOWN, false, "invalid iteration number %d\n", iteration);
-	return false;
+    // correct radius to FP units (physical pixel scale in microns per pixel)
+    REQUIRED_RECIPE_VALUE (double pixelScale, "PSASTRO.PIXEL.SCALE", F32, "Failed to lookup pixel scale"); 
+
+    // allowed limits for valid solutions
+    REQUIRED_RECIPE_VALUE (float maxError, "PSASTRO.MOSAIC.MAX.ERROR", F32, "failed to find single-chip max allowed error\n");
+    REQUIRED_RECIPE_VALUE (int minNstar, "PSASTRO.MOSAIC.MIN.NSTAR", S32, "failed to find single-chip min allowed stars\n");
+
+    // set the order of the per-chip fit (higher order only if nonlinear == true)
+    int order = 1;
+    if (nonlinear) {
+	// select the desired chip order
+	REQUIRED_RECIPE_VALUE (order, "PSASTRO.MOSAIC.CHIP.ORDER", S32, "failed to find mosaic chip-level fit order\n");
+
+	// modify the order to correspond to the actual number of matched stars:
+	if ((match->n < 11) && (order >= 3)) order = 2;
+	if ((match->n <  7) && (order >= 2)) order = 1;
+	if ((match->n <  4) && (order >= 1)) order = 0;
+	if (order < 1) {
+	    psLogMsg ("psastro", 3, "insufficient stars or invalid order: %ld stars", match->n); 
+	    return false; 
+	} 
     }
 
-    // correct to FP units (physical pixel scale in microns per pixel)
-    double pixelScale = psMetadataLookupF32 (&status, recipe, "PSASTRO.PIXEL.SCALE");
-    if (!status) { 
-	psError(PS_ERR_IO, false, "Failed to lookup pixel scale"); 
-	return false; 
-    } 
-
-    // set the order of the per-chip fit (iteration 1: 1, iteration 2: from recipe)
-    int order = 1;
-    if (iteration == 2) {
-	order = psMetadataLookupS32 (&status, recipe, "PSASTRO.MOSAIC.CHIP.ORDER");
-	if (!status) {
-	    psError(PSASTRO_ERR_UNKNOWN, false, "failed to find mosaic chip-level fit order\n");
-	    return false;
-	}
-    }
+    // create output toFPA; set masks appropriate to the Elixir DVO astrometry format
     psFree (chip->toFPA);
     chip->toFPA = psPlaneTransformAlloc (order, order);
@@ -64,12 +73,13 @@
     }
 
-    // allowed limits for valid solutions
-    // XXX have these values depend on the iteration?
-    float maxError = psMetadataLookupF32 (&status, recipe, "PSASTRO.MOSAIC.MAX.ERROR");
-    int minNstar = psMetadataLookupS32 (&status, recipe, "PSASTRO.MOSAIC.MIN.NSTAR");
+    // toSky converts from FPA & TPA units (microns) to sky units (radians)
+    pmFPA *fpa = chip->parent;
+    float plateScale = 0.5*(fpa->toSky->Xs + fpa->toSky->Ys)*3600.0*PM_DEG_RAD;
 
-    // astError is the average 1D scatter in pixels ('results' are in FPA units = microns)
-    // XXX currently using supplied pixel scale: use toFPA->x->coeff[1][0], etc?
-    float astError = 0.5*(results->xStats->clippedStdev + results->yStats->clippedStdev) / pixelScale;
+    // pixError is the average 1D scatter in pixels ('results' are in FPA units = microns)
+    float pixError = 0.5*(results->xStats->clippedStdev + results->yStats->clippedStdev) / pixelScale;
+
+    // astError is the average 1D scatter in arcsec ('results' are in FPA units = microns)
+    float astError = 0.5*(results->xStats->clippedStdev + results->yStats->clippedStdev) * plateScale;
     int astNstar = results->yStats->clippedNvalues;
 
@@ -77,5 +87,5 @@
 
     // XXX should these result in errors or be handled another way?
-    psLogMsg ("psastro", PS_LOG_INFO, "astrometry solution: error: %f, Nstars: %d", astError, astNstar);
+    psLogMsg ("psastro", PS_LOG_INFO, "astrometry solution: error: %f arcsec, Nstars: %d", astError, astNstar);
     if (astError > maxError) {
 	psLogMsg("psastro", PS_LOG_INFO, "residual error is too large, failed to find a solution: %f > %f", astError, maxError);
@@ -88,13 +98,17 @@
 
     // DVO expects NASTRO = 0 if we fail to find a solution
+    psMetadataAddF32 (updates, PS_LIST_TAIL, "PERROR",   PS_META_REPLACE, "astrometry error (pixels)", pixError);
+    psMetadataAddF32 (updates, PS_LIST_TAIL, "CERROR",   PS_META_REPLACE, "astrometry error (arcsec)", astError);
     if (validSolution) {
-	psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTRO",   PS_META_REPLACE, "", astNstar);
-	psMetadataAddF32 (updates, PS_LIST_TAIL, "CPRECISE", PS_META_REPLACE, "", astError/sqrt(astNstar));
+	psMetadataAddF32 (updates, PS_LIST_TAIL, "CPRECISE", PS_META_REPLACE, "astrometry precision (arcsec)", astError/sqrt(astNstar));
+	psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTRO",   PS_META_REPLACE, "number of astrometry stars", astNstar);
     } else {
-	psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTRO",   PS_META_REPLACE, "", 0);
-	psMetadataAddF32 (updates, PS_LIST_TAIL, "CPRECISE", PS_META_REPLACE, "", 0.0);
+	psMetadataAddF32 (updates, PS_LIST_TAIL, "CPRECISE", PS_META_REPLACE, "astrometry precision (arcsec)", 0.0);
+	psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTRO",   PS_META_REPLACE, "number of astrometry stars", 0);
     }
-    psMetadataAddF32 (updates, PS_LIST_TAIL, "CERROR",   PS_META_REPLACE, "", astError);
     psMetadataAddF32 (updates, PS_LIST_TAIL, "EQUINOX",  PS_META_REPLACE, "", 2000.0); // XXX this is bogus: should be defined based on equinox of refstars
+
+    // determine fromFPA transformation and apply new transformation to raw & ref stars
+    psastroUpdateChipToFPA (fpa, chip, rawstars, refstars);
 
     psFree (fitStats);
Index: /trunk/psastro/src/psastroMosaicSetAstrom.c
===================================================================
--- /trunk/psastro/src/psastroMosaicSetAstrom.c	(revision 10879)
+++ /trunk/psastro/src/psastroMosaicSetAstrom.c	(revision 10880)
@@ -47,66 +47,5 @@
 	}
     }
+    psFree (view);
     return true;
 }
-
-bool psastroMosaicSetAstrom_tmp (pmFPA *fpa) {
-
-    pmChip *chip = NULL;
-    pmCell *cell = NULL;
-    pmReadout *readout = NULL;
-    pmFPAview *view = pmFPAviewAlloc (0);
-
-    FILE *f1 = fopen ("raw.tmp.dat", "w");
-    FILE *f2 = fopen ("ref.tmp.dat", "w");
-
-    // 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; }
-	
-	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
-	    // XXX there can only be one readout per chip, right?
-	    while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) {
-		if (! readout->data_exists) { continue; }
-
-		// select the raw objects for this readout
-		psArray *rawstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.RAWSTARS");
-		if (rawstars == NULL) { continue; }
-
-		for (int i = 0; i < rawstars->n; i++) {
-		    pmAstromObj *raw = rawstars->data[i];
-	
-		    fprintf (f1, "%f %f  %f %f  %f %f  ", raw->sky->r, raw->sky->d, raw->TP->x, raw->TP->y, raw->FP->x, raw->FP->y);
-
-		    psPlaneTransformApply (raw->FP, chip->toFPA, raw->chip);
-		    psPlaneTransformApply (raw->TP, fpa->toTPA, raw->FP);
-		    psDeproject (raw->sky, raw->TP, fpa->toSky);
-
-		    fprintf (f1, "|  %f %f  %f %f  %f %f   %f\n", raw->sky->r, raw->sky->d, raw->TP->x, raw->TP->y, raw->FP->x, raw->FP->y, raw->Mag);
-		}
-
-		psArray *refstars = psMetadataLookupPtr (NULL, readout->analysis, "PSASTRO.REFSTARS");
-		if (refstars == NULL) { continue; }
-
-		for (int i = 0; i < refstars->n; i++) {
-		    pmAstromObj *ref = refstars->data[i];
-	
-		    fprintf (f2, "%f %f  %f %f  %f %f  ", ref->sky->r, ref->sky->d, ref->TP->x, ref->TP->y, ref->FP->x, ref->FP->y);
-
-		    psProject (ref->TP, ref->sky, fpa->toSky);
-		    psPlaneTransformApply (ref->FP, fpa->fromTPA, ref->TP);
-		    psPlaneTransformApply (ref->chip, chip->fromFPA, ref->FP);
-
-		    fprintf (f2, "|  %f %f  %f %f  %f %f   %f\n", ref->sky->r, ref->sky->d, ref->TP->x, ref->TP->y, ref->FP->x, ref->FP->y, ref->Mag);
-		}
-	    }
-	}
-    }
-    fclose (f1);
-    fclose (f2);
-    return true;
-}
Index: /trunk/psastro/src/psastroMosaicSetMatch.c
===================================================================
--- /trunk/psastro/src/psastroMosaicSetMatch.c	(revision 10879)
+++ /trunk/psastro/src/psastroMosaicSetMatch.c	(revision 10880)
@@ -8,7 +8,4 @@
     pmFPAview *view = pmFPAviewAlloc (0);
     char radiusWord[64];
-
-    FILE *g1 = fopen ("raw.ps.dat", "w");
-    FILE *g2 = fopen ("ref.ps.dat", "w");
 
     // use small radius to match stars (assume starting astrometry is good)
@@ -47,29 +44,11 @@
 		psTrace ("psastro", 4, "Matched %ld refstars\n", matches->n);
 
-		for (int i = 0; i < matches->n; i++) {
-		    pmAstromMatch *match = matches->data[i];
-
-		    pmAstromObj *raw = rawstars->data[match->raw];
-		    fprintf (g1, "%d %f %f  %f %f  %f %f  %f %f\n", i, 
-			     DEG_RAD*raw->sky->r, DEG_RAD*raw->sky->d, 
-			     raw->TP->x, raw->TP->y, 
-			     raw->FP->x, raw->FP->y, 
-			     raw->chip->x, raw->chip->y);
-
-		    pmAstromObj *ref = refstars->data[match->ref];
-		    fprintf (g2, "%d %f %f  %f %f  %f %f  %f %f\n", i, 
-			     DEG_RAD*ref->sky->r, DEG_RAD*ref->sky->d, 
-			     ref->TP->x, ref->TP->y, 
-			     ref->FP->x, ref->FP->y, 
-			     ref->chip->x, ref->chip->y);
-		}
-
 		// XXX drop the old one
 		psMetadataAdd (readout->analysis, PS_LIST_TAIL, "PSASTRO.MATCH", PS_DATA_ARRAY | PS_META_REPLACE, "astrometry matches", matches);
+		psFree (matches);
 	    }
 	}
     }
-    fclose (g1);
-    fclose (g2);
+    psFree (view);
     return true;
 }
Index: /trunk/psastro/src/psastroOneChip.c
===================================================================
--- /trunk/psastro/src/psastroOneChip.c	(revision 10879)
+++ /trunk/psastro/src/psastroOneChip.c	(revision 10880)
@@ -23,5 +23,4 @@
     // allowed limits for valid solutions
     REQUIRED_RECIPE_VALUE (float maxError, "PSASTRO.MAX.ERROR", F32, "failed to find single-chip max allowed error\n");
-
     REQUIRED_RECIPE_VALUE (int minNstar, "PSASTRO.MIN.NSTAR", S32, "failed to find single-chip min allowed stars\n");
 
@@ -53,6 +52,5 @@
     }
 
-    // create the output fit model, modify the order to correspond to the actual number of
-    // matched stars:
+    // modify the order to correspond to the actual number of matched stars:
     if ((match->n < 11) && (order >= 3)) order = 2;
     if ((match->n <  7) && (order >= 2)) order = 1;
@@ -66,5 +64,5 @@
     } 
 
-    // set masks appropriate to the Elixir DVO astrometry format
+    // create output toFPA; set masks appropriate to the Elixir DVO astrometry format
     psFree (chip->toFPA);
     chip->toFPA = psPlaneTransformAlloc (order, order);
@@ -125,5 +123,5 @@
     psMetadataAddF32 (updates, PS_LIST_TAIL, "EQUINOX",  PS_META_REPLACE, "equinox of ref catalog", 2000.0); // XXX this is bogus: should be defined based on equinox of refstars
 
-    // write results
+    // determine fromFPA transformation and apply new transformation to raw & ref stars
     psastroUpdateChipToFPA (fpa, chip, rawstars, refstars);
     
Index: /trunk/psastro/src/psastroUtils.c
===================================================================
--- /trunk/psastro/src/psastroUtils.c	(revision 10879)
+++ /trunk/psastro/src/psastroUtils.c	(revision 10880)
@@ -73,4 +73,5 @@
 
     }
+    psastroMosaicSetAstrom (fpa);
     return true;
 }
