Index: trunk/psastro/src/psastroEnforceChip.c
===================================================================
--- trunk/psastro/src/psastroEnforceChip.c	(revision 15357)
+++ trunk/psastro/src/psastroEnforceChip.c	(revision 15357)
@@ -0,0 +1,75 @@
+# include "psastroInternal.h"
+
+bool psastroEnforceChips (pmFPA *fpa, psMetadata *recipe) {
+
+  pmChip *chip = NULL;
+  // identify reference astrometry table, stored as an fpa? better format?
+
+  pmFPAfile *refAstrom = psMetadataLookupPtr (NULL, config->files, "PSASTRO.REF.ASTROM");
+
+  pmFPAview *view = pmFPAviewAlloc (0);
+
+  // physical pixel scale in microns per pixel
+  double pixelTol = psMetadataLookupF32 (&status, recipe, "PSASTRO.PIXEL.TOLERANCE");
+  if (!status) {
+    psError(PS_ERR_IO, true, "Failed to lookup pixel tolerance"); 
+    return false; 
+  } 
+  double angleTol = psMetadataLookupF32 (&status, recipe, "PSASTRO.ANGLE.TOLERANCE");
+  if (!status) {
+    psError(PS_ERR_IO, true, "Failed to lookup angle tolerance"); 
+    return false; 
+  } 
+
+  // loop over all chips
+  while ((obsChip = pmFPAviewNextChip (view, fpa, 1)) != NULL) {
+    psTrace ("psastro", 4, "Chip %d: %x %x\n", view->chip, obsChip->file_exists, obsChip->process);
+    if (!obsChip->process || !obsChip->file_exists || !obsChip->data_exists) { continue; }
+
+    // set the chip astrometry using the refAstrom file
+    pmChip *refChip = pmFPAviewThisChip (view, refAstrom->fpa);
+
+    // bad Astrometry test:  ref pixel or angle outside nominal
+
+    psPlane refPixel = {0.0, 0.0, 0.0, 0.0};
+    psPlane obsCoord, refCoord;
+
+    // find location of 0,0 pixel in focal plane coords for this chip
+    psPlaneTransformApply (&obsCoord, obsChip->toFPA, &refPixel);
+
+    // find location of 0,0 pixel in focal plane coords for ref chip
+    psPlaneTransformApply (&refCoord, refChip->toFPA, &refPixel);
+    
+    psPlane offPixel = {0.0, 0.0, 0.0, 0.0};
+    psPlane obsOffPt, refOffPt;
+
+    // find location of 0,0 pixel in focal plane coords for this chip
+    psPlaneTransformApply (&obsOffPt, obsChip->toFPA, &offPixel);
+
+    // find location of 0,0 pixel in focal plane coords for ref chip
+    psPlaneTransformApply (&refOffPt, refChip->toFPA, &offPixel);
+    
+    double obsAngle = atan2 (obsOffPt.y - obsCoord.y, obsOffPt.x - obsCoord.x);
+
+    badAstrom = false;
+    badAstrom |= fabs(obsCoord.x - refCoord.x) > pixelTol;
+    badAstrom |= fabs(obsCoord.y - refCoord.y) > pixelTol;
+    badAstrom |= fabs(obsAngle   - refAngle)   > angleTol;
+
+    if (!badAstrom) continue;
+
+    psFree (obsChip->toFPA);
+    psFree (obsChip->fromFPA);
+
+    // XXX can we do a straight copy?  I think so, but we may need to apply a scaling factor based
+    // on the toSky or toTPA values
+    obsChip->toFPA   = psMemIncrRefCounter (refChip->toFPA);
+    obsChip->fromFPA = psMemIncrRefCounter (refChip->fromFPA);
+  }
+  return true;
+}
+
+// XXX for this function to work, I need to:
+// 1 *) define badAstrom (ref pixel too far from nominal?) (ref angle too far off?)
+// 2) load the refAstrom fpa in the pmFPAfileIO stage 
+// 3) allow for this operation to be optional
