Index: trunk/psastro/src/psastroUtils.c
===================================================================
--- trunk/psastro/src/psastroUtils.c	(revision 5509)
+++ trunk/psastro/src/psastroUtils.c	(revision 5510)
@@ -197,5 +197,5 @@
 }
 
-bool psastroProjectRawstars (pmFPA *fpa) {
+bool psastroProjectFPA (pmFPA *fpa, bool toSky) {
 
     for (int i = 0; i < fpa->chips->n; i++) {
@@ -205,37 +205,141 @@
 	    for (int k = 0; k < cell->readouts->n; k++) {
 		pmReadout *readout = cell->readouts->data[k];
-		for (int m = 0; m < readout->stars->n; m++) {
-		    pmAstromObj *star = readout->data[m];
-		    // apply readout offsets
-		    // apply cell PlaneTransform
-		    // apply chip PlaneTransform
-		    psPlaneTransformApply (star-> 
-
-	    }
-	    chip->cells->data[j] = cell;
-	}
-	fpa->chips->data[i] = chip;
-    }
-    return (fpa);
+		if (toSky) {
+		    psastroProjectRawstars (readout->stars, readout);
+		} else {
+		    psastroProjectRefstars (readout->stars, readout);
+		}
+	    }
+	}
+    }
+    return true;
 }
  
-bool psastroChipAstrom (psArray *refstars, pmFPA *subset) {
-
-    // do this loop over the readouts 
-
-    // find initial offset / rotation
-    stat = pmAstromGridMatch (subset, refstars, config);
-
-    pmAstromModifyFPA (fpa, stat);
-
-    // use fit result to re-project rawstars
-    psastroProjectRawstars (fpa, subset);
-    psastroProjectRefstars (fpa, refstars);
+bool psastroProjectRawstars (psArray *stars, pmReadout *readout) {
+
+    pmCell *cell = readout->cell;
+    pmChip *chip = cell->chip;
+    pmFPA  *fpa  = chip->cell;
+
+    for (int i = 0; i < readout->stars->n; i++) {
+	pmAstromObj *star = readout->stars->data[i];
+	psCoordReadoutToCell (&star->cell, &star->pix, readout);
+	psCoordCellToChip (&star->chip, &star->cell, cell);
+	psCoordChipToFP (&star->FP, &star->chip, chip);
+	psCoordFPtoTP (&star->TP, &star->FP, fpa);
+	psCoordTPtoSky (&star->sky, &star->TP, fpa);
+    }
+    return true;
+}
+ 
+bool psastroProjectRefstars (psArray *stars, pmReadout *readout) {
+
+    pmCell *cell = readout->cell;
+    pmChip *chip = cell->chip;
+    pmFPA  *fpa  = chip->cell;
+
+    for (int i = 0; i < stars->n; i++) {
+	pmAstromObj *star = stars->data[i];
+
+	psCoordSkytoTP (&star->TP, &star->sky, fpa);
+	psCoordTPtoFP (&star->FP, &star->TP, fpa);
+	psCoordFPtoChip (&star->chip, &star->FP, chip);
+	psCoordChipToCell (&star->cell, &star->chip, cell);
+	psCoordReadoutToCell (&star->pix, &star->cell, readout);
+    }
+    return true;
+}
+ 
+// measure per-chip astrometry terms 
+bool psastroChipAstrom (pmFPA *fpa, psMetadata *config) {
+
+    pmFPA *raw = pmFPACopy (fpa);
+
+    // first pass: measure the per-chip solutions, modify the chip.toFPA terms
+    for (int i = 0; i < fpa->chips->n; i++) {
+	pmChip *chip = fpa->chips->data[i];
+
+	// cells->n > 1 is not yet well-defined
+	if (chip->cells->n > 1) {
+	    psLogMsg ("pmSourcesReadCMP", 3, "undefined behavior for nCells > 1");
+	    return false;
+	}
+
+	for (int j = 0; j < chip->cells->n; j++) {
+	    pmCell *cell = chip->cells->data[j];
+
+	    // readouts->n > 1 is not yet well-defined
+	    if (cell->readouts->n > 1) {
+		psLogMsg ("pmSourcesReadCMP", 3, "undefined behavior for nReadouts > 1");
+		return false;
+	    }
+
+	    // load the corresponding reference data (DVO command)
+	    psArray *refstars = psastroLoadReference (cell->header, config);
+
+	    for (int k = 0; k < cell->readouts->n; k++) {
+
+		pmReadout *readout = cell->readouts->data[k];
+
+		// use the header & config info to project refstars on the focal plane
+		psastroProjectRefstars (refstars, readout);
+
+		// find initial offset / rotation
+		stat = pmAstromGridMatch (readout->stars, refstars, config);
+
+		// adjust the chip.toFPA terms only
+		pmAstromGridApply (chip->toFPA, stat);
+
+		// use fit result to re-project rawstars
+		psastroProjectRawstars (readout->stars, readout);
+		psastroProjectRefstars (refstars,       readout);
     
-    // use small radius to match stars
-    match = pmAstromRadiusMatch (rawstars, refstars, options);
-
-    // fit astrometric terms
-    output = pmAstromMatchedListFit (fpa, subset, refstars, match, options);
-}
-
+		// use small radius to match stars
+		match = pmAstromRadiusMatch (rawstars, refstars, options);
+
+		// fit astrometric terms
+		pmAstromMatchedListFit (chip->toFPA, readout->stars, refstars, match, options);
+	    }
+	}
+    }
+
+    // second stage: re-normalize the chip terms, passing the 
+    // average rotation and offset values to the fpa.toSky
+	    
+# if (0)
+    // code disabled for now 
+    // this is not as trivial as it seems at first:
+    // applying a new rotation to the FPA implies changes to the 
+    // (x,y) reference coordinates for the chips as well as a rotation
+    // I need to calculate both the x,y offset effect and the rotation
+    // in one step.  what about the effect of higher order terms in either
+    // the chip.toFPA or the fpa.toTPA? 
+    // this calculation also needs to account for scale effects between the 
+    // fpa and the chips.
+
+    // calculate the average rotation and boresite offset relative to raw
+    for (int i = 0; i < fpa->chips->n; i++) {
+	pmChip *iChip = raw->chips->data[i];
+	pmChip *oChip = fpa->chips->data[i];
+
+	T1 = psPlaneTransformGetRotation (iChip->toFPA);
+	T2 = psPlaneTransformGetRotation (oChip->toFPA);
+	dT += T1 - T2;
+	dN ++;
+
+	
+    }
+
+    dT /= dN;
+
+    psPlaneTransformSetRotation (fpa->toTPA, dT);
+	
+    // apply the new modifcations in rotation and boresite
+    for (int i = 0; i < fpa->chips->n; i++) {
+	pmChip *iChip = raw->chips->data[i];
+	pmChip *oChip = fpa->chips->data[i];
+
+	psPlaneTransformSetRotation (oChip->toFPA, -dT);
+    }
+# endif 
+}
