Index: trunk/psastro/src/psastroMosaicOneChip.c
===================================================================
--- trunk/psastro/src/psastroMosaicOneChip.c	(revision 39926)
+++ trunk/psastro/src/psastroMosaicOneChip.c	(revision 41895)
@@ -23,4 +23,5 @@
     bool status;
     char errorWord[64];
+    char stdevWord[64];
     char orderWord[64];
 
@@ -44,7 +45,10 @@
 
     // allowed limits for valid solutions
+    // CERROR is currently tested during the iterations, but not CERSTD
     snprintf (errorWord, 64, "PSASTRO.MOSAIC.MAX.ERROR.N%d", iteration);
-    REQUIRED_RECIPE_VALUE (float maxError, errorWord, 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");
+    snprintf (stdevWord, 64, "PSASTRO.MOSAIC.MAX.STDEV.N%d", iteration);
+    REQUIRED_RECIPE_VALUE (float maxError,                  errorWord, F32, "failed to find single-chip max allowed error\n");
+    REQUIRED_RECIPE_VALUE (float maxStdev,                  stdevWord, F32, "failed to find single-chip max allowed stdev\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 iteration > 0)
@@ -88,6 +92,7 @@
         }
     } else {
+	// Forward transformations (chip->fpa->tpa->sky) use Ordinary polynomials
         psFree (chip->toFPA);
-        chip->toFPA = psPlaneTransformAlloc (order, order);
+        chip->toFPA = psPlaneTransformAlloc (order, order, PS_POLYNOMIAL_ORD);
         for (int i = 0; i <= chip->toFPA->x->nX; i++) {
             for (int j = 0; j <= chip->toFPA->x->nY; j++) {
@@ -134,4 +139,8 @@
     int astNstar = results->yStats->clippedNvalues;
 
+    // astStdev is the average 1D stdev of median residuals in arcsec ('results' are in FPA units = microns)
+    // the median residuals are calculated in a grid of N x N bins 
+    float astStdev = 0.5*(results->dXstdev + results->dYstdev) * plateScale;
+
     // if we clip away too many stars, the order may be invalid
     if (order == 3) { minNstar = PS_MAX (15, minNstar); }
@@ -141,10 +150,14 @@
     bool validSolution = true;
 
-    // XXX should these result in errors or be handled another way?
-    psLogMsg ("psastro", PS_LOG_INFO, "astrometry solution: error: %f arcsec, Nstars: %d", astError, astNstar);
+    // We have options to exclude chips on the basis of NASTRO, CERROR, CERSTD
+    psLogMsg ("psastro", PS_LOG_INFO, "astrometry solution: error: %f arcsec, Nstars: %d, stdev: %f arcsec", astError, astNstar, astStdev);
     if ((maxError > 0) && (astError > maxError)) {
         psLogMsg("psastro", PS_LOG_INFO, "residual error is too large, failed to find a solution: %f > %f", astError, maxError);
         validSolution = false;
     }
+    if ((maxStdev > 0) && (astStdev > maxStdev)) {
+        psLogMsg("psastro", PS_LOG_INFO, "residual stdev is too large, failed to find a solution: %f > %f", astStdev, maxStdev);
+        validSolution = false;
+    }
     if (astNstar < minNstar) {
         psLogMsg("psastro", PS_LOG_INFO, "solution uses too few stars: %d < %d", astNstar, minNstar);
@@ -152,13 +165,16 @@
     }
 
-    // DVO expects NASTRO = 0 if we fail to find a solution
+    // DVO expects NASTRO = 0 if we fail to find a solution, NASTUSED is the true number
     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);
+    psMetadataAddF32 (updates, PS_LIST_TAIL, "CERSTD",   PS_META_REPLACE, "astrometry stdev (arcsec)", astStdev);
     if (validSolution) {
         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);
+        psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTUSED", PS_META_REPLACE, "number of astrometry stars", astNstar);
     } else {
         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);
+        psMetadataAddS32 (updates, PS_LIST_TAIL, "NASTUSED", PS_META_REPLACE, "number of astrometry stars", astNstar);
     }
     psMetadataAddF32 (updates, PS_LIST_TAIL, "EQUINOX",  PS_META_REPLACE, "", 2000.0); // XXX this is bogus: should be defined based on equinox of refstars
